diff options
501 files changed, 10514 insertions, 6638 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index e44e9022bf5d..b2f4eb760747 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -25,7 +25,6 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.AlarmManager; import android.app.AppGlobals; import android.app.IUidObserver; import android.app.job.IJobScheduler; @@ -95,7 +94,6 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob; import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob; -import com.android.server.job.JobSchedulerServiceDumpProto.RegisteredJob; import com.android.server.job.controllers.BackgroundJobsController; import com.android.server.job.controllers.BatteryController; import com.android.server.job.controllers.ConnectivityController; @@ -117,7 +115,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; @@ -240,18 +237,7 @@ public class JobSchedulerService extends com.android.server.SystemService final SparseIntArray mBackingUpUids = new SparseIntArray(); /** - * Count standby heartbeats, and keep track of which beat each bucket's jobs will - * next become runnable. Index into this array is by normalized bucket: - * { ACTIVE, WORKING, FREQUENT, RARE, NEVER }. The ACTIVE and NEVER bucket - * milestones are not updated: ACTIVE apps get jobs whenever they ask for them, - * and NEVER apps don't get them at all. - */ - final long[] mNextBucketHeartbeat = { 0, 0, 0, 0, Long.MAX_VALUE }; - long mHeartbeat = 0; - long mLastHeartbeatTime = sElapsedRealtimeClock.millis(); - - /** - * Named indices into the STANDBY_BEATS array, for clarity in referring to + * Named indices into standby bucket arrays, for clarity in referring to * specific buckets' bookkeeping. */ public static final int ACTIVE_INDEX = 0; @@ -260,21 +246,6 @@ public class JobSchedulerService extends com.android.server.SystemService public static final int RARE_INDEX = 3; public static final int NEVER_INDEX = 4; - /** - * Bookkeeping about when jobs last run. We keep our own record in heartbeat time, - * rather than rely on Usage Stats' timestamps, because heartbeat time can be - * manipulated for testing purposes and we need job runnability to track that rather - * than real time. - * - * Outer SparseArray slices by user handle; inner map of package name to heartbeat - * is a HashMap<> rather than ArrayMap<> because we expect O(hundreds) of keys - * and it will be accessed in a known-hot code path. - */ - final SparseArray<HashMap<String, Long>> mLastJobHeartbeats = new SparseArray<>(); - - static final String HEARTBEAT_TAG = "*job.heartbeat*"; - final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener(); - // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked -- private class ConstantsObserver extends ContentObserver { @@ -311,11 +282,6 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.e(TAG, "Bad jobscheduler settings", e); } } - - if (mConstants.USE_HEARTBEATS) { - // Reset the heartbeat alarm based on the new heartbeat duration - setNextHeartbeatAlarm(); - } } } @@ -465,13 +431,15 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count"; private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time"; private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time"; - private static final String KEY_STANDBY_HEARTBEAT_TIME = "standby_heartbeat_time"; - private static final String KEY_STANDBY_WORKING_BEATS = "standby_working_beats"; - private static final String KEY_STANDBY_FREQUENT_BEATS = "standby_frequent_beats"; - private static final String KEY_STANDBY_RARE_BEATS = "standby_rare_beats"; + private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME = + "standby_heartbeat_time"; + private static final String DEPRECATED_KEY_STANDBY_WORKING_BEATS = "standby_working_beats"; + private static final String DEPRECATED_KEY_STANDBY_FREQUENT_BEATS = + "standby_frequent_beats"; + private static final String DEPRECATED_KEY_STANDBY_RARE_BEATS = "standby_rare_beats"; private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac"; private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac"; - private static final String KEY_USE_HEARTBEATS = "use_heartbeats"; + private static final String DEPRECATED_KEY_USE_HEARTBEATS = "use_heartbeats"; private static final int DEFAULT_MIN_IDLE_COUNT = 1; private static final int DEFAULT_MIN_CHARGING_COUNT = 1; @@ -488,13 +456,8 @@ public class JobSchedulerService extends com.android.server.SystemService private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE; private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; - private static final long DEFAULT_STANDBY_HEARTBEAT_TIME = 11 * 60 * 1000L; - private static final int DEFAULT_STANDBY_WORKING_BEATS = 11; // ~ 2 hours, with 11min beats - private static final int DEFAULT_STANDBY_FREQUENT_BEATS = 43; // ~ 8 hours - private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f; - private static final boolean DEFAULT_USE_HEARTBEATS = false; /** * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things @@ -617,26 +580,7 @@ public class JobSchedulerService extends com.android.server.SystemService * The minimum backoff time to allow for exponential backoff. */ long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME; - /** - * How often we recalculate runnability based on apps' standby bucket assignment. - * This should be prime relative to common time interval lengths such as a quarter- - * hour or day, so that the heartbeat drifts relative to wall-clock milestones. - */ - long STANDBY_HEARTBEAT_TIME = DEFAULT_STANDBY_HEARTBEAT_TIME; - /** - * Mapping: standby bucket -> number of heartbeats between each sweep of that - * bucket's jobs. - * - * Bucket assignments as recorded in the JobStatus objects are normalized to be - * indices into this array, rather than the raw constants used - * by AppIdleHistory. - */ - final int[] STANDBY_BEATS = { - 0, - DEFAULT_STANDBY_WORKING_BEATS, - DEFAULT_STANDBY_FREQUENT_BEATS, - DEFAULT_STANDBY_RARE_BEATS - }; + /** * The fraction of a job's running window that must pass before we * consider running it when the network is congested. @@ -647,11 +591,6 @@ public class JobSchedulerService extends com.android.server.SystemService * we consider matching it against a metered network. */ public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC; - /** - * Whether to use heartbeats or rolling window for quota management. True will use - * heartbeats, false will use a rolling window. - */ - public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -709,19 +648,10 @@ public class JobSchedulerService extends com.android.server.SystemService DEFAULT_MIN_LINEAR_BACKOFF_TIME); MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME, DEFAULT_MIN_EXP_BACKOFF_TIME); - STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME, - DEFAULT_STANDBY_HEARTBEAT_TIME); - STANDBY_BEATS[WORKING_INDEX] = mParser.getInt(KEY_STANDBY_WORKING_BEATS, - DEFAULT_STANDBY_WORKING_BEATS); - STANDBY_BEATS[FREQUENT_INDEX] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS, - DEFAULT_STANDBY_FREQUENT_BEATS); - STANDBY_BEATS[RARE_INDEX] = mParser.getInt(KEY_STANDBY_RARE_BEATS, - DEFAULT_STANDBY_RARE_BEATS); CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC, DEFAULT_CONN_CONGESTION_DELAY_FRAC); CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC, DEFAULT_CONN_PREFETCH_RELAX_FRAC); - USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS); } void dump(IndentingPrintWriter pw) { @@ -757,17 +687,8 @@ public class JobSchedulerService extends com.android.server.SystemService pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println(); pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println(); pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println(); - pw.printPair(KEY_STANDBY_HEARTBEAT_TIME, STANDBY_HEARTBEAT_TIME).println(); - pw.print("standby_beats={"); - pw.print(STANDBY_BEATS[0]); - for (int i = 1; i < STANDBY_BEATS.length; i++) { - pw.print(", "); - pw.print(STANDBY_BEATS[i]); - } - pw.println('}'); pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println(); pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println(); - pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println(); pw.decreaseIndent(); } @@ -797,13 +718,8 @@ public class JobSchedulerService extends com.android.server.SystemService proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT); proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME); proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME); - proto.write(ConstantsProto.STANDBY_HEARTBEAT_TIME_MS, STANDBY_HEARTBEAT_TIME); - for (int period : STANDBY_BEATS) { - proto.write(ConstantsProto.STANDBY_BEATS, period); - } proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC); proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC); - proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS); } } @@ -1441,9 +1357,6 @@ public class JobSchedulerService extends com.android.server.SystemService mAppStateTracker = Preconditions.checkNotNull( LocalServices.getService(AppStateTracker.class)); - if (mConstants.USE_HEARTBEATS) { - setNextHeartbeatAlarm(); - } // Register br for package removals and user removals. final IntentFilter filter = new IntentFilter(); @@ -1647,7 +1560,7 @@ public class JobSchedulerService extends com.android.server.SystemService } delayMillis = Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS); - JobStatus newJob = new JobStatus(failureToReschedule, getCurrentHeartbeat(), + JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, backoffAttempts, failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis()); @@ -1682,8 +1595,7 @@ public class JobSchedulerService extends com.android.server.SystemService * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead * to underscheduling at least, rather than if we had taken the last execution time to be the * start of the execution. - * <p>Unlike a reschedule prior to execution, in this case we advance the next-heartbeat - * tracking as though the job were newly-scheduled. + * * @return A new job representing the execution criteria for this instantiation of the * recurring job. */ @@ -1736,7 +1648,7 @@ public class JobSchedulerService extends com.android.server.SystemService if (newLatestRuntimeElapsed < elapsedNow) { Slog.wtf(TAG, "Rescheduling calculated latest runtime in the past: " + newLatestRuntimeElapsed); - return new JobStatus(periodicToReschedule, getCurrentHeartbeat(), + return new JobStatus(periodicToReschedule, elapsedNow + period - flex, elapsedNow + period, 0 /* backoffAttempt */, sSystemClock.millis() /* lastSuccessfulRunTime */, @@ -1751,64 +1663,13 @@ public class JobSchedulerService extends com.android.server.SystemService newEarliestRunTimeElapsed / 1000 + ", " + newLatestRuntimeElapsed / 1000 + "]s"); } - return new JobStatus(periodicToReschedule, getCurrentHeartbeat(), + return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed, newLatestRuntimeElapsed, 0 /* backoffAttempt */, sSystemClock.millis() /* lastSuccessfulRunTime */, periodicToReschedule.getLastFailedRunTime()); } - /* - * We default to "long enough ago that every bucket's jobs are immediately runnable" to - * avoid starvation of apps in uncommon-use buckets that might arise from repeated - * reboot behavior. - */ - long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) { - // The furthest back in pre-boot time that we need to bother with - long heartbeat = -mConstants.STANDBY_BEATS[RARE_INDEX]; - boolean cacheHit = false; - synchronized (mLock) { - HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId); - if (jobPackages != null) { - long cachedValue = jobPackages.getOrDefault(packageName, Long.MAX_VALUE); - if (cachedValue < Long.MAX_VALUE) { - cacheHit = true; - heartbeat = cachedValue; - } - } - if (!cacheHit) { - // We haven't seen it yet; ask usage stats about it - final long timeSinceJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId); - if (timeSinceJob < Long.MAX_VALUE) { - // Usage stats knows about it from before, so calculate back from that - // and go from there. - heartbeat = mHeartbeat - (timeSinceJob / mConstants.STANDBY_HEARTBEAT_TIME); - } - // If usage stats returned its "not found" MAX_VALUE, we still have the - // negative default 'heartbeat' value we established above - setLastJobHeartbeatLocked(packageName, userId, heartbeat); - } - } - if (DEBUG_STANDBY) { - Slog.v(TAG, "Last job heartbeat " + heartbeat + " for " - + packageName + "/" + userId); - } - return heartbeat; - } - - long heartbeatWhenJobsLastRun(JobStatus job) { - return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId()); - } - - void setLastJobHeartbeatLocked(String packageName, int userId, long heartbeat) { - HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId); - if (jobPackages == null) { - jobPackages = new HashMap<>(); - mLastJobHeartbeats.put(userId, jobPackages); - } - jobPackages.put(packageName, heartbeat); - } - // JobCompletedListener implementations. /** @@ -2082,7 +1943,7 @@ public class JobSchedulerService extends com.android.server.SystemService } catch (RemoteException e) { } if (mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT > 1 - && job.getStandbyBucket() != ACTIVE_INDEX + && job.getEffectiveStandbyBucket() != ACTIVE_INDEX && (job.getFirstForceBatchedTimeElapsed() == 0 || sElapsedRealtimeClock.millis() - job.getFirstForceBatchedTimeElapsed() < mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS)) { @@ -2176,82 +2037,6 @@ public class JobSchedulerService extends com.android.server.SystemService mMaybeQueueFunctor.postProcess(); } - /** - * Heartbeat tracking. The heartbeat alarm is intentionally non-wakeup. - */ - class HeartbeatAlarmListener implements AlarmManager.OnAlarmListener { - - @Override - public void onAlarm() { - synchronized (mLock) { - final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime; - final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME; - if (beatsElapsed > 0) { - mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME; - advanceHeartbeatLocked(beatsElapsed); - } - } - setNextHeartbeatAlarm(); - } - } - - // Intentionally does not touch the alarm timing - void advanceHeartbeatLocked(long beatsElapsed) { - if (!mConstants.USE_HEARTBEATS) { - return; - } - mHeartbeat += beatsElapsed; - if (DEBUG_STANDBY) { - Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed - + " to " + mHeartbeat); - } - // Don't update ACTIVE or NEVER bucket milestones. Note that mHeartbeat - // will be equal to mNextBucketHeartbeat[bucket] for one beat, during which - // new jobs scheduled by apps in that bucket will be permitted to run - // immediately. - boolean didAdvanceBucket = false; - for (int i = 1; i < mNextBucketHeartbeat.length - 1; i++) { - // Did we reach or cross a bucket boundary? - if (mHeartbeat >= mNextBucketHeartbeat[i]) { - didAdvanceBucket = true; - } - while (mHeartbeat > mNextBucketHeartbeat[i]) { - mNextBucketHeartbeat[i] += mConstants.STANDBY_BEATS[i]; - } - if (DEBUG_STANDBY) { - Slog.v(TAG, " Bucket " + i + " next heartbeat " - + mNextBucketHeartbeat[i]); - } - } - - if (didAdvanceBucket) { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Hit bucket boundary; reevaluating job runnability"); - } - mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); - } - } - - void setNextHeartbeatAlarm() { - final long heartbeatLength; - synchronized (mLock) { - if (!mConstants.USE_HEARTBEATS) { - return; - } - heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME; - } - final long now = sElapsedRealtimeClock.millis(); - final long nextBeatOrdinal = (now + heartbeatLength) / heartbeatLength; - final long nextHeartbeat = nextBeatOrdinal * heartbeatLength; - if (DEBUG_STANDBY) { - Slog.i(TAG, "Setting heartbeat alarm for " + nextHeartbeat - + " = " + TimeUtils.formatDuration(nextHeartbeat - now)); - } - AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); - am.setExact(AlarmManager.ELAPSED_REALTIME, nextHeartbeat, - HEARTBEAT_TAG, mHeartbeatAlarm, mHandler); - } - /** Returns true if both the calling and source users for the job are started. */ private boolean areUsersStartedLocked(final JobStatus job) { boolean sourceStarted = ArrayUtils.contains(mStartedUsers, job.getSourceUserId()); @@ -2323,54 +2108,6 @@ public class JobSchedulerService extends com.android.server.SystemService return false; } - if (mConstants.USE_HEARTBEATS) { - // If the app is in a non-active standby bucket, make sure we've waited - // an appropriate amount of time since the last invocation. During device- - // wide parole, standby bucketing is ignored. - // - // Jobs in 'active' apps are not subject to standby, nor are jobs that are - // specifically marked as exempt. - if (DEBUG_STANDBY) { - Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString() - + " parole=" + mInParole + " active=" + job.uidActive - + " exempt=" + job.getJob().isExemptedFromAppStandby()); - } - if (!mInParole - && !job.uidActive - && !job.getJob().isExemptedFromAppStandby()) { - final int bucket = job.getStandbyBucket(); - if (DEBUG_STANDBY) { - Slog.v(TAG, " bucket=" + bucket + " heartbeat=" + mHeartbeat - + " next=" + mNextBucketHeartbeat[bucket]); - } - if (mHeartbeat < mNextBucketHeartbeat[bucket]) { - // Only skip this job if the app is still waiting for the end of its nominal - // bucket interval. Once it's waited that long, we let it go ahead and clear. - // The final (NEVER) bucket is special; we never age those apps' jobs into - // runnability. - final long appLastRan = heartbeatWhenJobsLastRun(job); - if (bucket >= mConstants.STANDBY_BEATS.length - || (mHeartbeat > appLastRan - && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) { - if (job.getWhenStandbyDeferred() == 0) { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < " - + (appLastRan + mConstants.STANDBY_BEATS[bucket]) - + " for " + job); - } - job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis()); - } - return false; - } else { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Bucket deferred job aged into runnability at " - + mHeartbeat + " : " + job); - } - } - } - } - } - // The expensive check: validate that the defined package+service is // still present & viable. return isComponentUsable(job); @@ -2439,9 +2176,6 @@ public class JobSchedulerService extends com.android.server.SystemService // Job pending/active doesn't affect the readiness of a job. - // Skipping the heartbeat check as this will only come into play when using the rolling - // window quota management system. - // The expensive check: validate that the defined package+service is // still present & viable. return isComponentUsable(job); @@ -2450,9 +2184,6 @@ public class JobSchedulerService extends com.android.server.SystemService /** Returns the maximum amount of time this job could run for. */ public long getMaxJobExecutionTimeMs(JobStatus job) { synchronized (mLock) { - if (mConstants.USE_HEARTBEATS) { - return JobServiceContext.EXECUTING_TIMESLICE_MILLIS; - } return Math.min(mQuotaController.getMaxJobExecutionTimeMsLocked(job), JobServiceContext.EXECUTING_TIMESLICE_MILLIS); } @@ -2498,56 +2229,6 @@ public class JobSchedulerService extends com.android.server.SystemService final class LocalService implements JobSchedulerInternal { /** - * The current bucket heartbeat ordinal - */ - public long currentHeartbeat() { - return getCurrentHeartbeat(); - } - - /** - * Heartbeat ordinal at which the given standby bucket's jobs next become runnable - */ - public long nextHeartbeatForBucket(int bucket) { - synchronized (mLock) { - return mNextBucketHeartbeat[bucket]; - } - } - - /** - * Heartbeat ordinal for the given app. This is typically the heartbeat at which - * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run - * jobs in a long time is immediately runnable even if the app is bucketed into - * an infrequent time allocation. - */ - public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, - final int appStandbyBucket) { - if (appStandbyBucket == 0 || - appStandbyBucket >= mConstants.STANDBY_BEATS.length) { - // ACTIVE => everything can be run right away - // NEVER => we won't run them anyway, so let them go in the future - // as soon as the app enters normal use - if (DEBUG_STANDBY) { - Slog.v(TAG, "Base heartbeat forced ZERO for new job in " - + packageName + "/" + userId); - } - return 0; - } - - final long baseHeartbeat = heartbeatWhenJobsLastRun(packageName, userId); - if (DEBUG_STANDBY) { - Slog.v(TAG, "Base heartbeat " + baseHeartbeat + " for new job in " - + packageName + "/" + userId); - } - return baseHeartbeat; - } - - public void noteJobStart(String packageName, int userId) { - synchronized (mLock) { - setLastJobHeartbeatLocked(packageName, userId, mHeartbeat); - } - } - - /** * Returns a list of all pending jobs. A running job is not considered pending. Periodic * jobs are always considered pending. */ @@ -3158,12 +2839,6 @@ public class JobSchedulerService extends com.android.server.SystemService } } - long getCurrentHeartbeat() { - synchronized (mLock) { - return mHeartbeat; - } - } - // Shell command infrastructure int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) { try { @@ -3249,21 +2924,6 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; } - // Shell command infrastructure - int executeHeartbeatCommand(PrintWriter pw, int numBeats) { - if (numBeats < 1) { - pw.println(getCurrentHeartbeat()); - return 0; - } - - pw.print("Advancing standby heartbeat by "); - pw.println(numBeats); - synchronized (mLock) { - advanceHeartbeatLocked(numBeats); - } - return 0; - } - void triggerDockState(boolean idleState) { final Intent dockIntent; if (idleState) { @@ -3319,20 +2979,6 @@ public class JobSchedulerService extends com.android.server.SystemService } pw.println(); - pw.println(" Heartbeat:"); - pw.print(" Current: "); pw.println(mHeartbeat); - pw.println(" Next"); - pw.print(" ACTIVE: "); pw.println(mNextBucketHeartbeat[0]); - pw.print(" WORKING: "); pw.println(mNextBucketHeartbeat[1]); - pw.print(" FREQUENT: "); pw.println(mNextBucketHeartbeat[2]); - pw.print(" RARE: "); pw.println(mNextBucketHeartbeat[3]); - pw.print(" Last heartbeat: "); - TimeUtils.formatDuration(mLastHeartbeatTime, nowElapsed, pw); - pw.println(); - pw.print(" Next heartbeat: "); - TimeUtils.formatDuration(mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME, - nowElapsed, pw); - pw.println(); pw.print(" In parole?: "); pw.print(mInParole); pw.println(); @@ -3358,9 +3004,6 @@ public class JobSchedulerService extends com.android.server.SystemService } job.dump(pw, " ", true, nowElapsed); - pw.print(" Last run heartbeat: "); - pw.print(heartbeatWhenJobsLastRun(job)); - pw.println(); pw.print(" Ready: "); pw.print(isReadyToBeExecutedLocked(job)); @@ -3514,15 +3157,6 @@ public class JobSchedulerService extends com.android.server.SystemService } proto.end(settingsToken); - proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[2]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[3]); - proto.write(JobSchedulerServiceDumpProto.LAST_HEARTBEAT_TIME_MILLIS, - mLastHeartbeatTime - nowUptime); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS, - mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime); proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole); proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mThermalConstraint); @@ -3564,7 +3198,6 @@ public class JobSchedulerService extends com.android.server.SystemService } proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_PRESENT, componentPresent); - proto.write(RegisteredJob.LAST_RUN_HEARTBEAT, heartbeatWhenJobsLastRun(job)); proto.end(rjToken); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index e3614413121a..01d158ba9452 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -340,15 +340,8 @@ public final class JobSchedulerShellCommand extends ShellCommand { private int doHeartbeat(PrintWriter pw) throws Exception { checkPermission("manipulate scheduler heartbeat"); - final String arg = getNextArg(); - final int numBeats = (arg != null) ? Integer.parseInt(arg) : 0; - - final long ident = Binder.clearCallingIdentity(); - try { - return mInternal.executeHeartbeatCommand(pw, numBeats); - } finally { - Binder.restoreCallingIdentity(ident); - } + pw.println("Heartbeat command is no longer supported"); + return -1; } private int triggerDockState(PrintWriter pw) throws Exception { @@ -401,8 +394,7 @@ public final class JobSchedulerShellCommand extends ShellCommand { pw.println(" -u or --user: specify which user's job is to be run; the default is"); pw.println(" the primary or system user"); pw.println(" heartbeat [num]"); - pw.println(" With no argument, prints the current standby heartbeat. With a positive"); - pw.println(" argument, advances the standby heartbeat by that number."); + pw.println(" No longer used."); pw.println(" monitor-battery [on|off]"); pw.println(" Control monitoring of all battery changes. Off by default. Turning"); pw.println(" on makes get-battery-seq useful."); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 7da128f9d3ec..4d9f1331e6ff 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -285,9 +285,6 @@ public final class JobServiceContext implements ServiceConnection { UsageStatsManagerInternal usageStats = LocalServices.getService(UsageStatsManagerInternal.class); usageStats.setLastJobRunTime(jobPackage, jobUserId, mExecutionStartTimeElapsed); - JobSchedulerInternal jobScheduler = - LocalServices.getService(JobSchedulerInternal.class); - jobScheduler.noteJobStart(jobPackage, jobUserId); mAvailable = false; mStoppedReason = null; mStoppedTime = 0; diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index d69faf37397c..4321fc716b4d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -189,7 +189,7 @@ public final class JobStore { if (utcTimes != null) { Pair<Long, Long> elapsedRuntimes = convertRtcBoundsToElapsed(utcTimes, elapsedNow); - JobStatus newJob = new JobStatus(job, job.getBaseHeartbeat(), + JobStatus newJob = new JobStatus(job, elapsedRuntimes.first, elapsedRuntimes.second, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime()); newJob.prepareLocked(am); @@ -944,10 +944,9 @@ public final class JobStore { JobSchedulerInternal service = LocalServices.getService(JobSchedulerInternal.class); final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName, sourceUserId, elapsedNow); - long currentHeartbeat = service != null ? service.currentHeartbeat() : 0; JobStatus js = new JobStatus( jobBuilder.build(), uid, sourcePackageName, sourceUserId, - appBucket, currentHeartbeat, sourceTag, + appBucket, sourceTag, elapsedRuntimes.first, elapsedRuntimes.second, lastSuccessfulRunTime, lastFailedRunTime, (rtcIsGood) ? null : rtcRuntimes, internalFlags); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index f8cf6ae04950..a67aadfc6959 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -47,7 +47,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobSchedulerService.Constants; -import com.android.server.job.JobServiceContext; import com.android.server.job.StateControllerProto; import com.android.server.net.NetworkPolicyManagerInternal; @@ -88,8 +87,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") private final ArraySet<Network> mAvailableNetworks = new ArraySet<>(); - private boolean mUseQuotaLimit; - private static final int MSG_DATA_SAVER_TOGGLED = 0; private static final int MSG_UID_RULES_CHANGES = 1; private static final int MSG_REEVALUATE_JOBS = 2; @@ -110,8 +107,6 @@ public final class ConnectivityController extends StateController implements mConnManager.registerNetworkCallback(request, mNetworkCallback); mNetPolicyManager.registerListener(mNetPolicyListener); - - mUseQuotaLimit = !mConstants.USE_HEARTBEATS; } @GuardedBy("mLock") @@ -142,24 +137,6 @@ public final class ConnectivityController extends StateController implements } } - @GuardedBy("mLock") - @Override - public void onConstantsUpdatedLocked() { - if (mConstants.USE_HEARTBEATS) { - // App idle exceptions are only requested for the rolling quota system. - if (DEBUG) Slog.i(TAG, "Revoking all standby exceptions"); - for (int i = 0; i < mRequestedWhitelistJobs.size(); ++i) { - int uid = mRequestedWhitelistJobs.keyAt(i); - mNetPolicyManagerInternal.setAppIdleWhitelist(uid, false); - } - mRequestedWhitelistJobs.clear(); - } - if (mUseQuotaLimit == mConstants.USE_HEARTBEATS) { - mUseQuotaLimit = !mConstants.USE_HEARTBEATS; - mHandler.obtainMessage(MSG_REEVALUATE_JOBS).sendToTarget(); - } - } - /** * Returns true if the job's requested network is available. This DOES NOT necesarilly mean * that the UID has been granted access to the network. @@ -237,11 +214,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override public void evaluateStateLocked(JobStatus jobStatus) { - if (mConstants.USE_HEARTBEATS) { - // This should only be used for the rolling quota system. - return; - } - if (!jobStatus.hasConnectivityConstraint()) { return; } @@ -263,9 +235,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override public void reevaluateStateLocked(final int uid) { - if (mConstants.USE_HEARTBEATS) { - return; - } // Check if we still need a connectivity exception in case the JobService was disabled. ArraySet<JobStatus> jobs = mTrackedJobs.get(uid); if (jobs == null) { @@ -329,9 +298,7 @@ public final class ConnectivityController extends StateController implements */ private boolean isInsane(JobStatus jobStatus, Network network, NetworkCapabilities capabilities, Constants constants) { - final long maxJobExecutionTimeMs = mUseQuotaLimit - ? mService.getMaxJobExecutionTimeMs(jobStatus) - : JobServiceContext.EXECUTING_TIMESLICE_MILLIS; + final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus); final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes(); if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { @@ -617,7 +584,6 @@ public final class ConnectivityController extends StateController implements @Override public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { - pw.print("mUseQuotaLimit="); pw.println(mUseQuotaLimit); if (mRequestedWhitelistJobs.size() > 0) { pw.print("Requested standby exceptions:"); 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 6f2b33453891..3c50e3809e7b 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,7 @@ package com.android.server.job.controllers; +import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.app.AppGlobals; @@ -169,12 +170,6 @@ public final class JobStatus { private final int numFailures; /** - * Current standby heartbeat when this job was scheduled or last ran. Used to - * pin the runnability check regardless of the job's app moving between buckets. - */ - private final long baseHeartbeat; - - /** * Which app standby bucket this job's app is in. Updated when the app is moved to a * different bucket. */ @@ -350,8 +345,6 @@ public final class JobStatus { * @param standbyBucket The standby bucket that the source package is currently assigned to, * cached here for speed of handling during runnability evaluations (and updated when bucket * assignments are changed) - * @param heartbeat Timestamp of when the job was created, in the standby-related - * timebase. * @param tag A string associated with the job for debugging/logging purposes. * @param numFailures Count of how many times this job has requested a reschedule because * its work was not yet finished. @@ -364,13 +357,12 @@ public final class JobStatus { * @param internalFlags Non-API property flags about this job */ private JobStatus(JobInfo job, int callingUid, String sourcePackageName, - int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures, + int sourceUserId, int standbyBucket, String tag, int numFailures, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) { this.job = job; this.callingUid = callingUid; this.standbyBucket = standbyBucket; - this.baseHeartbeat = heartbeat; int tempSourceUid = -1; if (sourceUserId != -1 && sourcePackageName != null) { @@ -440,7 +432,7 @@ public final class JobStatus { public JobStatus(JobStatus jobStatus) { this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), - jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(), + jobStatus.getStandbyBucket(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(), @@ -462,13 +454,13 @@ public final class JobStatus { * standby bucket is whatever the OS thinks it should be at this moment. */ public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId, - int standbyBucket, long baseHeartbeat, String sourceTag, + int standbyBucket, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, Pair<Long, Long> persistedExecutionTimesUTC, int innerFlags) { this(job, callingUid, sourcePkgName, sourceUserId, - standbyBucket, baseHeartbeat, + standbyBucket, sourceTag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, innerFlags); @@ -486,13 +478,13 @@ public final class JobStatus { } /** Create a new job to be rescheduled with the provided parameters. */ - public JobStatus(JobStatus rescheduling, long newBaseHeartbeat, + public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, long newLatestRuntimeElapsedMillis, int backoffAttempt, long lastSuccessfulRunTime, long lastFailedRunTime) { this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), - rescheduling.getStandbyBucket(), newBaseHeartbeat, + rescheduling.getStandbyBucket(), rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis, newLatestRuntimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags()); @@ -529,11 +521,8 @@ public final class JobStatus { int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage, sourceUserId, elapsedNow); JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); - long currentHeartbeat = js != null - ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket) - : 0; return new JobStatus(job, callingUid, sourcePkg, sourceUserId, - standbyBucket, currentHeartbeat, tag, 0, + standbyBucket, tag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, /*innerFlags=*/ 0); @@ -710,12 +699,22 @@ public final class JobStatus { return UserHandle.getUserId(callingUid); } - public int getStandbyBucket() { - return standbyBucket; + /** + * Returns an appropriate standby bucket for the job, taking into account any standby + * exemptions. + */ + public int getEffectiveStandbyBucket() { + if (uidActive || getJob().isExemptedFromAppStandby()) { + // Treat these cases as if they're in the ACTIVE bucket so that they get throttled + // like other ACTIVE apps. + return ACTIVE_INDEX; + } + return getStandbyBucket(); } - public long getBaseHeartbeat() { - return baseHeartbeat; + /** Returns the real standby bucket of the job. */ + public int getStandbyBucket() { + return standbyBucket; } public void setStandbyBucket(int newBucket) { @@ -1631,10 +1630,6 @@ public final class JobStatus { } pw.print(prefix); pw.print("Standby bucket: "); pw.println(getBucketName()); - if (standbyBucket > 0) { - pw.print(prefix); pw.print("Base heartbeat: "); - pw.println(baseHeartbeat); - } if (whenStandbyDeferred != 0) { pw.print(prefix); pw.print(" Deferred since: "); TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index b8cfac4d4206..38950d5a9d34 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -416,13 +416,6 @@ public final class QuotaController extends StateController { private volatile boolean mInParole; - /** - * If the QuotaController should throttle apps based on their standby bucket and job activity. - * If false, all jobs will have their CONSTRAINT_WITHIN_QUOTA bit set to true immediately and - * indefinitely. - */ - private boolean mShouldThrottle; - /** How much time each app will have to run jobs within their standby bucket window. */ private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS; @@ -594,8 +587,6 @@ public final class QuotaController extends StateController { } catch (RemoteException e) { // ignored; both services live in system_server } - - mShouldThrottle = !mConstants.USE_HEARTBEATS; } @Override @@ -607,8 +598,6 @@ public final class QuotaController extends StateController { public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); - // Still need to track jobs even if mShouldThrottle is false in case it's set to true at - // some point. ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName); if (jobs == null) { jobs = new ArraySet<>(); @@ -616,16 +605,10 @@ public final class QuotaController extends StateController { } jobs.add(jobStatus); jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA); - if (mShouldThrottle) { - final boolean isWithinQuota = isWithinQuotaLocked(jobStatus); - setConstraintSatisfied(jobStatus, isWithinQuota); - if (!isWithinQuota) { - maybeScheduleStartAlarmLocked(userId, pkgName, - getEffectiveStandbyBucket(jobStatus)); - } - } else { - // QuotaController isn't throttling, so always set to true. - jobStatus.setQuotaConstraintSatisfied(true); + final boolean isWithinQuota = isWithinQuotaLocked(jobStatus); + setConstraintSatisfied(jobStatus, isWithinQuota); + if (!isWithinQuota) { + maybeScheduleStartAlarmLocked(userId, pkgName, jobStatus.getEffectiveStandbyBucket()); } } @@ -674,20 +657,6 @@ public final class QuotaController extends StateController { } @Override - public void onConstantsUpdatedLocked() { - if (mShouldThrottle == mConstants.USE_HEARTBEATS) { - mShouldThrottle = !mConstants.USE_HEARTBEATS; - - // Update job bookkeeping out of band. - BackgroundThread.getHandler().post(() -> { - synchronized (mLock) { - maybeUpdateAllConstraintsLocked(); - } - }); - } - } - - @Override public void onAppRemovedLocked(String packageName, int uid) { if (packageName == null) { Slog.wtf(TAG, "Told app removed but given null package name."); @@ -750,22 +719,9 @@ public final class QuotaController extends StateController { return getRemainingExecutionTimeLocked(jobStatus); } - /** - * Returns an appropriate standby bucket for the job, taking into account any standby - * exemptions. - */ - private int getEffectiveStandbyBucket(@NonNull final JobStatus jobStatus) { - if (jobStatus.uidActive || jobStatus.getJob().isExemptedFromAppStandby()) { - // Treat these cases as if they're in the ACTIVE bucket so that they get throttled - // like other ACTIVE apps. - return ACTIVE_INDEX; - } - return jobStatus.getStandbyBucket(); - } - @VisibleForTesting boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) { - final int standbyBucket = getEffectiveStandbyBucket(jobStatus); + final int standbyBucket = jobStatus.getEffectiveStandbyBucket(); // A job is within quota if one of the following is true: // 1. it was started while the app was in the TOP state // 2. the app is currently in the foreground @@ -780,8 +736,6 @@ public final class QuotaController extends StateController { boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { if (standbyBucket == NEVER_INDEX) return false; - // This check is needed in case the flag is toggled after a job has been registered. - if (!mShouldThrottle) return true; // Quota constraint is not enforced while charging or when parole is on. if (mChargeTracker.isCharging() || mInParole) { @@ -817,7 +771,7 @@ public final class QuotaController extends StateController { long getRemainingExecutionTimeLocked(@NonNull final JobStatus jobStatus) { return getRemainingExecutionTimeLocked(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), - getEffectiveStandbyBucket(jobStatus)); + jobStatus.getEffectiveStandbyBucket()); } @VisibleForTesting @@ -1291,7 +1245,7 @@ public final class QuotaController extends StateController { // finish. changed |= js.setQuotaConstraintSatisfied(true); } else if (realStandbyBucket != ACTIVE_INDEX - && realStandbyBucket == getEffectiveStandbyBucket(js)) { + && realStandbyBucket == js.getEffectiveStandbyBucket()) { // An app in the ACTIVE bucket may be out of quota while the job could be in quota // for some reason. Therefore, avoid setting the real value here and check each job // individually. @@ -1820,8 +1774,7 @@ public final class QuotaController extends StateController { if (timer != null && timer.isActive()) { timer.rescheduleCutoff(); } - if (!mShouldThrottle || maybeUpdateConstraintForPkgLocked(userId, - packageName)) { + if (maybeUpdateConstraintForPkgLocked(userId, packageName)) { mStateChangedListener.onControllerStateChanged(); } } @@ -2396,7 +2349,7 @@ public final class QuotaController extends StateController { changed = true; } - if (changed && mShouldThrottle) { + if (changed) { // Update job bookkeeping out of band. BackgroundThread.getHandler().post(() -> { synchronized (mLock) { @@ -2561,7 +2514,6 @@ public final class QuotaController extends StateController { @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate<JobStatus> predicate) { - pw.println("Is throttling: " + mShouldThrottle); pw.println("Is charging: " + mChargeTracker.isCharging()); pw.println("In parole: " + mInParole); pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis()); @@ -2598,7 +2550,7 @@ public final class QuotaController extends StateController { pw.println(); pw.increaseIndent(); - pw.print(JobStatus.bucketName(getEffectiveStandbyBucket(js))); + pw.print(JobStatus.bucketName(js.getEffectiveStandbyBucket())); pw.print(", "); if (js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) { pw.print("within quota"); @@ -2710,7 +2662,7 @@ public final class QuotaController extends StateController { js.getSourceUid()); proto.write( StateControllerProto.QuotaController.TrackedJob.EFFECTIVE_STANDBY_BUCKET, - getEffectiveStandbyBucket(js)); + js.getEffectiveStandbyBucket()); proto.write(StateControllerProto.QuotaController.TrackedJob.IS_TOP_STARTED_JOB, mTopStartedJobs.contains(js)); proto.write(StateControllerProto.QuotaController.TrackedJob.HAS_QUOTA, diff --git a/api/current.txt b/api/current.txt index aee8eb1b161f..e76501328f82 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6794,6 +6794,7 @@ package android.app.admin { method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String); method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String); method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>); + method public boolean setKeyGrantForApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String, boolean); method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean); method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean); method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int); @@ -29830,6 +29831,7 @@ package android.net.wifi { method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); method public int getMaxNumberOfNetworkSuggestionsPerApp(); + method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) @NonNull public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions(); method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); @@ -40627,8 +40629,9 @@ package android.se.omapi { package android.security { public final class AttestedKeyPair { - method public java.util.List<java.security.cert.Certificate> getAttestationRecord(); - method public java.security.KeyPair getKeyPair(); + ctor public AttestedKeyPair(@Nullable java.security.KeyPair, @Nullable java.security.cert.Certificate[]); + method @NonNull public java.util.List<java.security.cert.Certificate> getAttestationRecord(); + method @Nullable public java.security.KeyPair getKeyPair(); } public class ConfirmationAlreadyPresentingException extends java.lang.Exception { @@ -73165,7 +73168,7 @@ package java.util.logging { method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String); method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @NonNull java.util.function.Supplier<java.lang.String>); method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Object); - method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, Object[]); + method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Object[]); method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Throwable); method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>); method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String); diff --git a/api/system-current.txt b/api/system-current.txt index eef6b3f98e61..18e30bac8dfc 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3693,7 +3693,7 @@ package android.media.audiopolicy { package android.media.session { public final class MediaSessionManager { - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull android.media.session.MediaSessionManager.Callback, @Nullable android.os.Handler); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.Callback); method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback); @@ -7170,6 +7170,14 @@ package android.telephony { field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; } + public static final class CarrierConfigManager.Wifi { + field public static final String KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING = "wifi.carrier_connection_manager_package_string"; + field public static final String KEY_CARRIER_PROFILES_VERSION_INT = "wifi.carrier_profiles_version_int"; + field public static final String KEY_NETWORK_PROFILES_STRING_ARRAY = "wifi.network_profiles_string_array"; + field public static final String KEY_PASSPOINT_PROFILES_STRING_ARRAY = "wifi.passpoint_profiles_string_array"; + field public static final String KEY_PREFIX = "wifi."; + } + public final class CarrierRestrictionRules implements android.os.Parcelable { method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); method public int describeContents(); @@ -9095,6 +9103,7 @@ package android.telephony.ims.feature { public abstract class ImsFeature { ctor public ImsFeature(); method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method public final int getSlotIndex(); method public abstract void onFeatureReady(); method public abstract void onFeatureRemoved(); method public final void setFeatureState(int); @@ -9108,7 +9117,7 @@ package android.telephony.ims.feature { field public static final int STATE_UNAVAILABLE = 0; // 0x0 } - @Deprecated public static class ImsFeature.Capabilities { + public static class ImsFeature.Capabilities { field @Deprecated protected int mCapabilities; } diff --git a/api/test-current.txt b/api/test-current.txt index 8e6ff3019b0a..46a0e1b16ebe 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2869,6 +2869,11 @@ package android.telephony { method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int); } + public class PhoneNumberUtils { + method public static int getMinMatchForTest(); + method public static void setMinMatchForTest(int); + } + public class ServiceState implements android.os.Parcelable { method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo); method public void setCdmaSystemAndNetworkId(int, int); diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp index c1f86544070e..3e5877b05708 100644 --- a/cmds/bootanimation/Android.bp +++ b/cmds/bootanimation/Android.bp @@ -40,27 +40,6 @@ cc_binary { "audioplay.cpp", ], - product_variables: { - product_is_iot: { - shared_libs: [ - "libandroidthings", - "libandroidthings_protos", - "libchrome", - "libprotobuf-cpp-lite", - ], - static_libs: ["libjsoncpp"], - srcs: [ - "iot/iotbootanimation_main.cpp", - "iot/BootAction.cpp", - "iot/BootParameters.cpp", - ], - exclude_srcs: [ - "bootanimation_main.cpp", - "audioplay.cpp", - ], - }, - }, - init_rc: ["bootanim.rc"], } @@ -80,10 +59,4 @@ cc_library_shared { "libGLESv1_CM", "libgui", ], - - product_variables: { - product_is_iot: { - init_rc: ["iot/bootanim_iot.rc"], - }, - }, } diff --git a/cmds/bootanimation/iot/Android.bp b/cmds/bootanimation/iot/Android.bp deleted file mode 100644 index 1f248adcb9e1..000000000000 --- a/cmds/bootanimation/iot/Android.bp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2018 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. -// - -// libbootanimation_iot_test -// =========================================================== -cc_test { - name: "libbootanimation_iot_test", - cflags: [ - "-Wall", - "-Werror", - "-Wunused", - "-Wunreachable-code", - ], - - shared_libs: [ - "libandroidthings", - "libandroidthings_protos", - "libbase", - "libchrome", - "liblog", - "libprotobuf-cpp-lite", - ], - - static_libs: ["libjsoncpp"], - - srcs: [ - "BootParameters.cpp", - "BootParameters_test.cpp", - ], - - enabled: false, - product_variables: { - product_is_iot: { - enabled: true, - }, - }, -} diff --git a/cmds/bootanimation/iot/BootAction.cpp b/cmds/bootanimation/iot/BootAction.cpp deleted file mode 100644 index 8b55147110bc..000000000000 --- a/cmds/bootanimation/iot/BootAction.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#include "BootAction.h" - -#define LOG_TAG "BootAction" - -#include <dlfcn.h> - -#include <pio/peripheral_manager_client.h> -#include <utils/Log.h> - -namespace android { - -BootAction::~BootAction() { - if (mLibHandle != nullptr) { - dlclose(mLibHandle); - } -} - -bool BootAction::init(const std::string& libraryPath, - const std::unique_ptr<BootParameters>& bootParameters) { - APeripheralManagerClient* client = nullptr; - ALOGD("Connecting to peripheralmanager"); - // Wait for peripheral manager to come up. - while (client == nullptr) { - client = APeripheralManagerClient_new(); - if (client == nullptr) { - ALOGV("peripheralmanager is not up, sleeping before we check again."); - usleep(250000); - } - } - ALOGD("Peripheralmanager is up."); - APeripheralManagerClient_delete(client); - - - ALOGI("Loading boot action %s", libraryPath.c_str()); - mLibHandle = dlopen(libraryPath.c_str(), RTLD_NOW); - if (mLibHandle == nullptr) { - ALOGE("Unable to load library at %s :: %s", - libraryPath.c_str(), dlerror()); - return false; - } - - void* loaded = nullptr; - if (!loadSymbol("boot_action_init", &loaded) || loaded == nullptr) { - return false; - } - mLibInit = reinterpret_cast<libInit>(loaded); - - loaded = nullptr; - if (!loadSymbol("boot_action_shutdown", &loaded) || loaded == nullptr) { - return false; - } - mLibShutdown = reinterpret_cast<libShutdown>(loaded); - - // StartPart is considered optional, if it isn't exported by the library - // we will still call init and shutdown. - loaded = nullptr; - if (!loadSymbol("boot_action_start_part", &loaded) || loaded == nullptr) { - ALOGI("No boot_action_start_part found, action will not be told when " - "Animation parts change."); - } else { - mLibStartPart = reinterpret_cast<libStartPart>(loaded); - } - - // SilentBoot is considered optional, if it isn't exported by the library - // and the boot is silent, no method is called. - loaded = nullptr; - if (!loadSymbol("boot_action_silent_boot", &loaded) || loaded == nullptr) { - ALOGW("No boot_action_silent_boot found, boot action will not be " - "executed during a silent boot."); - } else { - mLibSilentBoot = reinterpret_cast<libInit>(loaded); - } - - bool result = true; - const auto& parameters = bootParameters->getParameters(); - if (bootParameters->isSilentBoot()) { - if (mLibSilentBoot != nullptr) { - ALOGD("Entering boot_action_silent_boot"); - result = mLibSilentBoot(parameters.data(), parameters.size()); - ALOGD("Returned from boot_action_silent_boot"); - } else { - ALOGW("Skipping missing boot_action_silent_boot"); - } - } else { - ALOGD("Entering boot_action_init"); - result = mLibInit(parameters.data(), parameters.size()); - ALOGD("Returned from boot_action_init"); - } - - return result; -} - -void BootAction::startPart(int partNumber, int playNumber) { - if (mLibStartPart == nullptr) return; - - ALOGD("Entering boot_action_start_part"); - mLibStartPart(partNumber, playNumber); - ALOGD("Returned from boot_action_start_part"); -} - -void BootAction::shutdown() { - ALOGD("Entering boot_action_shutdown"); - mLibShutdown(); - ALOGD("Returned from boot_action_shutdown"); -} - -bool BootAction::loadSymbol(const char* symbol, void** loaded) { - *loaded = dlsym(mLibHandle, symbol); - if (*loaded == nullptr) { - ALOGE("Unable to load symbol : %s :: %s", symbol, dlerror()); - return false; - } - return true; -} - -} // namespace android diff --git a/cmds/bootanimation/iot/BootAction.h b/cmds/bootanimation/iot/BootAction.h deleted file mode 100644 index 7119c35db0f9..000000000000 --- a/cmds/bootanimation/iot/BootAction.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#ifndef _BOOTANIMATION_BOOTACTION_H -#define _BOOTANIMATION_BOOTACTION_H - -#include <string> -#include <vector> - -#include "BootParameters.h" - -#include <boot_action/boot_action.h> // libandroidthings native API. -#include <utils/RefBase.h> - -namespace android { - -class BootAction : public RefBase { -public: - ~BootAction(); - - // libraryPath is a fully qualified path to the target .so library. - bool init(const std::string& libraryPath, - const std::unique_ptr<BootParameters>& bootParameters); - - // The animation is going to start playing partNumber for the playCount'th - // time, update the action as needed. - // This is run in the same thread as the boot animation, - // you must not block here. - void startPart(int partNumber, int playCount); - - // Shutdown the boot action, this will be called shortly before the - // process is shut down to allow time for cleanup. - void shutdown(); - -private: - typedef bool (*libInit)(const ABootActionParameter* parameters, - size_t numParameters); - typedef void (*libStartPart)(int partNumber, int playNumber); - typedef void (*libShutdown)(); - - bool loadSymbol(const char* symbol, void** loaded); - - void* mLibHandle = nullptr; - libInit mLibInit = nullptr; - libStartPart mLibStartPart = nullptr; - libShutdown mLibShutdown = nullptr; - - // Called only if the boot is silent. - libInit mLibSilentBoot = nullptr; -}; - -} // namespace android - - -#endif // _BOOTANIMATION_BOOTACTION_H diff --git a/cmds/bootanimation/iot/BootParameters.cpp b/cmds/bootanimation/iot/BootParameters.cpp deleted file mode 100644 index 30a9b2895c44..000000000000 --- a/cmds/bootanimation/iot/BootParameters.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#include "BootParameters.h" - -#define LOG_TAG "BootParameters" - -#include <errno.h> -#include <fcntl.h> - -#include <android-base/file.h> -#include <json/json.h> -#include <utils/Log.h> - -using android::base::ReadFileToString; -using android::base::RemoveFileIfExists; -using android::base::WriteStringToFile; -using Json::ArrayIndex; -using Json::Reader; -using Json::Value; - -namespace android { - -namespace { - -// Keys for deprecated parameters. Devices that OTA from N to O and that used -// the hidden BootParameters API will store these in the JSON blob. To support -// the transition from N to O, these keys are mapped to the new parameters. -constexpr const char *kKeyLegacyVolume = "volume"; -constexpr const char *kKeyLegacyAnimationsDisabled = "boot_animation_disabled"; -constexpr const char *kKeyLegacyParamNames = "param_names"; -constexpr const char *kKeyLegacyParamValues = "param_values"; - -constexpr const char *kNextBootFile = "/data/misc/bootanimation/next_boot.proto"; -constexpr const char *kLastBootFile = "/data/misc/bootanimation/last_boot.proto"; - -constexpr const char *kLegacyNextBootFile = "/data/misc/bootanimation/next_boot.json"; -constexpr const char *kLegacyLastBootFile = "/data/misc/bootanimation/last_boot.json"; - -void removeLegacyFiles() { - std::string err; - if (!RemoveFileIfExists(kLegacyLastBootFile, &err)) { - ALOGW("Unable to delete %s: %s", kLegacyLastBootFile, err.c_str()); - } - - err.clear(); - if (!RemoveFileIfExists(kLegacyNextBootFile, &err)) { - ALOGW("Unable to delete %s: %s", kLegacyNextBootFile, err.c_str()); - } -} - -void createNextBootFile() { - errno = 0; - int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE); - if (fd == -1) { - ALOGE("Unable to create next boot file: %s", strerror(errno)); - } else { - // Make next_boot.json writable to everyone so DeviceManagementService - // can save saved_parameters there. - if (fchmod(fd, DEFFILEMODE)) - ALOGE("Unable to set next boot file permissions: %s", strerror(errno)); - close(fd); - } -} - -} // namespace - -// Renames the 'next' boot file to the 'last' file and reads its contents. -bool BootParameters::swapAndLoadBootConfigContents(const char *lastBootFile, - const char *nextBootFile, - std::string *contents) { - if (!ReadFileToString(nextBootFile, contents)) { - RemoveFileIfExists(lastBootFile); - return false; - } - - errno = 0; - if (rename(nextBootFile, lastBootFile) && errno != ENOENT) - ALOGE("Unable to swap boot files: %s", strerror(errno)); - - return true; -} - -BootParameters::BootParameters() { - loadParameters(); -} - -// Saves the boot parameters state to disk so the framework can read it. -void BootParameters::storeParameters() { - errno = 0; - if (!WriteStringToFile(mProto.SerializeAsString(), kLastBootFile)) { - ALOGE("Failed to write boot parameters to %s: %s", kLastBootFile, strerror(errno)); - } - - // WriteStringToFile sets the file permissions to 0666, but these are not - // honored by the system. - errno = 0; - if (chmod(kLastBootFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { - ALOGE("Failed to set permissions for %s: %s", kLastBootFile, strerror(errno)); - } -} - -// Load the boot parameters from disk, try the old location and format if the -// file does not exist. Note: -// - Parse errors result in defaults being used (a normal boot). -// - Legacy boot parameters default to a silent boot. -void BootParameters::loadParameters() { - // Precedence is given to the new file format (.proto). - std::string contents; - if (swapAndLoadBootConfigContents(kLastBootFile, kNextBootFile, &contents)) { - parseBootParameters(contents); - } else if (swapAndLoadBootConfigContents(kLegacyLastBootFile, kLegacyNextBootFile, &contents)) { - parseLegacyBootParameters(contents); - storeParameters(); - removeLegacyFiles(); - } - - createNextBootFile(); -} - -void BootParameters::parseBootParameters(const std::string &contents) { - if (!mProto.ParseFromString(contents)) { - ALOGW("Failed to parse parameters from %s", kLastBootFile); - return; - } - - loadStateFromProto(); -} - -// Parses the JSON in the proto. -void BootParameters::parseLegacyBootParameters(const std::string &contents) { - Value json; - if (!Reader().parse(contents, json)) { - ALOGW("Failed to parse parameters from %s", kLegacyLastBootFile); - return; - } - - int volume = 0; - bool bootAnimationDisabled = true; - - Value &jsonValue = json[kKeyLegacyVolume]; - if (jsonValue.isIntegral()) { - volume = jsonValue.asInt(); - } - - jsonValue = json[kKeyLegacyAnimationsDisabled]; - if (jsonValue.isIntegral()) { - bootAnimationDisabled = jsonValue.asInt() == 1; - } - - // Assume a silent boot unless all of the following are true - - // 1. The volume is neither 0 nor -1000 (the legacy default value). - // 2. The boot animations are explicitly enabled. - // Note: brightness was never used. - mProto.set_silent_boot((volume == 0) || (volume == -1000) || bootAnimationDisabled); - - Value &keys = json[kKeyLegacyParamNames]; - Value &values = json[kKeyLegacyParamValues]; - if (keys.isArray() && values.isArray() && (keys.size() == values.size())) { - for (ArrayIndex i = 0; i < keys.size(); ++i) { - auto &key = keys[i]; - auto &value = values[i]; - if (key.isString() && value.isString()) { - auto userParameter = mProto.add_user_parameter(); - userParameter->set_key(key.asString()); - userParameter->set_value(value.asString()); - } - } - } - - loadStateFromProto(); -} - -void BootParameters::loadStateFromProto() { - // A missing key returns a safe, default value. - // Ignore invalid or missing parameters. - mIsSilentBoot = mProto.silent_boot(); - - for (const auto ¶m : mProto.user_parameter()) { - mParameters.push_back({.key = param.key().c_str(), .value = param.value().c_str()}); - } -} - -} // namespace android diff --git a/cmds/bootanimation/iot/BootParameters.h b/cmds/bootanimation/iot/BootParameters.h deleted file mode 100644 index cbd1ca61cfc3..000000000000 --- a/cmds/bootanimation/iot/BootParameters.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#ifndef _BOOTANIMATION_BOOT_PARAMETERS_H_ -#define _BOOTANIMATION_BOOT_PARAMETERS_H_ - -#include <list> -#include <string> -#include <vector> - -#include <boot_action/boot_action.h> // libandroidthings native API. -#include <boot_parameters.pb.h> - -namespace android { - -// Provides access to the parameters set by DeviceManager.reboot(). -class BootParameters { -public: - // Constructor loads the parameters for this boot and swaps the param files - // to clear the parameters for next boot. - BootParameters(); - - // Returns whether or not this is a silent boot. - bool isSilentBoot() const { return mIsSilentBoot; } - - // Returns the additional boot parameters that were set on reboot. - const std::vector<ABootActionParameter>& getParameters() const { return mParameters; } - - // Exposed for testing. Sets the parameters to the serialized proto. - void parseBootParameters(const std::string &contents); - - // For devices that OTA from N to O. - // Exposed for testing. Sets the parameters to the raw JSON. - void parseLegacyBootParameters(const std::string &contents); - - // Exposed for testing. Loads the contents from |nextBootFile| and replaces - // |lastBootFile| with |nextBootFile|. - static bool swapAndLoadBootConfigContents(const char *lastBootFile, const char *nextBootFile, - std::string *contents); - - private: - void loadParameters(); - - // Replaces the legacy JSON blob with the updated version, allowing the - // framework to read it. - void storeParameters(); - - void loadStateFromProto(); - - bool mIsSilentBoot = false; - - std::vector<ABootActionParameter> mParameters; - - // Store the proto because mParameters makes a shallow copy. - android::things::proto::BootParameters mProto; -}; - -} // namespace android - - -#endif // _BOOTANIMATION_BOOT_PARAMETERS_H_ diff --git a/cmds/bootanimation/iot/BootParameters_test.cpp b/cmds/bootanimation/iot/BootParameters_test.cpp deleted file mode 100644 index d55bce6eecc3..000000000000 --- a/cmds/bootanimation/iot/BootParameters_test.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#include "BootParameters.h" - -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <android-base/file.h> -#include <android-base/test_utils.h> -#include <boot_parameters.pb.h> -#include <gtest/gtest.h> - -namespace android { - -namespace { - -TEST(BootParametersTest, TestNoBootParametersIsNotSilent) { - android::things::proto::BootParameters proto; - - BootParameters bootParameters = BootParameters(); - bootParameters.parseBootParameters(proto.SerializeAsString()); - - ASSERT_FALSE(bootParameters.isSilentBoot()); - ASSERT_EQ(0u, bootParameters.getParameters().size()); -} - -TEST(BootParametersTest, TestParseIsSilent) { - android::things::proto::BootParameters proto; - proto.set_silent_boot(true); - - BootParameters bootParameters = BootParameters(); - bootParameters.parseBootParameters(proto.SerializeAsString()); - - ASSERT_TRUE(bootParameters.isSilentBoot()); -} - -TEST(BootParametersTest, TestParseIsNotSilent) { - android::things::proto::BootParameters proto; - proto.set_silent_boot(false); - - BootParameters bootParameters = BootParameters(); - bootParameters.parseBootParameters(proto.SerializeAsString()); - - ASSERT_FALSE(bootParameters.isSilentBoot()); -} - -TEST(BootParametersTest, TestParseBootParameters) { - android::things::proto::BootParameters proto; - proto.set_silent_boot(false); - - auto userParameter = proto.add_user_parameter(); - userParameter->set_key("key1"); - userParameter->set_value("value1"); - - userParameter = proto.add_user_parameter(); - userParameter->set_key("key2"); - userParameter->set_value("value2"); - - BootParameters bootParameters = BootParameters(); - bootParameters.parseBootParameters(proto.SerializeAsString()); - - auto ¶meters = bootParameters.getParameters(); - ASSERT_EQ(2u, parameters.size()); - ASSERT_STREQ(parameters[0].key, "key1"); - ASSERT_STREQ(parameters[0].value, "value1"); - ASSERT_STREQ(parameters[1].key, "key2"); - ASSERT_STREQ(parameters[1].value, "value2"); -} - -TEST(BootParametersTest, TestParseLegacyDisableBootAnimationIsSilent) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":200, - "volume":100, - "boot_animation_disabled":1, - "param_names":[], - "param_values":[] - } - )"); - - ASSERT_TRUE(bootParameters.isSilentBoot()); -} - -TEST(BootParametersTest, TestParseLegacyZeroVolumeIsSilent) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":200, - "volume":0, - "boot_animation_disabled":0, - "param_names":[], - "param_values":[] - } - )"); - - ASSERT_TRUE(bootParameters.isSilentBoot()); -} - -TEST(BootParametersTest, TestParseLegacyDefaultVolumeIsSilent) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":200, - "volume":-1000, - "boot_animation_disabled":0, - "param_names":[], - "param_values":[] - } - )"); - - ASSERT_TRUE(bootParameters.isSilentBoot()); -} - -TEST(BootParametersTest, TestParseLegacyNotSilent) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":200, - "volume":500, - "boot_animation_disabled":0, - "param_names":[], - "param_values":[] - } - )"); - - ASSERT_FALSE(bootParameters.isSilentBoot()); -} - -TEST(BootParametersTest, TestParseLegacyParameters) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":200, - "volume":100, - "boot_animation_disabled":1, - "param_names":["key1", "key2"], - "param_values":["value1", "value2"] - } - )"); - - auto parameters = bootParameters.getParameters(); - ASSERT_EQ(2u, parameters.size()); - ASSERT_STREQ(parameters[0].key, "key1"); - ASSERT_STREQ(parameters[0].value, "value1"); - ASSERT_STREQ(parameters[1].key, "key2"); - ASSERT_STREQ(parameters[1].value, "value2"); -} - -TEST(BootParametersTest, TestParseLegacyZeroParameters) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":200, - "volume":100, - "boot_animation_disabled":1, - "param_names":[], - "param_values":[] - } - )"); - - ASSERT_EQ(0u, bootParameters.getParameters().size()); -} - -TEST(BootParametersTest, TestMalformedLegacyParametersAreSkipped) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":500, - "volume":500, - "boot_animation_disabled":0, - "param_names":["key1", "key2"], - "param_values":[1, "value2"] - } - )"); - - auto parameters = bootParameters.getParameters(); - ASSERT_EQ(1u, parameters.size()); - ASSERT_STREQ(parameters[0].key, "key2"); - ASSERT_STREQ(parameters[0].value, "value2"); -} - -TEST(BootParametersTest, TestLegacyUnequalParameterSizesAreSkipped) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":500, - "volume":500, - "boot_animation_disabled":0, - "param_names":["key1", "key2"], - "param_values":["value1"] - } - )"); - - ASSERT_EQ(0u, bootParameters.getParameters().size()); -} - -TEST(BootParametersTest, TestMissingLegacyBootParametersIsSilent) { - BootParameters bootParameters = BootParameters(); - bootParameters.parseLegacyBootParameters(R"( - { - "brightness":500 - } - )"); - - EXPECT_TRUE(bootParameters.isSilentBoot()); - ASSERT_EQ(0u, bootParameters.getParameters().size()); -} - -TEST(BootParametersTest, TestLastFileIsRemovedOnError) { - TemporaryFile lastFile; - TemporaryDir tempDir; - std::string nonExistentFilePath(std::string(tempDir.path) + "/nonexistent"); - std::string contents; - - BootParameters::swapAndLoadBootConfigContents(lastFile.path, nonExistentFilePath.c_str(), - &contents); - - struct stat buf; - ASSERT_EQ(-1, lstat(lastFile.path, &buf)); - ASSERT_TRUE(contents.empty()); -} - -TEST(BootParametersTest, TestNextFileIsRemovedLastFileExistsOnSuccess) { - TemporaryFile lastFile; - TemporaryFile nextFile; - - base::WriteStringToFile("foo", nextFile.path); - - std::string contents; - // Expected side effects: - // - |next_file| is moved to |last_file| - // - |contents| is the contents of |next_file| before being moved. - BootParameters::swapAndLoadBootConfigContents(lastFile.path, nextFile.path, &contents); - - struct stat buf; - ASSERT_EQ(0, lstat(lastFile.path, &buf)); - ASSERT_EQ(-1, lstat(nextFile.path, &buf)); - ASSERT_EQ(contents, "foo"); - - contents.clear(); - ASSERT_TRUE(base::ReadFileToString(lastFile.path, &contents)); - ASSERT_EQ(contents, "foo"); -} - -} // namespace - -} // namespace android diff --git a/cmds/bootanimation/iot/bootanim_iot.rc b/cmds/bootanimation/iot/bootanim_iot.rc deleted file mode 100644 index 2fc13364b53d..000000000000 --- a/cmds/bootanimation/iot/bootanim_iot.rc +++ /dev/null @@ -1,2 +0,0 @@ -on post-fs-data - mkdir /data/misc/bootanimation 0777 root root diff --git a/cmds/bootanimation/iot/iotbootanimation_main.cpp b/cmds/bootanimation/iot/iotbootanimation_main.cpp deleted file mode 100644 index ae3529796b9a..000000000000 --- a/cmds/bootanimation/iot/iotbootanimation_main.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#define LOG_TAG "IotBootAnimation" - -#include <base/files/file_util.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/ProcessState.h> -#include <cutils/properties.h> -#include <sys/resource.h> -#include <utils/Log.h> -#include <utils/threads.h> -#include <BootAnimation.h> - -#include "BootAction.h" -#include "BootAnimationUtil.h" -#include "BootParameters.h" - -using namespace android; - -// Create a typedef for readability. -typedef android::BootAnimation::Animation Animation; - -namespace { - -constexpr const char* kDefaultLibName = "libbootaction.so"; - -class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks { -public: - BootActionAnimationCallbacks(std::unique_ptr<BootParameters> bootParameters) - : mBootParameters(std::move(bootParameters)) {} - - void init(const Vector<Animation::Part>&) override { - std::string library_path("/oem/lib/"); - - // This value is optionally provided by the user and will be written to - // /oem/oem.prop. - char property[PROP_VALUE_MAX] = {0}; - property_get("ro.oem.bootactions.lib", property, kDefaultLibName); - library_path += property; - - if (!::base::PathExists(::base::FilePath(library_path))) { - ALOGI("Skipping boot actions: %s does not exist", library_path.c_str()); - return; - } - - mBootAction = new BootAction(); - if (!mBootAction->init(library_path, mBootParameters)) { - mBootAction = nullptr; - } - }; - - void playPart(int partNumber, const Animation::Part&, int playNumber) override { - if (mBootAction != nullptr) { - mBootAction->startPart(partNumber, playNumber); - } - }; - - void shutdown() override { - if (mBootAction != nullptr) { - // If we have a bootaction we want to wait until we are actually - // told to shut down. If the animation exits early keep the action - // running. - char value[PROPERTY_VALUE_MAX] = {0}; - for (int exitRequested = 0; exitRequested == 0; ) { - property_get("service.bootanim.exit", value, "0"); - exitRequested = atoi(value); - - // Poll value at 10hz. - if (exitRequested == 0) { - usleep(100000); - } - } - - mBootAction->shutdown(); - // Give it two seconds to shut down. - sleep(2); - mBootAction = nullptr; - } - }; - -private: - std::unique_ptr<BootParameters> mBootParameters; - sp<BootAction> mBootAction = nullptr; -}; - -} // namespace - -int main() { - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY); - - // Clear our params for next boot no matter what. - std::unique_ptr<BootParameters> bootParameters(new BootParameters()); - - if (bootAnimationDisabled()) { - ALOGI("boot animation disabled"); - return 0; - } - - waitForSurfaceFlinger(); - - sp<ProcessState> proc(ProcessState::self()); - ProcessState::self()->startThreadPool(); - - bool isSilentBoot = bootParameters->isSilentBoot(); - sp<BootActionAnimationCallbacks> callbacks = - new BootActionAnimationCallbacks(std::move(bootParameters)); - - // On silent boot, animations aren't displayed. - if (isSilentBoot) { - callbacks->init({}); - } else { - sp<BootAnimation> boot = new BootAnimation(callbacks); - } - - IPCThreadState::self()->joinThreadPool(); - return 0; -} diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index f6c72ea9d3b9..35c4cebdcf6c 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -56,6 +56,7 @@ import "frameworks/base/core/proto/android/telecomm/enums.proto"; import "frameworks/base/core/proto/android/telephony/enums.proto"; import "frameworks/base/core/proto/android/view/enums.proto"; import "frameworks/base/core/proto/android/wifi/enums.proto"; +import "frameworks/base/core/proto/android/stats/textclassifier/textclassifier_enums.proto"; /** * The master atom class. This message defines all of the available @@ -319,6 +320,16 @@ message Atom { 217 [(log_from_module) = "permissioncontroller"]; PermissionAppsFragmentViewed permission_apps_fragment_viewed = 218 [(log_from_module) = "permissioncontroller"]; + TextSelectionEvent text_selection_event = + 219 [(log_from_module) = "textclassifier"]; + TextLinkifyEvent text_linkify_event = + 220 [(log_from_module) = "textclassifier"]; + ConversationActionsEvent conversation_actions_event = + 221 [(log_from_module) = "textclassifier"]; + LanguageDetectionEvent language_detection_event = + 222 [(log_from_module) = "textclassifier"]; + ExclusionRectStateChanged exclusion_rect_state_changed = 223; + BackGesture back_gesture_reported_reported = 224; } // Pulled events will start at field 10000. @@ -2500,6 +2511,41 @@ message PhoneStateChanged { optional State state = 1; } +message BackGesture { + enum BackType { + DEFAULT_BACK_TYPE = 0; + COMPLETED = 1; + COMPLETED_REJECTED = 2; // successful because coming from rejected area + INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area + INCOMPLETE = 4; + } + optional BackType type = 1; + + optional int32 y_coordinate = 2; // y coordinate for ACTION_DOWN event + enum WindowHorizontalLocation { + DEFAULT_LOCATION = 0; + LEFT = 1; + RIGHT = 2; + } + optional WindowHorizontalLocation x_location = 3; +} + +message ExclusionRectStateChanged { + optional string component_name = 1; // if not available, simply packageName + optional int32 requested_height = 2; // px + optional int32 rejected_height = 3; // px + + enum WindowHorizontalLocation { + DEFAULT_LOCATION = 0; + LEFT = 1; + RIGHT = 2; + } + optional WindowHorizontalLocation x_location = 4; + optional bool landscape = 5; + optional bool splitscreen = 6; + optional int32 duration_millis = 7; +} + message LauncherUIChanged { optional android.stats.launcher.LauncherAction action = 1; optional android.stats.launcher.LauncherState src_state = 2; @@ -6790,3 +6836,136 @@ message PermissionAppsFragmentViewed { } optional Category category = 6; } + +/** + * Logs when there is a smart selection related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message TextSelectionEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // Index of this event in a session. + optional int32 event_index = 5; + + // Entity type that is involved. + optional string entity_type = 6; + + // Relative word index of the start of the selection. + optional int32 relative_word_start_index = 7; + + // Relative word (exclusive) index of the end of the selection. + optional int32 relative_word_end_index = 8; + + // Relative word index of the start of the smart selection. + optional int32 relative_suggested_word_start_index = 9; + + // Relative word (exclusive) index of the end of the smart selection. + optional int32 relative_suggested_word_end_index = 10; +} + +/** + * Logs when there is a smart linkify related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message TextLinkifyEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // Index of this event in a session. + optional int32 event_index = 5; + + // Entity type that is involved. + optional string entity_type = 6; + + // Number of links detected. + optional int32 num_links = 7; + + // The total length of all links. + optional int32 linked_text_length = 8; + + // Length of input text. + optional int32 text_length = 9; + + // Time spent on generating links in ms. + optional int64 latency_millis = 10; +} + +/** + * Logs when there is a conversation actions related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message ConversationActionsEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // The first entity type that is involved. + optional string first_entity_type = 5; + + // The second entity type that is involved. + optional string second_entity_type = 6; + + // The third entity type that is involved. + optional string third_entity_type = 7; + + // The score of the first entity type. + optional float score = 8; +} + +/** + * Logs when there is a language detection related event. + * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java + * Logged from: TextClassifierEventLogger.java + */ +message LanguageDetectionEvent { + // A session ID. + optional string session_id = 1; + + // Event type of this event. + optional android.stats.textclassifier.EventType event_type = 2; + + // Name of the model that is involved in this event. + optional string model_name = 3; + + // Type of widget that was involved in triggering this event. + optional android.stats.textclassifier.WidgetType widget_type = 4; + + // Detected language. + optional string language_tag = 5; + + // Score of the detected language. + optional float score = 6; + + // Position of this action. + optional int32 action_index = 7; +} diff --git a/config/boot-profile.txt b/config/boot-profile.txt index e69de29bb2d1..57e06c23b7ec 100644 --- a/config/boot-profile.txt +++ b/config/boot-profile.txt @@ -0,0 +1,642 @@ +Lcom/android/internal/os/RuntimeInit$MethodAndArgsCaller;->run()V +Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V +Lcom/android/internal/util/ConcurrentUtils$1$1;->run()V +Lcom/android/server/SystemConfig;->getInstance()Lcom/android/server/SystemConfig; +Lcom/android/server/SystemConfig;-><init>()V +Lcom/android/server/SystemConfig;->readPermissions(Ljava/io/File;I)V +Lcom/android/server/SystemConfig;->readPermissionsFromXml(Ljava/io/File;I)V +Lcom/android/internal/os/ProcessCpuTracker;->update()V +Lcom/android/internal/os/ProcessCpuTracker;->init()V +Lcom/android/internal/os/ProcessCpuTracker;->collectStats(Ljava/lang/String;IZ[ILjava/util/ArrayList;)[I +Landroid/content/pm/PackageParser$SigningDetails$Builder;->build()Landroid/content/pm/PackageParser$SigningDetails; +Landroid/content/pm/PackageParser$SigningDetails;-><init>(Landroid/content/pm/PackageParser$SigningDetails;)V +Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I)V +Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;ILandroid/util/ArraySet;[Landroid/content/pm/Signature;)V +Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I[Landroid/content/pm/Signature;)V +Landroid/util/ArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object; +Landroid/util/ArrayMap;->indexOfKey(Ljava/lang/Object;)I +Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey; +Landroid/util/ArrayMap;->indexOf(Ljava/lang/Object;I)I +Landroid/util/ArrayMap;->indexOfNull()I +Landroid/util/ArrayMap;->indexOfValue(Ljava/lang/Object;)I +Lcom/android/internal/os/ProcessCpuTracker;->getName(Lcom/android/internal/os/ProcessCpuTracker$Stats;Ljava/lang/String;)V +Lcom/android/internal/os/ProcStatsUtil;->readTerminatedProcFile(Ljava/lang/String;B)Ljava/lang/String; +Lcom/android/internal/os/BatteryStatsImpl;->writeAsyncLocked()V +Lcom/android/internal/os/BatteryStatsImpl;->writeStatsLocked(Z)V +Lcom/android/internal/os/BatteryStatsImpl;->writeSummaryToParcel(Landroid/os/Parcel;Z)V +Landroid/util/SparseArray;->get(I)Ljava/lang/Object; +Landroid/util/SparseArray;->get(ILjava/lang/Object;)Ljava/lang/Object; +Lcom/android/internal/os/BatteryStatsImpl;->readLocked()V +Lcom/android/internal/os/BatteryStatsImpl;->readSummaryFromParcel(Landroid/os/Parcel;)V +Landroid/util/ArrayMap;->binarySearchHashes([III)I +Landroid/util/ContainerHelpers;->binarySearch([III)I +Lcom/android/internal/os/BatteryStatsImpl;->updateCpuTimeLocked(ZZ)V +Lcom/android/internal/os/KernelCpuUidTimeReader;->readDelta(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V +Landroid/util/ArrayMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Landroid/util/ArrayMap;->putAll(Landroid/util/ArrayMap;)V +Landroid/util/ArrayMap;->putAll(Ljava/util/Map;)V +Landroid/util/SparseArray;-><init>()V +Landroid/util/SparseArray;-><init>(I)V +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V +Lcom/android/server/SystemConfig;->readPrivAppPermissions(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;Landroid/util/ArrayMap;)V +Landroid/content/pm/Signature;-><init>(Ljava/lang/String;)V +Landroid/content/pm/Signature;-><init>([B)V +Landroid/content/pm/Signature;-><init>([Ljava/security/cert/Certificate;)V +Lcom/android/internal/os/ProcessCpuTracker$Stats;-><init>(IIZ)V +Lcom/android/internal/os/KernelCpuProcStringReader;->asLongs(Ljava/nio/CharBuffer;[J)I +Lcom/android/internal/util/XmlUtils;->nextElement(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/internal/util/XmlUtils;->nextElementWithin(Lorg/xmlpull/v1/XmlPullParser;I)Z +Lcom/android/internal/util/ArrayUtils;->newUnpaddedObjectArray(I)[Ljava/lang/Object; +Landroid/util/SparseArray;->put(ILjava/lang/Object;)V +Lcom/android/internal/os/BatteryStatsImpl;->updateKernelWakelocksLocked()V +Landroid/util/ArraySet;->add(Ljava/lang/Object;)Z +Landroid/util/ArraySet;->addAll(Landroid/util/ArraySet;)V +Landroid/util/ArraySet;->addAll(Ljava/util/Collection;)Z +Lcom/android/internal/os/KernelWakelockReader;->readKernelWakelockStats(Lcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; +Lcom/android/internal/util/GrowingArrayUtils;->insert([IIII)[I +Lcom/android/internal/util/GrowingArrayUtils;->insert([JIIJ)[J +Lcom/android/internal/util/GrowingArrayUtils;->insert([Ljava/lang/Object;IILjava/lang/Object;)[Ljava/lang/Object; +Lcom/android/internal/util/GrowingArrayUtils;->insert([ZIIZ)[Z +HPLcom/android/internal/app/procstats/ProcessStats;-><init>(Landroid/os/Parcel;)V +Lcom/android/internal/app/procstats/ProcessStats;-><init>(Z)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;-><init>(Lcom/android/internal/os/BatteryStatsImpl;I)V +Lcom/android/internal/os/KernelWakelockReader;->parseProcWakelocks([BIZLcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; +Landroid/content/pm/PackageParser;->getCachedResult(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parsePackageItemInfo(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageItemInfo;[Ljava/lang/String;Ljava/lang/String;Landroid/content/res/TypedArray;ZIIIIII)Z +Landroid/content/pm/PackageParser;->parsePackageList(Ljava/lang/String;)Ljava/util/Set; +Landroid/content/pm/PackageParser;->parsePackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite; +Landroid/content/pm/PackageParser;->parsePackageSplitNames(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;)Landroid/util/Pair; +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V +Landroid/content/pm/Signature;->parseHexDigit(I)I +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->readWakeSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V +Landroid/util/ArraySet;->iterator()Ljava/util/Iterator; +Landroid/content/pm/PackageParser;->fromCacheEntryStatic([B)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->fromCacheEntry([B)Landroid/content/pm/PackageParser$Package; +Lcom/android/internal/os/BatteryStatsImpl$Timer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidUserSysTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V +Landroid/os/FileUtils;->bytesToFile(Ljava/lang/String;[B)V +Landroid/os/StrictMode;->allowThreadDiskReads()Landroid/os/StrictMode$ThreadPolicy; +Landroid/os/StrictMode;->allowThreadDiskReadsMask()I +Landroid/content/pm/PackageParser$Package;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageParser$Package;-><init>(Ljava/lang/String;)V +Lcom/android/server/SystemConfig;->addFeature(Ljava/lang/String;I)V +Landroid/os/StrictMode;->setThreadPolicy(Landroid/os/StrictMode$ThreadPolicy;)V +Landroid/os/StrictMode;->setThreadPolicyMask(I)V +Landroid/content/pm/FallbackCategoryProvider;->loadFallbacks()V +Landroid/os/Parcel$ReadWriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V +Landroid/os/Parcel;->writeString(Ljava/lang/String;)V +Landroid/os/Parcel;->writeStringArray([Ljava/lang/String;)V +Landroid/os/Parcel;->writeStringList(Ljava/util/List;)V +Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->add(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V +Landroid/os/Parcel;->writeInt(I)V +Landroid/os/Parcel;->writeIntArray([I)V +Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V +Landroid/content/pm/PackageParser;->parsePublicKey(Ljava/lang/String;)Ljava/security/PublicKey; +Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;->nextLine()Ljava/nio/CharBuffer; +Landroid/util/Xml;->newPullParser()Lorg/xmlpull/v1/XmlPullParser; +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Lcom/android/internal/os/PowerProfile;)[J +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Ljava/lang/String;)[J +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V +Landroid/os/HandlerThread;->run()V +Landroid/os/Looper;->loop()V +Landroid/util/SparseArray;->size()I +Landroid/util/ArrayMap;-><init>()V +Landroid/util/ArrayMap;-><init>(I)V +Landroid/util/ArrayMap;-><init>(IZ)V +Landroid/util/ArrayMap;-><init>(Landroid/util/ArrayMap;)V +Landroid/os/Parcel;->writeLong(J)V +Landroid/os/Parcel;->writeLongArray([J)V +Landroid/os/Parcel;->readParcelable(Ljava/lang/ClassLoader;)Landroid/os/Parcelable; +Landroid/os/Parcel;->readParcelableArray(Ljava/lang/ClassLoader;Ljava/lang/Class;)[Landroid/os/Parcelable; +Landroid/os/Parcel;->readParcelableCreator(Ljava/lang/ClassLoader;)Landroid/os/Parcelable$Creator; +Landroid/os/Parcel;->readParcelableList(Ljava/util/List;Ljava/lang/ClassLoader;)Ljava/util/List; +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V +Landroid/os/SystemProperties;->getBoolean(Ljava/lang/String;Z)Z +Landroid/content/pm/IntentFilterVerificationInfo;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V +Landroid/util/ArrayMap;->allocArrays(I)V +Landroid/os/Parcel;->readInt()I +Landroid/os/Parcel;->readIntArray([I)V +Landroid/content/pm/IntentFilterVerificationInfo;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I +Lcom/android/internal/util/ArrayUtils;->appendInt([IIZ)[I +Landroid/util/TimingsTraceLog;->traceEnd()V +Lcom/android/internal/os/BatteryStatsImpl$Timer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Landroid/os/Parcel;->readString()Ljava/lang/String; +Landroid/os/Parcel;->readStringArray()[Ljava/lang/String; +Landroid/os/Parcel;->readStringList(Ljava/util/List;)V +Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;->add(Ljava/lang/String;Ljava/lang/Object;)V +Lcom/android/internal/os/BatteryStatsImpl;->getKernelWakelockTimerLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer; +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Landroid/os/storage/StorageManager;->hasAdoptable()Z +Landroid/os/Parcel$ReadWriteHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String; +Landroid/os/Handler;->dispatchMessage(Landroid/os/Message;)V +Lcom/android/internal/os/BatteryStatsImpl$5;->run()V +Lcom/android/internal/os/BatteryStatsImpl;->commitPendingDataToDisk(Landroid/os/Parcel;Lcom/android/internal/os/AtomicFile;)V +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;)I +Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;I)I +Landroid/util/ArraySet;->indexOfNull()I +Landroid/os/Parcel;->readLong()J +Landroid/os/Parcel;->readLongArray([J)V +Lcom/android/internal/util/XmlUtils;->skipCurrentTag(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->getServiceStatsLocked(Ljava/lang/String;Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv; +Landroid/os/StrictMode;->setBlockGuardPolicy(I)V +Landroid/util/TimingsTraceLog;->logDuration(Ljava/lang/String;J)V +Landroid/util/Base64;->decode(Ljava/lang/String;I)[B +Landroid/util/Base64;->decode([BI)[B +Landroid/util/Base64;->decode([BIII)[B +Landroid/util/ArrayMap;->valueAt(I)Ljava/lang/Object; +Lcom/android/internal/os/BatteryStatsImpl$Uid;->getWakelockTimerLocked(Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;I)Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer; +Landroid/util/ArraySet;-><init>()V +Landroid/util/ArraySet;-><init>(I)V +Landroid/util/ArraySet;-><init>(Landroid/util/ArraySet;)V +Landroid/util/ArraySet;-><init>(Ljava/util/Collection;)V +Lcom/android/internal/os/KernelCpuProcStringReader;->open(Z)Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator; +Landroid/content/pm/ApplicationInfo;-><init>()V +Landroid/content/pm/ApplicationInfo;-><init>(Landroid/content/pm/ApplicationInfo;)V +Landroid/content/pm/ApplicationInfo;-><init>(Landroid/os/Parcel;)V +Landroid/util/ArraySet;->remove(Ljava/lang/Object;)Z +Landroid/util/ArraySet;->removeAll(Ljava/util/Collection;)Z +Landroid/util/ArraySet;->removeAt(I)Ljava/lang/Object; +Landroid/util/ArraySet;->removeAll(Landroid/util/ArraySet;)Z +Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ApplicationInfo; +Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/os/ServiceManagerProxy;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V +Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;)V +Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;Z)V +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V +Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V +Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V +Lcom/android/internal/os/PowerProfile;->readPowerValuesFromXml(Landroid/content/Context;Z)V +Lcom/android/server/SystemConfig;->readPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V +Landroid/content/res/ResourcesImpl;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;Landroid/view/DisplayAdjustments;)V +Landroid/os/ServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/os/ServiceManager;->getServiceOrThrow(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/util/Base64$Decoder;->process([BIIZ)Z +Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)J +Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;J)J +Lcom/android/internal/os/BatteryStatsImpl$Uid;->getPackageStatsLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg; +Lcom/android/internal/app/procstats/ProcessStats;->resetCommon()V +HPLcom/android/internal/app/procstats/ProcessStats;->resetSafely()V +Landroid/content/res/ResourcesImpl;->updateConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V +Landroid/content/res/Resources;-><init>()V +Landroid/content/res/Resources;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;)V +Landroid/content/res/Resources;-><init>(Ljava/lang/ClassLoader;)V +Landroid/os/ServiceManager;->rawGetService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/util/LongSparseArray;->put(JLjava/lang/Object;)V +Landroid/util/ArrayMap;->freeArrays([I[Ljava/lang/Object;I)V +Landroid/util/ArrayMap;->keyAt(I)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Activity; +Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/content/pm/PackageParser$ParseComponentArgs;Landroid/content/pm/ActivityInfo;)V +Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/os/Parcel;)V +Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V +Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V +Landroid/util/ArraySet;->allocArrays(I)V +Landroid/os/storage/StorageManager;->isFileEncryptedNativeOnly()Z +Lcom/android/internal/os/BatteryStatsImpl$Counter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl;->updateRailStatsLocked()V +Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/util/SparseIntArray;-><init>()V +Landroid/util/SparseIntArray;-><init>(I)V +Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)I +Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V +Lcom/android/internal/os/BatteryStatsImpl;-><init>(Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V +Lcom/android/internal/app/procstats/ProcessStats;->updateFragmentation()V +Landroid/os/Parcel;->readTypedObject(Landroid/os/Parcelable$Creator;)Ljava/lang/Object; +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getTotalDurationMsLocked(J)J +Landroid/os/Parcel;->createTypedArray(Landroid/os/Parcelable$Creator;)[Ljava/lang/Object; +Landroid/os/Parcel;->createTypedArrayList(Landroid/os/Parcelable$Creator;)Ljava/util/ArrayList; +Landroid/os/Parcel;->createTypedArrayMap(Landroid/os/Parcelable$Creator;)Landroid/util/ArrayMap; +Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String; +Lcom/android/server/LocalServices;->addService(Ljava/lang/Class;Ljava/lang/Object;)V +Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I +Landroid/util/TimingsTraceLog;->traceBegin(Ljava/lang/String;)V +Landroid/content/res/AssetManager;-><init>()V +Landroid/content/res/AssetManager;->getResourceValue(IILandroid/util/TypedValue;Z)Z +Landroid/util/LongSparseLongArray;->put(JJ)V +Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->uptimeMillis()J +Landroid/content/res/AssetManager;->setApkAssets([Landroid/content/res/ApkAssets;Z)V +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->readSummaryFromParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray; +Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Z +Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z +Landroid/os/StrictMode$ThreadPolicy;-><init>(ILandroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)V +Lcom/android/internal/os/KernelCpuSpeedReader;->readDelta()[J +Lcom/android/internal/os/AtomicFile;->startWrite()Ljava/io/FileOutputStream; +Landroid/app/ContextImpl;->createSystemUiContext(Landroid/app/ContextImpl;I)Landroid/app/ContextImpl; +Landroid/app/ActivityThread;->getSystemUiContext()Landroid/app/ContextImpl; +Landroid/os/Parcel;->recycle()V +Landroid/util/Slog;->i(Ljava/lang/String;Ljava/lang/String;)I +Landroid/os/Binder;-><init>()V +Landroid/os/Binder;-><init>(Ljava/lang/String;)V +Landroid/content/Context;->getSystemService(Ljava/lang/Class;)Ljava/lang/Object; +Lcom/android/internal/util/ArrayUtils;->newUnpaddedLongArray(I)[J +Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V +Landroid/content/res/ResourcesImpl;->getValueForDensity(IILandroid/util/TypedValue;Z)V +Landroid/util/LongSparseLongArray;-><init>()V +Landroid/util/LongSparseLongArray;-><init>(I)V +Landroid/os/BatteryStats$Timer;-><init>()V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->createAggregatedPartialWakelockTimerLocked()Lcom/android/internal/os/BatteryStatsImpl$DualTimer; +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2300(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobCompletionsFromParcelLocked(Landroid/os/Parcel;)V +Landroid/util/MapCollections$KeySet;->iterator()Ljava/util/Iterator; +Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->writeSummaryToParcel(Landroid/os/Parcel;JJ)V +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->computeRunTimeLocked(J)J +Landroid/bluetooth/BluetoothAdapter;->getDefaultAdapter()Landroid/bluetooth/BluetoothAdapter; +Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->startAndInstall()V +Landroid/content/pm/PackageItemInfo;-><init>(Landroid/content/pm/PackageItemInfo;)V +Landroid/content/pm/PackageItemInfo;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/ActivityInfo;-><init>()V +Landroid/content/pm/ActivityInfo;-><init>(Landroid/content/pm/ActivityInfo;)V +Landroid/content/pm/ActivityInfo;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ActivityInfo; +Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/os/BinderProxy;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Landroid/os/HandlerThread;->getLooper()Landroid/os/Looper; +Landroid/os/FileUtils;->$closeResource(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V +Landroid/os/SystemProperties;->digestOf([Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/util/ArrayUtils;->isEmpty(Ljava/util/Collection;)Z +Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z +Landroid/util/AtomicFile;-><init>(Ljava/io/File;)V +Landroid/util/AtomicFile;-><init>(Ljava/io/File;Ljava/lang/String;)V +Landroid/util/LongSparseArray;-><init>()V +Landroid/util/LongSparseArray;-><init>(I)V +Landroid/content/res/Resources;->obtainTypedArray(I)Landroid/content/res/TypedArray; +Landroid/util/AtomicFile;->openRead()Ljava/io/FileInputStream; +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;-><init>(Z)V +Lcom/android/internal/os/BatteryStatsImpl$Counter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->makeProcessState(ILandroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Lcom/android/internal/os/BatteryStatsImpl$DualTimer; +Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Ljava/lang/Object; +Landroid/content/pm/PackageUserState;-><init>()V +Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidActiveTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V +Lcom/android/internal/os/BatteryStatsImpl;->updateRpmStatsLocked()V +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/KernelMemoryBandwidthStats;->updateStats()V +Landroid/content/pm/PackageParser;->isCacheUpToDate(Ljava/io/File;Ljava/io/File;)Z +Landroid/os/StrictMode;->initThreadDefaults(Landroid/content/pm/ApplicationInfo;)V +Landroid/app/ResourcesManager;->getOrCreateResources(Landroid/os/IBinder;Landroid/content/res/ResourcesKey;Ljava/lang/ClassLoader;)Landroid/content/res/Resources; +Landroid/app/ResourcesManager;->getOrCreateResourcesForActivityLocked(Landroid/os/IBinder;Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources; +Landroid/app/ResourcesManager;->getOrCreateResourcesLocked(Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources; +Landroid/app/ResourcesManager;->getResources(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;Ljava/lang/ClassLoader;)Landroid/content/res/Resources; +Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;[Ljava/lang/String;)Landroid/content/res/Resources; +Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources; +Landroid/app/ContextImpl;->getSystemService(Ljava/lang/String;)Ljava/lang/Object; +Landroid/app/ContextImpl;->getSystemServiceName(Ljava/lang/Class;)Ljava/lang/String; +Landroid/app/SystemServiceRegistry$CachedServiceFetcher;->getService(Landroid/app/ContextImpl;)Ljava/lang/Object; +Landroid/util/TimingsTraceLog;->assertSameThread()V +Landroid/os/HandlerThread;-><init>(Ljava/lang/String;)V +Landroid/os/HandlerThread;-><init>(Ljava/lang/String;I)V +Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I +Landroid/content/res/Configuration;-><init>()V +Landroid/content/res/Configuration;-><init>(Landroid/content/res/Configuration;)V +Landroid/view/SurfaceControl;->getInternalDisplayToken()Landroid/os/IBinder; +Landroid/view/SurfaceControl;->getPhysicalDisplayToken(J)Landroid/os/IBinder; +Landroid/content/res/Resources;->getInteger(I)I +Landroid/os/Handler;->sendMessageAtTime(Landroid/os/Message;J)Z +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->init(JJ)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->readSummaryFromParcel(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg;-><init>(Lcom/android/internal/os/BatteryStatsImpl;)V +Landroid/util/ArraySet;->freeArrays([I[Ljava/lang/Object;I)V +Landroid/util/ArrayMap;->entrySet()Ljava/util/Set; +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidClusterTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V +Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony; +Landroid/telephony/TelephonyManager;->requestModemActivityInfo(Landroid/os/ResultReceiver;)V +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getMaxDurationMsLocked(J)J +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->endSample()V +Lcom/android/internal/os/BatteryStatsImpl;->updateKernelMemoryBandwidthLocked()V +Landroid/content/pm/ComponentInfo;-><init>()V +Landroid/content/pm/ComponentInfo;-><init>(Landroid/content/pm/ComponentInfo;)V +Landroid/content/pm/ComponentInfo;-><init>(Landroid/os/Parcel;)V +Landroid/view/SurfaceControl;->getDisplayConfigs(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo; +Lcom/android/internal/os/AtomicFile;->finishWrite(Ljava/io/FileOutputStream;)V +Landroid/app/ResourcesManager;->createResourcesImpl(Landroid/content/res/ResourcesKey;)Landroid/content/res/ResourcesImpl; +Landroid/app/ContextImpl;->updateDisplay(I)V +Landroid/hardware/display/DisplayManagerGlobal;->getInstance()Landroid/hardware/display/DisplayManagerGlobal; +Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/content/res/Resources;)Landroid/view/Display; +Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/view/DisplayAdjustments;)Landroid/view/Display; +Landroid/os/Parcel;->readStrongBinder()Landroid/os/IBinder; +Landroid/app/ContextImpl;->setTheme(I)V +Landroid/content/IntentFilter;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V +Landroid/text/TextUtils;->getLayoutDirectionFromLocale(Ljava/util/Locale;)I +Landroid/os/Handler;-><init>()V +Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;)V +Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;Z)V +Landroid/os/Handler;-><init>(Landroid/os/Looper;)V +Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;)V +Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V +Landroid/os/Handler;-><init>(Z)V +Landroid/os/Binder;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface; +Landroid/content/pm/PackageParser;->isApkFile(Ljava/io/File;)Z +Landroid/util/SparseIntArray;->put(II)V +Landroid/content/pm/ApplicationInfo;->initForUser(I)V +Landroid/os/BinderProxy;->getInstance(JJ)Landroid/os/BinderProxy; +Landroid/content/pm/IntentFilterVerificationInfo;->getStringFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Landroid/os/PowerManager; +Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Ljava/lang/Object; +Landroid/util/ArrayMap;->containsKey(Ljava/lang/Object;)Z +Landroid/app/WindowConfiguration;->setToDefaults()V +Lcom/android/internal/util/MemInfoReader;->readMemInfo()V +Landroid/util/LongSparseArray;->get(J)Ljava/lang/Object; +Landroid/util/LongSparseArray;->get(JLjava/lang/Object;)Ljava/lang/Object; +Landroid/util/Spline;->createSpline([F[F)Landroid/util/Spline; +Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I +Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/content/res/Resources;)V +Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;)V +Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;Landroid/content/res/Resources;)V +Landroid/net/Uri;->withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri; +Landroid/content/res/TypedArray;->obtain(Landroid/content/res/Resources;I)Landroid/content/res/TypedArray; +Landroid/provider/Settings$System;->getUriFor(Ljava/lang/String;)Landroid/net/Uri; +Landroid/util/MapCollections$ArrayIterator;->next()Ljava/lang/Object; +Landroid/view/DisplayAdjustments;-><init>()V +Landroid/view/DisplayAdjustments;-><init>(Landroid/content/res/Configuration;)V +Landroid/view/DisplayAdjustments;-><init>(Landroid/view/DisplayAdjustments;)V +Landroid/hardware/display/DisplayManager;->getOrCreateDisplayLocked(IZ)Landroid/view/Display; +Landroid/content/res/Resources;->getIntArray(I)[I +Landroid/content/res/StringBlock;->get(I)Ljava/lang/CharSequence; +Landroid/content/res/XmlBlock$Parser;->getText()Ljava/lang/String; +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;-><init>(Lcom/android/internal/os/BatteryStatsImpl;Lcom/android/internal/os/BatteryStatsImpl$Uid;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->readSyncSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V +Landroid/hardware/display/DisplayManagerGlobal;->getDisplayInfo(I)Landroid/view/DisplayInfo; +Landroid/os/FileUtils;->readTextFile(Ljava/io/File;ILjava/lang/String;)Ljava/lang/String; +Lcom/android/internal/app/procstats/ProcessStats;->buildTimePeriodStartClockStr()V +Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;J)Ljava/lang/CharSequence; +Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Calendar;)Ljava/lang/CharSequence; +Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Date;)Ljava/lang/CharSequence; +Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager; +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->getRealtime(J)J +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->writeSummaryToParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;)V +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2600(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V +Landroid/os/Parcel;->unmarshall([BII)V +Landroid/content/pm/PackageParser$Package;->fixupOwner(Ljava/util/List;)V +Landroid/content/res/Resources;->getBoolean(I)Z +Landroid/content/res/AssetManager;->getResourceText(I)Ljava/lang/CharSequence; +Landroid/content/res/AssetManager;->getResourceTextArray(I)[Ljava/lang/CharSequence; +Landroid/content/res/Resources;->getText(I)Ljava/lang/CharSequence; +HPLandroid/content/res/Resources;->getText(ILjava/lang/CharSequence;)Ljava/lang/CharSequence; +Landroid/content/res/Resources;->getTextArray(I)[Ljava/lang/CharSequence; +Landroid/os/MessageQueue;->next()Landroid/os/Message; +Landroid/os/Parcel;->marshall()[B +Lcom/android/internal/logging/EventLogTags;->writeCommitSysConfigFile(Ljava/lang/String;J)V +Landroid/os/ThreadLocalWorkSource;->restore(J)V +Landroid/os/Looper;->prepare()V +Landroid/os/Looper;->prepareMainLooper()V +Lcom/android/internal/app/procstats/ProcessStats;->splitAndParseNumbers(Ljava/lang/String;)[I +Landroid/os/Trace;->traceEnd(J)V +Landroid/os/Parcel;->readExceptionCode()I +Landroid/os/Parcel;->readException()V +Landroid/os/Parcel;->readException(ILjava/lang/String;)V +Lcom/android/internal/util/StatLogger;->logDurationStat(IJ)J +Landroid/content/res/ResourcesImpl$ThemeImpl;->applyStyle(IZ)V +Landroid/content/res/Resources$Theme;->applyStyle(IZ)V +Landroid/content/res/AssetManager;->applyStyleToTheme(JIZ)V +Landroid/os/Trace;->isTagEnabled(J)Z +Lcom/android/internal/util/ArrayUtils;->containsAll([Ljava/lang/Object;[Ljava/lang/Object;)Z +Landroid/os/Trace;->traceBegin(JLjava/lang/String;)V +Landroid/hardware/display/DisplayManager;-><init>(Landroid/content/Context;)V +Landroid/os/Bundle;-><init>()V +Landroid/os/Bundle;-><init>(I)V +Landroid/os/Bundle;-><init>(Landroid/os/Bundle;)V +Landroid/os/Bundle;-><init>(Landroid/os/PersistableBundle;)V +Landroid/content/pm/PackageBackwardCompatibility;->updatePackage(Landroid/content/pm/PackageParser$Package;)V +Landroid/content/pm/PackageBackwardCompatibility;->modifySharedLibraries(Landroid/content/pm/PackageParser$Package;)V +Landroid/content/pm/Signature;->areExactMatch([Landroid/content/pm/Signature;[Landroid/content/pm/Signature;)Z +Lcom/android/internal/util/ArrayUtils;->contains(Ljava/util/Collection;Ljava/lang/Object;)Z +Lcom/android/internal/util/ArrayUtils;->contains([II)Z +Lcom/android/internal/util/ArrayUtils;->contains([Ljava/lang/Object;Ljava/lang/Object;)Z +Lcom/android/internal/util/ConcurrentUtils$1;->newThread(Ljava/lang/Runnable;)Ljava/lang/Thread; +Landroid/os/PowerManager;-><init>(Landroid/content/Context;Landroid/os/IPowerManager;Landroid/os/Handler;)V +Landroid/content/res/AssetManager;->getResourceArray(I[I)I +Landroid/content/res/AssetManager;->getResourceArraySize(I)I +Landroid/app/WindowConfiguration;-><init>()V +Landroid/view/SurfaceControl;->getPhysicalDisplayIds()[J +Lcom/android/internal/os/BackgroundThread;->getHandler()Landroid/os/Handler; +Landroid/net/Uri$StringUri;->buildUpon()Landroid/net/Uri$Builder; +Lcom/android/internal/os/AtomicFile;->readFully()[B +Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I +Landroid/content/res/ResourcesImpl;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser; +Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser; +Landroid/content/res/Resources;->getXml(I)Landroid/content/res/XmlResourceParser; +Landroid/content/res/XmlBlock$Parser;->next()I +Landroid/content/res/XmlBlock$Parser;->nextTag()I +Landroid/content/res/XmlBlock$Parser;->nextText()Ljava/lang/String; +Lcom/google/android/collect/Sets;->newArraySet()Landroid/util/ArraySet; +Lcom/google/android/collect/Sets;->newArraySet([Ljava/lang/Object;)Landroid/util/ArraySet; +Landroid/util/ArraySet;->contains(Ljava/lang/Object;)Z +Lcom/android/internal/os/BatteryStatsImpl$Uid;->getSensorTimerLocked(IZ)Lcom/android/internal/os/BatteryStatsImpl$DualTimer; +Landroid/content/pm/PackageParser$SigningDetails;->hasCertificate(Landroid/content/pm/Signature;)Z +Landroid/content/pm/PackageParser$SigningDetails;->hasCertificateInternal(Landroid/content/pm/Signature;I)Z +Landroid/content/res/XmlBlock$Parser;->getAttributeValue(I)Ljava/lang/String; +Landroid/content/res/XmlBlock$Parser;->getAttributeValue(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V +Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V +Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([[Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V +Landroid/util/Spline$MonotoneCubicSpline;-><init>([F[F)V +Landroid/content/res/Configuration;->setTo(Landroid/content/res/Configuration;)V +Landroid/content/res/Configuration;->setToDefaults()V +Lcom/android/server/SystemConfig;->readSplitPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/io/File;)V +Lcom/android/internal/os/RpmStats;->getSubsystem(Ljava/lang/String;)Lcom/android/internal/os/RpmStats$PowerStateSubsystem; +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->computeRealtime(JI)J +Landroid/os/Parcel;->dataPosition()I +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getCurrentDurationMsLocked(J)J +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->checkPrecondition(Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;)Z +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeRunTimeLocked(J)J +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeCurrentCountLocked()I +Lcom/android/internal/os/KernelMemoryBandwidthStats;->parseStats(Ljava/io/BufferedReader;)V +Landroid/util/MapCollections;->getEntrySet()Ljava/util/Set; +Landroid/util/MapCollections$EntrySet;->iterator()Ljava/util/Iterator; +Lcom/android/internal/os/BatteryStatsImpl$Uid;->writeJobCompletionsToParcelLocked(Landroid/os/Parcel;)V +Landroid/os/Parcel;->readBundle()Landroid/os/Bundle; +Landroid/os/Parcel;->readBundle(Ljava/lang/ClassLoader;)Landroid/os/Bundle; +Landroid/content/res/Resources;->getString(I)Ljava/lang/String; +Landroid/content/res/Resources;->getString(I[Ljava/lang/Object;)Ljava/lang/String; +Landroid/content/res/Resources;->getStringArray(I)[Ljava/lang/String; +Landroid/os/ThreadLocalWorkSource;->setUid(I)J +Landroid/content/pm/PackageParser;->parseClusterPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parseClusterPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite; +Landroid/content/pm/split/DefaultSplitAssetLoader;->getBaseAssetManager()Landroid/content/res/AssetManager; +Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/io/File;Landroid/content/res/AssetManager;I)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parseBaseApkCommon(Landroid/content/pm/PackageParser$Package;Ljava/util/Set;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->cacheResult(Ljava/io/File;ILandroid/content/pm/PackageParser$Package;)V +Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->parseMonolithicPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite; +Landroid/content/pm/PackageParser;->parseApkLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$ApkLite; +Landroid/content/pm/PackageParser;->parseApkLite(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;Landroid/content/pm/PackageParser$SigningDetails;)Landroid/content/pm/PackageParser$ApkLite; +Landroid/content/pm/PackageParser;->parseApkLiteInner(Ljava/io/File;Ljava/io/FileDescriptor;Ljava/lang/String;I)Landroid/content/pm/PackageParser$ApkLite; +Landroid/content/pm/PackageParser;->toCacheEntry(Landroid/content/pm/PackageParser$Package;)[B +Landroid/content/pm/PackageParser;->parseBaseApplication(Landroid/content/pm/PackageParser$Package;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Z +Landroid/os/Parcel;->writeParcelable(Landroid/os/Parcelable;I)V +Landroid/os/Parcel;->writeParcelableArray([Landroid/os/Parcelable;I)V +Landroid/os/Parcel;->writeParcelableCreator(Landroid/os/Parcelable;)V +Landroid/os/Parcel;->writeParcelableList(Ljava/util/List;I)V +Landroid/content/pm/PackageParser$Package;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/content/res/Resources;->obtainAttributes(Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray; +Landroid/content/res/Resources;->obtainAttributes(Landroid/content/res/Resources;Landroid/content/res/Resources$Theme;Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray; +Landroid/content/pm/split/DefaultSplitAssetLoader;->close()V +Landroid/content/res/AssetManager;->openXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser; +Landroid/content/res/AssetManager;->close()V +Landroid/content/res/AssetManager;->openXmlBlockAsset(ILjava/lang/String;)Landroid/content/res/XmlBlock; +Landroid/content/pm/PackageParser;->generateAppDetailsHiddenActivity(Landroid/content/pm/PackageParser$Package;I[Ljava/lang/String;Z)Landroid/content/pm/PackageParser$Activity; +Landroid/content/pm/split/DefaultSplitAssetLoader;->loadApkAssets(Ljava/lang/String;I)Landroid/content/res/ApkAssets; +Landroid/content/pm/PackageParser$Activity;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/os/FileUtils;->trimFilename(Ljava/lang/StringBuilder;I)V +Landroid/content/res/ApkAssets;->openXml(Ljava/lang/String;)Landroid/content/res/XmlResourceParser; +Landroid/content/res/Configuration;->setLocales(Landroid/os/LocaleList;)V +Landroid/content/pm/PackageParser;->buildTaskAffinityName(Ljava/lang/String;Ljava/lang/String;Ljava/lang/CharSequence;[Ljava/lang/String;)Ljava/lang/String; +Landroid/content/res/AssetManager;->retrieveAttributes(Landroid/content/res/XmlBlock$Parser;[I[I[I)Z +Landroid/content/pm/PackageParser;->buildCompoundName(Ljava/lang/String;Ljava/lang/CharSequence;Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String; +Landroid/content/pm/ActivityInfo;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/content/res/XmlBlock$Parser;->close()V +Landroid/content/pm/PackageParser;->validateName(Ljava/lang/String;ZZ)Ljava/lang/String; +Landroid/util/ArraySet;->equals(Ljava/lang/Object;)Z +Landroid/content/pm/PackageItemInfo;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->finishAndUninstall()V +Landroid/content/res/TypedArray;->loadStringValueAt(I)Ljava/lang/CharSequence; +Landroid/content/pm/ApplicationInfo;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/os/FileUtils;->isValidExtFilename(Ljava/lang/String;)Z +Landroid/content/res/AssetManager;->findCookieForPath(Ljava/lang/String;)I +Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String; +Landroid/content/res/TypedArray;->peekValue(I)Landroid/util/TypedValue; +Landroid/app/ActivityThread;->attach(ZJ)V +Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z +Landroid/content/res/XmlBlock$Parser;->getAttributeName(I)Ljava/lang/String; +Landroid/content/res/XmlBlock$Parser;->getAttributeNameResource(I)I +Landroid/content/pm/PackageParser$ApkLite;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZIIIILjava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZZZZZZII)V +Landroid/app/ResourcesManager;->createAssetManager(Landroid/content/res/ResourcesKey;)Landroid/content/res/AssetManager; +Landroid/content/res/AssetManager$Builder;->build()Landroid/content/res/AssetManager; +Landroid/os/FileUtils;->deleteContents(Ljava/io/File;)Z +Landroid/os/FileUtils;->deleteContentsAndDir(Ljava/io/File;)Z +Landroid/content/res/ResourcesImpl;->adjustLanguageTag(Ljava/lang/String;)Ljava/lang/String; +Landroid/sysprop/DisplayProperties;->tryParseBoolean(Ljava/lang/String;)Ljava/lang/Boolean; +Landroid/content/pm/PackageParserCacheHelper$WriteHelper;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageParser$Package;->getLongVersionCode()J +Lcom/android/internal/util/function/pooled/OmniFunction;->run()V +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Landroid/os/SystemProperties;->get(Ljava/lang/String;)Ljava/lang/String; +Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Landroid/os/SystemProperties;->getInt(Ljava/lang/String;I)I +Landroid/os/SystemProperties;->getLong(Ljava/lang/String;J)J +Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V +Landroid/content/res/TypedArray;->recycle()V +Landroid/content/res/Configuration;->fixUpLocaleList()V +Landroid/content/res/XmlBlock;->newParser(I)Landroid/content/res/XmlResourceParser; +Landroid/content/pm/ComponentInfo;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/content/res/ApkAssets;->getAssetPath()Ljava/lang/String; +Landroid/util/MapCollections$MapIterator;->next()Ljava/lang/Object; +Landroid/content/res/ResourcesImpl;->flushLayoutCache()V +Landroid/os/FileUtils;->buildValidExtFilename(Ljava/lang/String;)Ljava/lang/String; +Landroid/content/res/ApkAssets;->getStringFromPool(I)Ljava/lang/CharSequence; +Landroid/content/pm/Signature;->equals(Ljava/lang/Object;)Z +Landroid/content/pm/PackageUserState;->equals(Ljava/lang/Object;)Z +Landroid/util/ArrayMap$1;->colGetEntry(II)Ljava/lang/Object; +Lcom/android/internal/os/BackgroundThread;->ensureThreadLocked()V +Landroid/app/ActivityThread;-><init>()V +Landroid/app/ActivityThread;->getSystemContext()Landroid/app/ContextImpl; +Landroid/app/ContextImpl;->createSystemContext(Landroid/app/ActivityThread;)Landroid/app/ContextImpl; +Landroid/app/ContextImpl;-><init>(Landroid/app/ContextImpl;Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;Landroid/os/IBinder;Landroid/os/UserHandle;ILjava/lang/ClassLoader;Ljava/lang/String;)V +Landroid/app/ResourcesManager;->getDisplayMetrics()Landroid/util/DisplayMetrics; +Landroid/app/ResourcesManager;->getDisplayMetrics(ILandroid/view/DisplayAdjustments;)Landroid/util/DisplayMetrics; +Landroid/content/pm/PackageParser$Package;->setApplicationVolumeUuid(Ljava/lang/String;)V +Landroid/content/pm/AndroidHidlUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V +Landroid/content/res/ApkAssets;->close()V +Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(IZ)Z +Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(Ljava/lang/String;Ljava/lang/String;Z)Z +Landroid/content/pm/PackageParser;->setMaxAspectRatio(Landroid/content/pm/PackageParser$Package;)V +Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V +Landroid/os/Parcel;->writeTypedList(Ljava/util/List;)V +Landroid/os/Parcel;->writeTypedList(Ljava/util/List;I)V +Landroid/content/res/Configuration;->getLocales()Landroid/os/LocaleList; +Landroid/view/DisplayEventReceiver;-><init>(Landroid/os/Looper;I)V +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doInvoke()Ljava/lang/Object; +Landroid/content/pm/PackageSharedLibraryUpdater;->prefixImplicitDependency(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;Ljava/lang/String;)V +Landroid/util/MapCollections$MapIterator;->getKey()Ljava/lang/Object; +Landroid/util/MapCollections$ValuesCollection;->iterator()Ljava/util/Iterator; +Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->elapsedRealtime()J +Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application; +Landroid/content/pm/IntentFilterVerificationInfo;->getIntFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I +Landroid/content/res/ResourcesImpl;->calcConfigChanges(Landroid/content/res/Configuration;)I +Landroid/content/pm/PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V +Landroid/util/SparseArray;->valueAt(I)Ljava/lang/Object; +Landroid/util/ArraySet;->ensureCapacity(I)V +Landroid/os/storage/StorageManager;->convert(Ljava/lang/String;)Ljava/util/UUID; +Landroid/os/storage/StorageManager;->convert(Ljava/util/UUID;)Ljava/lang/String; +Landroid/content/pm/PackageParser;->checkOverlayRequiredSystemProperty(Ljava/lang/String;Ljava/lang/String;)Z +Landroid/content/res/ThemedResourceCache;->prune(I)Z +Landroid/content/res/ThemedResourceCache;->pruneEntriesLocked(Landroid/util/LongSparseArray;I)Z +Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object; +Landroid/content/res/XmlBlock$Parser;->getAttributeCount()I +Landroid/content/pm/PackageParser;->parseMetaData(Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;Landroid/os/Bundle;[Ljava/lang/String;)Landroid/os/Bundle; +Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics; +Landroid/text/TextUtils;->writeToParcel(Ljava/lang/CharSequence;Landroid/os/Parcel;I)V +Landroid/view/DisplayAdjustments;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V +Landroid/content/res/CompatibilityInfo;->applyToDisplayMetrics(Landroid/util/DisplayMetrics;)V +Landroid/content/res/TypedArray;->getString(I)Ljava/lang/String; +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->getUpdateVersion()I +Landroid/os/ResultReceiver;->send(ILandroid/os/Bundle;)V +Lcom/android/internal/os/ProcessCpuTracker;->getCpuTimeForPid(I)J +Landroid/os/FileUtils;->contains(Ljava/io/File;Ljava/io/File;)Z +Landroid/os/FileUtils;->contains(Ljava/lang/String;Ljava/lang/String;)Z +Landroid/content/pm/PackageParser$SigningDetails;->checkCapability(Landroid/content/pm/PackageParser$SigningDetails;I)Z +Landroid/util/MapCollections$MapIterator;->getValue()Ljava/lang/Object; +Landroid/os/BinderProxy$ProxyMap;->get(J)Landroid/os/BinderProxy; +Landroid/util/TimingsTraceLog;-><init>(Ljava/lang/String;J)V +Landroid/os/PowerManager;->newWakeLock(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock; +Landroid/content/ComponentName;->hashCode()I +Landroid/util/MapCollections$ArrayIterator;->hasNext()Z +Landroid/app/IActivityTaskManager$Stub;-><init>()V +Lcom/android/internal/os/ProcessCpuTracker;-><init>(Z)V +Lcom/android/internal/util/RingBuffer;-><init>(Ljava/lang/Class;I)V +Lcom/android/server/LocalServices;->getService(Ljava/lang/Class;)Ljava/lang/Object; +Lcom/android/internal/util/XmlUtils;->readStringAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/os/BatteryStatsImpl;->setPowerProfileLocked(Lcom/android/internal/os/PowerProfile;)V +Lcom/android/internal/os/BatteryStatsImpl;->readDailyStatsLocked()V +Lcom/android/internal/widget/LockPatternUtils;-><init>(Landroid/content/Context;)V +Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/Editable; +Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/SpannableStringBuilder; +Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;II)Landroid/text/SpannableStringBuilder; +Landroid/content/res/Resources;->newTheme()Landroid/content/res/Resources$Theme; +Landroid/os/Parcel;->obtain()Landroid/os/Parcel; +Landroid/os/Parcel;->obtain(J)Landroid/os/Parcel; +Landroid/content/res/Configuration;->updateFrom(Landroid/content/res/Configuration;)I +Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;)Landroid/app/ContextImpl; +Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;)Landroid/app/ContextImpl; +Landroid/util/SparseArray;->clear()V +Landroid/util/ArrayMap;->remove(Ljava/lang/Object;)Ljava/lang/Object; +Landroid/util/ArrayMap;->removeAt(I)Ljava/lang/Object; +Landroid/os/Parcel;->writeBundle(Landroid/os/Bundle;)V +Landroid/content/pm/PackageParser;->hasDomainURLs(Landroid/content/pm/PackageParser$Package;)Z +Landroid/util/Pools$SynchronizedPool;->release(Ljava/lang/Object;)Z +Landroid/os/Parcel;->setDataPosition(I)V +Landroid/os/LocaleList;->getDefault()Landroid/os/LocaleList; +Landroid/content/res/ConfigurationBoundResourceCache;->onConfigurationChange(I)V +Landroid/util/DisplayMetrics;->setToDefaults()V +Landroid/content/pm/PackageParser;->computeMinSdkVersion(ILjava/lang/String;I[Ljava/lang/String;[Ljava/lang/String;)I +Lcom/android/internal/os/ProcessCpuTracker;->onMeasureProcessName(Ljava/lang/String;)I +Lcom/android/server/SystemConfig$SharedLibraryEntry;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V +Landroid/util/MapCollections;->getKeySet()Ljava/util/Set; +Landroid/content/ComponentName;->unflattenFromString(Ljava/lang/String;)Landroid/content/ComponentName; +Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;)I +Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I +Landroid/os/SynchronousResultReceiver;->awaitResult(J)Landroid/os/SynchronousResultReceiver$Result; +Landroid/os/SynchronousResultReceiver;->onReceiveResult(ILandroid/os/Bundle;)V +Landroid/view/SurfaceControl;->getHdrCapabilities(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doRecycle()V +Landroid/os/Handler;->postAtFrontOfQueue(Ljava/lang/Runnable;)Z diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-greylist-max-p.txt index 25d45b0e6570..351e71dd9538 100644 --- a/config/hiddenapi-greylist-max-p.txt +++ b/config/hiddenapi-greylist-max-p.txt @@ -1,57 +1,14 @@ Landroid/app/IInstrumentationWatcher$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IInstrumentationWatcher; Landroid/app/ISearchManager$Stub;-><init>()V Landroid/app/IUiModeManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IUiModeManager; -Landroid/app/IUiModeManager;->disableCarMode(I)V Landroid/bluetooth/IBluetooth$Stub;-><init>()V Landroid/bluetooth/IBluetoothA2dp$Stub;-><init>()V Landroid/content/IIntentReceiver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentReceiver; Landroid/content/IIntentSender$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentSender; -Landroid/net/IConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo; -Landroid/net/IConnectivityManager;->reportInetCondition(II)V -Landroid/os/BatteryStats$Counter;-><init>()V -Landroid/os/BatteryStats$HistoryItem;->clear()V -Landroid/os/BatteryStats$HistoryItem;->next:Landroid/os/BatteryStats$HistoryItem; -Landroid/os/BatteryStats$HistoryItem;->same(Landroid/os/BatteryStats$HistoryItem;)Z -Landroid/os/BatteryStats$HistoryItem;->setTo(JBLandroid/os/BatteryStats$HistoryItem;)V -Landroid/os/BatteryStats$HistoryItem;->setTo(Landroid/os/BatteryStats$HistoryItem;)V -Landroid/os/BatteryStats$Timer;-><init>()V -Landroid/os/BatteryStats$Uid$Pkg;-><init>()V -Landroid/os/BatteryStats$Uid$Proc;-><init>()V -Landroid/os/BatteryStats$Uid$Sensor;-><init>()V -Landroid/os/BatteryStats$Uid$Wakelock;-><init>()V -Landroid/os/BatteryStats;-><init>()V -Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J -Landroid/os/BatteryStats;->getNetworkActivityBytes(II)J -Landroid/os/CancellationSignal;->mCancelInProgress:Z -Landroid/os/CancellationSignal;->mIsCanceled:Z -Landroid/os/CancellationSignal;->mOnCancelListener:Landroid/os/CancellationSignal$OnCancelListener; -Landroid/os/CancellationSignal;->mRemote:Landroid/os/ICancellationSignal; -Landroid/os/CancellationSignal;->waitForCancelFinishedLocked()V -Landroid/os/IPowerManager;->nap(J)V -Landroid/os/Parcel;->mCreators:Ljava/util/HashMap; -Landroid/os/PowerManager;->mHandler:Landroid/os/Handler; -Landroid/os/Process;->sendSignalQuiet(II)V -Landroid/os/Registrant;->getHandler()Landroid/os/Handler; -Landroid/os/RegistrantList;->get(I)Ljava/lang/Object; -Landroid/os/RemoteCallback;->mHandler:Landroid/os/Handler; Landroid/os/storage/IObbActionListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IObbActionListener; -Landroid/os/SystemProperties;->native_add_change_callback()V -Landroid/os/SystemProperties;->native_get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -Landroid/os/SystemProperties;->native_get_boolean(Ljava/lang/String;Z)Z -Landroid/os/SystemProperties;->native_get_int(Ljava/lang/String;I)I -Landroid/os/SystemProperties;->native_set(Ljava/lang/String;Ljava/lang/String;)V -Landroid/os/UserHandle;->formatUid(Ljava/io/PrintWriter;I)V -Landroid/os/WorkSource;->sGoneWork:Landroid/os/WorkSource; -Landroid/os/WorkSource;->sNewbWork:Landroid/os/WorkSource; -Landroid/os/WorkSource;->sTmpWorkSource:Landroid/os/WorkSource; -Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V -Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V -Landroid/telephony/CarrierMessagingServiceManager;-><init>()V Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats; -Landroid/view/IWindowManager;->setInTouchMode(Z)V -Landroid/view/IWindowManager;->showStrictModeViolation(Z)V Lcom/android/internal/R$styleable;->AndroidManifestActivityAlias:[I Lcom/android/internal/R$styleable;->AndroidManifestGrantUriPermission:[I Lcom/android/internal/R$styleable;->AndroidManifestInstrumentation:[I @@ -70,10 +27,3 @@ Lcom/android/internal/R$styleable;->MenuView:[I Lcom/android/internal/R$styleable;->Searchable:[I Lcom/android/internal/R$styleable;->SearchableActionKey:[I Lcom/android/internal/telephony/IPhoneSubInfo$Stub;-><init>()V -Lcom/android/internal/telephony/ITelephony;->getDataActivity()I -Lcom/android/internal/telephony/ITelephony;->getDataState()I -Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallForwardingChanged(Z)V -Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCellLocation(Landroid/os/Bundle;)V -Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataActivity(I)V -Lcom/android/internal/telephony/ITelephonyRegistry;->notifyOtaspChanged(II)V -Lcom/android/internal/view/BaseIWindow;-><init>()V diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index c30a6f491807..eb53b7c20dbc 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -121,8 +121,6 @@ Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap; Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V -Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V -Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard; Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -194,7 +192,6 @@ Landroid/content/res/DrawableCache;-><init>()V Landroid/content/UndoManager;-><init>()V Landroid/database/IContentObserver$Stub;-><init>()V Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/database/IContentObserver; -Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager; @@ -723,9 +720,6 @@ Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lco Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider; -Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V -Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V -Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager; Lcom/android/internal/logging/MetricsLogger;-><init>()V @@ -736,7 +730,6 @@ Lcom/android/internal/os/BatterySipper$DrainType;->values()[Lcom/android/interna Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService; Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService; Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback; -Lcom/android/internal/preference/YesNoPreference;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V Lcom/android/internal/R$anim;->fade_in:I Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I Lcom/android/internal/R$array;->config_autoBrightnessLevels:I diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index f655c8993456..61e2ae96f7bd 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1547,7 +1547,9 @@ public class Activity extends ContextThemeWrapper * had previously been frozen by {@link #onSaveInstanceState}. * * <p>This method is called between {@link #onStart} and - * {@link #onPostCreate}. + * {@link #onPostCreate}. This method is called only when recreating + * an activity; the method isn't invoked if {@link #onStart} is called for + * any other reason.</p> * * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}. * diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 69e71185f228..1fd7e52314e3 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -127,17 +127,6 @@ public abstract class ActivityManagerInternal { public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi); /** - * Sets if the given pid is currently running a remote animation, which is taken a signal for - * determining oom adjustment and scheduling behavior. - * - * @param pid The pid we are setting overlay UI for. - * @param runningRemoteAnimation True if the process is running a remote animation, false - * otherwise. - * @see RemoteAnimationAdapter - */ - public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation); - - /** * Called after the network policy rules are updated by * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and * {@param procStateSeq}. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2b4d4f8bc6eb..50f945b095cb 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -80,6 +80,7 @@ import android.graphics.Canvas; import android.graphics.HardwareRenderer; import android.graphics.ImageDecoder; import android.hardware.display.DisplayManagerGlobal; +import android.inputmethodservice.InputMethodService; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.Proxy; @@ -455,6 +456,8 @@ public final class ActivityThread extends ClientTransactionHandler { Bundle mCoreSettings = null; + boolean mHasImeComponent = false; + /** Activity client record, used for bookkeeping for the real {@link Activity} instance. */ public static final class ActivityClientRecord { @UnsupportedAppUsage @@ -5360,7 +5363,11 @@ public final class ActivityThread extends ClientTransactionHandler { } final int NSVC = mServices.size(); for (int i=0; i<NSVC; i++) { - callbacks.add(mServices.valueAt(i)); + final ComponentCallbacks2 serviceComp = mServices.valueAt(i); + if (serviceComp instanceof InputMethodService) { + mHasImeComponent = true; + } + callbacks.add(serviceComp); } } synchronized (mProviderMap) { @@ -5600,6 +5607,10 @@ public final class ActivityThread extends ClientTransactionHandler { } if (config == null) { + // TODO (b/135719017): Temporary log for debugging IME service. + if (Build.IS_DEBUGGABLE && mHasImeComponent) { + Log.w(TAG, "handleConfigurationChanged for IME app but config is null"); + } return; } @@ -5621,6 +5632,12 @@ public final class ActivityThread extends ClientTransactionHandler { mConfiguration = new Configuration(); } if (!mConfiguration.isOtherSeqNewer(config) && compat == null) { + // TODO (b/135719017): Temporary log for debugging IME service. + if (Build.IS_DEBUGGABLE && mHasImeComponent) { + Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete " + + ", config=" + config + + ", mConfiguration=" + mConfiguration); + } return; } @@ -5652,6 +5669,13 @@ public final class ActivityThread extends ClientTransactionHandler { config); } else if (!equivalent) { performConfigurationChanged(cb, config); + } else { + // TODO (b/135719017): Temporary log for debugging IME service. + if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) { + Log.w(TAG, "performConfigurationChanged didn't callback to IME " + + ", configDiff=" + configDiff + + ", mConfiguration=" + mConfiguration); + } } } } @@ -7142,6 +7166,12 @@ public final class ActivityThread extends ClientTransactionHandler { ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> { synchronized (mResourcesManager) { + // TODO (b/135719017): Temporary log for debugging IME service. + if (Build.IS_DEBUGGABLE && mHasImeComponent) { + Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, " + + "config=" + globalConfig); + } + // We need to apply this change to the resources immediately, because upon returning // the view hierarchy will be informed about it. if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig, diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 415ec64dc126..e8918285777b 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -120,8 +120,10 @@ public class ActivityView extends ViewGroup { mActivityTaskManager = ActivityTaskManager.getService(); mSurfaceView = new SurfaceView(context); + // Since ActivityView#getAlpha has been overridden, we should use parent class's alpha + // as master to synchronize surface view's alpha value. + mSurfaceView.setAlpha(super.getAlpha()); mSurfaceView.setUseAlpha(); - mSurfaceView.setAlpha(0f); mSurfaceCallback = new SurfaceCallback(); mSurfaceView.getHolder().addCallback(mSurfaceCallback); addView(mSurfaceView); @@ -348,9 +350,20 @@ public class ActivityView extends ViewGroup { mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */); } + /** + * Sets the alpha value when the content of {@link SurfaceView} needs to show or hide. + * <p>Note: The surface view may ignore the alpha value in some cases. Refer to + * {@link SurfaceView#setAlpha} for more details. + * + * @param alpha The opacity of the view. + */ @Override public void setAlpha(float alpha) { - mSurfaceView.setAlpha(alpha); + super.setAlpha(alpha); + + if (mSurfaceView != null) { + mSurfaceView.setAlpha(alpha); + } } @Override diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 1166cb57cca7..80c9ba2a9c48 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -132,6 +132,9 @@ public class DownloadManager { */ public final static String COLUMN_STATUS = Downloads.Impl.COLUMN_STATUS; + /** {@hide} */ + public final static String COLUMN_FILE_NAME_HINT = Downloads.Impl.COLUMN_FILE_NAME_HINT; + /** * Provides more detail on the status of the download. Its meaning depends on the value of * {@link #COLUMN_STATUS}. @@ -169,6 +172,9 @@ public class DownloadManager { */ public static final String COLUMN_MEDIAPROVIDER_URI = Downloads.Impl.COLUMN_MEDIAPROVIDER_URI; + /** {@hide} */ + public static final String COLUMN_DESTINATION = Downloads.Impl.COLUMN_DESTINATION; + /** @hide */ @TestApi public static final String COLUMN_MEDIASTORE_URI = Downloads.Impl.COLUMN_MEDIASTORE_URI; @@ -340,26 +346,22 @@ public class DownloadManager { */ @UnsupportedAppUsage public static final String[] UNDERLYING_COLUMNS = new String[] { - Downloads.Impl._ID, - Downloads.Impl._DATA + " AS " + COLUMN_LOCAL_FILENAME, - Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, - Downloads.Impl.COLUMN_DESTINATION, - Downloads.Impl.COLUMN_TITLE, - Downloads.Impl.COLUMN_DESCRIPTION, - Downloads.Impl.COLUMN_URI, - Downloads.Impl.COLUMN_STATUS, - Downloads.Impl.COLUMN_FILE_NAME_HINT, - Downloads.Impl.COLUMN_MIME_TYPE + " AS " + COLUMN_MEDIA_TYPE, - Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + COLUMN_TOTAL_SIZE_BYTES, - Downloads.Impl.COLUMN_LAST_MODIFICATION + " AS " + COLUMN_LAST_MODIFIED_TIMESTAMP, - Downloads.Impl.COLUMN_CURRENT_BYTES + " AS " + COLUMN_BYTES_DOWNLOADED_SO_FAR, - Downloads.Impl.COLUMN_ALLOW_WRITE, - /* add the following 'computed' columns to the cursor. - * they are not 'returned' by the database, but their inclusion - * eliminates need to have lot of methods in CursorTranslator - */ - "'placeholder' AS " + COLUMN_LOCAL_URI, - "'placeholder' AS " + COLUMN_REASON + DownloadManager.COLUMN_ID, + DownloadManager.COLUMN_LOCAL_FILENAME, + DownloadManager.COLUMN_MEDIAPROVIDER_URI, + DownloadManager.COLUMN_DESTINATION, + DownloadManager.COLUMN_TITLE, + DownloadManager.COLUMN_DESCRIPTION, + DownloadManager.COLUMN_URI, + DownloadManager.COLUMN_STATUS, + DownloadManager.COLUMN_FILE_NAME_HINT, + DownloadManager.COLUMN_MEDIA_TYPE, + DownloadManager.COLUMN_TOTAL_SIZE_BYTES, + DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP, + DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR, + DownloadManager.COLUMN_ALLOW_WRITE, + DownloadManager.COLUMN_LOCAL_URI, + DownloadManager.COLUMN_REASON }; /** diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index 650147b45bd2..61867ea737e7 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -185,4 +185,9 @@ oneway interface ITaskStackListener { * @param newDisplayId id of the new display. */ void onTaskDisplayChanged(int taskId, int newDisplayId); + + /** + * Called when any additions or deletions to the recent tasks list have been made. + */ + void onRecentTaskListUpdated(); } diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl index cae54b6c0611..f2c9f615c03f 100644 --- a/core/java/android/app/IUiModeManager.aidl +++ b/core/java/android/app/IUiModeManager.aidl @@ -30,6 +30,7 @@ interface IUiModeManager { /** * Disables the car mode. */ + @UnsupportedAppUsage(maxTargetSdk = 28) void disableCarMode(int flags); /** diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index b63feb590ad1..e3a0e11c3c68 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -182,4 +182,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { @Override public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException { } + + @Override + public void onRecentTaskListUpdated() throws RemoteException { + } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 5624ba54077a..49cfd41f1773 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4981,6 +4981,42 @@ public class DevicePolicyManager { return null; } + + /** + * Called by a device or profile owner, or delegated certificate chooser (an app that has been + * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to grant an application access + * to an already-installed (or generated) KeyChain key. + * This is useful (in combination with {@link #installKeyPair} or {@link #generateKeyPair}) to + * let an application call {@link android.security.KeyChain#getPrivateKey} without having to + * call {@link android.security.KeyChain#choosePrivateKeyAlias} first. + * + * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED} + * broadcast when access to a key is granted or revoked. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param alias The alias of the key to grant access to. + * @param packageName The name of the (already installed) package to grant access to. + * @param hasGrant Whether to grant access to the alias or revoke it. + * @return {@code true} if the grant was set successfully, {@code false} otherwise. + * + * @throws SecurityException if the caller is not a device owner, a profile owner or + * delegated certificate chooser. + * @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if + * {@code packageName} is not a name of an installed package. + */ + public boolean setKeyGrantForApp(@Nullable ComponentName admin, @NonNull String alias, + @NonNull String packageName, boolean hasGrant) { + throwIfParentInstance("addKeyGrant"); + try { + return mService.setKeyGrantForApp( + admin, mContext.getPackageName(), alias, packageName, hasGrant); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return false; + } + /** * Returns {@code true} if the device supports attestation of device identifiers in addition * to key attestation. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 2b9641999019..5cdef6d39dc6 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -436,4 +436,6 @@ interface IDevicePolicyManager { boolean isUnattendedManagedKiosk(); boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags); + + boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant); } diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl index 5f73e551d57c..c9dc019bd2f2 100644 --- a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl +++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl @@ -18,6 +18,8 @@ package android.companion; /** @hide */ interface ICompanionDeviceDiscoveryServiceCallback { + @UnsupportedAppUsage oneway void onDeviceSelected(String packageName, int userId, String deviceAddress); + @UnsupportedAppUsage oneway void onDeviceSelectionCancel(); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7a013f176691..73bc908632b2 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3197,6 +3197,7 @@ public abstract class Context { TELEPHONY_SERVICE, TELEPHONY_SUBSCRIPTION_SERVICE, CARRIER_CONFIG_SERVICE, + EUICC_SERVICE, TELECOM_SERVICE, CLIPBOARD_SERVICE, INPUT_METHOD_SERVICE, @@ -3387,6 +3388,8 @@ public abstract class Context { * @see android.telephony.SubscriptionManager * @see #CARRIER_CONFIG_SERVICE * @see android.telephony.CarrierConfigManager + * @see #EUICC_SERVICE + * @see android.telephony.euicc.EuiccManager * @see #INPUT_METHOD_SERVICE * @see android.view.inputmethod.InputMethodManager * @see #UI_MODE_SERVICE diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl index 22dc9fed59c4..623556695341 100644 --- a/core/java/android/database/IContentObserver.aidl +++ b/core/java/android/database/IContentObserver.aidl @@ -29,5 +29,6 @@ interface IContentObserver * observed. selfUpdate is true if the update was caused by a call to * commit on the cursor that is being observed. */ + @UnsupportedAppUsage oneway void onChange(boolean selfUpdate, in Uri uri, int userId); } diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 5ac13d8a067d..a0170dab9f04 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -206,10 +206,16 @@ public abstract class CameraMetadata<TKey> { continue; } - if (filterTags == null || Arrays.binarySearch(filterTags, - CameraMetadataNative.getTag(keyName, vendorId)) >= 0) { + + if (filterTags != null && Arrays.binarySearch(filterTags, + CameraMetadataNative.getTag(keyName, vendorId)) < 0) { + // ignore vendor keys not in filterTags + continue; + } + if (instance == null || instance.getProtected(k) != null) { keyList.add(k); } + } } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index cc8c182b867e..68857da940d5 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -2337,6 +2337,12 @@ public class CameraDeviceImpl extends CameraDevice final CaptureCallbackHolder holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId); + if (holder == null) { + Log.e(TAG, String.format("Receive capture error on unknown request ID %d", + requestId)); + return; + } + final CaptureRequest request = holder.getRequest(subsequenceId); Runnable failureDispatch = null; diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java index c135c8a73abc..76304bda05a1 100644 --- a/core/java/android/hardware/radio/RadioMetadata.java +++ b/core/java/android/hardware/radio/RadioMetadata.java @@ -26,6 +26,9 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Set; /** @@ -257,9 +260,22 @@ public final class RadioMetadata implements Parcelable { private final Bundle mBundle; + // Lazily computed hash code based upon the contents of mBundle. + private Integer mHashCode; + @Override public int hashCode() { - return mBundle.hashCode(); + if (mHashCode == null) { + List<String> keys = new ArrayList<String>(mBundle.keySet()); + keys.sort(null); + Object[] objs = new Object[2 * keys.size()]; + for (int i = 0; i < keys.size(); i++) { + objs[2 * i] = keys.get(i); + objs[2 * i + 1] = mBundle.get(keys.get(i)); + } + mHashCode = Arrays.hashCode(objs); + } + return mHashCode; } @Override @@ -626,6 +642,8 @@ public final class RadioMetadata implements Parcelable { String key = getKeyFromNativeKey(nativeKey); try { putInt(mBundle, key, value); + // Invalidate mHashCode to force it to be recomputed. + mHashCode = null; return 0; } catch (IllegalArgumentException ex) { return -1; @@ -639,6 +657,8 @@ public final class RadioMetadata implements Parcelable { return -1; } mBundle.putString(key, value); + // Invalidate mHashCode to force it to be recomputed. + mHashCode = null; return 0; } @@ -653,6 +673,8 @@ public final class RadioMetadata implements Parcelable { bmp = BitmapFactory.decodeByteArray(value, 0, value.length); if (bmp != null) { mBundle.putParcelable(key, bmp); + // Invalidate mHashCode to force it to be recomputed. + mHashCode = null; return 0; } } catch (Exception e) { @@ -668,6 +690,8 @@ public final class RadioMetadata implements Parcelable { } mBundle.putParcelable(key, new RadioMetadata.Clock( utcEpochSeconds, timezoneOffsetInMinutes)); + // Invalidate mHashCode to force it to be recomputed. + mHashCode = null; return 0; } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 61648dc7f1d8..5f662f914919 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -52,6 +52,7 @@ interface IConnectivityManager @UnsupportedAppUsage NetworkInfo getActiveNetworkInfo(); NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked); + @UnsupportedAppUsage(maxTargetSdk = 28) NetworkInfo getNetworkInfo(int networkType); NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked); @UnsupportedAppUsage @@ -112,6 +113,7 @@ interface IConnectivityManager int setUsbTethering(boolean enable, String callerPkg); + @UnsupportedAppUsage(maxTargetSdk = 28) void reportInetCondition(int networkType, int percentage); void reportNetworkConnectivity(in Network network, boolean hasConnectivity); diff --git a/core/java/android/net/LinkQualityInfo.java b/core/java/android/net/LinkQualityInfo.java index 3c5d474706fb..2e6915ff4aa5 100644 --- a/core/java/android/net/LinkQualityInfo.java +++ b/core/java/android/net/LinkQualityInfo.java @@ -24,8 +24,8 @@ import android.os.Parcelable; * Class that represents useful attributes of generic network links * such as the upload/download throughput or packet error rate. * Generally speaking, you should be dealing with instances of - * LinkQualityInfo subclasses, such as {@link android.net.#WifiLinkQualityInfo} - * or {@link android.net.#MobileLinkQualityInfo} which provide additional + * LinkQualityInfo subclasses, such as {@link android.net.WifiLinkQualityInfo} + * or {@link android.net.MobileLinkQualityInfo} which provide additional * information. * @hide */ diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index caa6a43e521c..a399e8362874 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -64,6 +64,10 @@ import java.util.Map; * @hide */ public abstract class BatteryStats implements Parcelable { + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public BatteryStats() {} + private static final String TAG = "BatteryStats"; private static final boolean LOCAL_LOGV = false; @@ -407,6 +411,9 @@ public abstract class BatteryStats implements Parcelable { */ public static abstract class Counter { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public Counter() {} + /** * Returns the count associated with this Counter for the * selected type of statistics. @@ -516,6 +523,9 @@ public abstract class BatteryStats implements Parcelable { */ public static abstract class Timer { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public Timer() {} + /** * Returns the count associated with this Timer for the * selected type of statistics. @@ -671,6 +681,9 @@ public abstract class BatteryStats implements Parcelable { * The statistics associated with a particular wake lock. */ public static abstract class Wakelock { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public Wakelock() {} + @UnsupportedAppUsage public abstract Timer getWakeTime(int type); } @@ -948,6 +961,10 @@ public abstract class BatteryStats implements Parcelable { public abstract void getDeferredJobsLineLocked(StringBuilder sb, int which); public static abstract class Sensor { + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public Sensor() {} + /* * FIXME: it's not correct to use this magic value because it * could clash with a sensor handle (which are defined by @@ -978,6 +995,9 @@ public abstract class BatteryStats implements Parcelable { */ public static abstract class Proc { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public Proc() {} + public static class ExcessivePower { public static final int TYPE_WAKE = 1; public static final int TYPE_CPU = 2; @@ -1053,6 +1073,9 @@ public abstract class BatteryStats implements Parcelable { */ public static abstract class Pkg { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public Pkg() {} + /** * Returns information about all wakeup alarms that have been triggered for this * package. The mapping keys are tag names for the alarms, the counter contains @@ -1558,6 +1581,7 @@ public abstract class BatteryStats implements Parcelable { * Battery history record. */ public static final class HistoryItem { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public HistoryItem next; // The time of this event in milliseconds, as per SystemClock.elapsedRealtime(). @@ -1875,6 +1899,7 @@ public abstract class BatteryStats implements Parcelable { numReadInts += (src.dataPosition()-start)/4; } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public void clear() { time = 0; cmd = CMD_NULL; @@ -1895,12 +1920,14 @@ public abstract class BatteryStats implements Parcelable { eventTag = null; } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public void setTo(HistoryItem o) { time = o.time; cmd = o.cmd; setToCommon(o); } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public void setTo(long time, byte cmd, HistoryItem o) { this.time = time; this.cmd = cmd; @@ -1956,6 +1983,7 @@ public abstract class BatteryStats implements Parcelable { && currentTime == o.currentTime; } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public boolean same(HistoryItem o) { if (!sameNonEvent(o) || eventCode != o.eventCode) { return false; @@ -2338,6 +2366,7 @@ public abstract class BatteryStats implements Parcelable { * * {@hide} */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public abstract long getMobileRadioActiveTime(long elapsedRealtimeUs, int which); /** @@ -2698,6 +2727,7 @@ public abstract class BatteryStats implements Parcelable { public static final int NETWORK_WIFI_BG_TX_DATA = 9; public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_WIFI_BG_TX_DATA + 1; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public abstract long getNetworkActivityBytes(int type, int which); public abstract long getNetworkActivityPackets(int type, int which); diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index 3cdebac413f9..c5cbad33c06c 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -235,22 +235,5 @@ public final class BugreportManager { Binder.restoreCallingIdentity(identity); } } - - // Old methods; should go away - @Override - public void onProgressUpdated(int progress) throws RemoteException { - // TODO(b/111441001): remove from interface - } - - @Override - public void onMaxProgressUpdated(int maxProgress) throws RemoteException { - // TODO(b/111441001): remove from interface - } - - @Override - public void onSectionComplete(String title, int status, int size, int durationMs) - throws RemoteException { - // TODO(b/111441001): remove from interface - } } } diff --git a/core/java/android/os/CancellationSignal.java b/core/java/android/os/CancellationSignal.java index e8053d5d275d..99fb9982e706 100644 --- a/core/java/android/os/CancellationSignal.java +++ b/core/java/android/os/CancellationSignal.java @@ -18,13 +18,19 @@ package android.os; import android.os.ICancellationSignal; +import dalvik.annotation.compat.UnsupportedAppUsage; + /** * Provides the ability to cancel an operation in progress. */ public final class CancellationSignal { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private boolean mIsCanceled; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private OnCancelListener mOnCancelListener; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private ICancellationSignal mRemote; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private boolean mCancelInProgress; /** @@ -152,6 +158,7 @@ public final class CancellationSignal { } } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private void waitForCancelFinishedLocked() { while (mCancelInProgress) { try { diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index e1d605e1c99d..185693e8e6e0 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -47,6 +47,7 @@ interface IPowerManager void wakeUp(long time, int reason, String details, String opPackageName); @UnsupportedAppUsage void goToSleep(long time, int reason, int flags); + @UnsupportedAppUsage(maxTargetSdk = 28) void nap(long time); @UnsupportedAppUsage boolean isInteractive(); diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index dbe3c93738b8..e1b55422274a 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -3148,6 +3148,7 @@ public final class Parcel { // Cache of previously looked up CREATOR.createFromParcel() methods for // particular classes. Keys are the names of the classes, values are // Method objects. + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static final HashMap<ClassLoader,HashMap<String,Parcelable.Creator<?>>> mCreators = new HashMap<>(); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 535d887de9ae..7ea26210dc0c 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -824,6 +824,7 @@ public final class PowerManager { final Context mContext; @UnsupportedAppUsage final IPowerManager mService; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) final Handler mHandler; IThermalService mThermalService; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index b535e8d0601c..30e59590022c 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -999,6 +999,7 @@ public class Process { * your own log, or the Android Illuminati will find you some night and * beat you up. */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public static final native void sendSignalQuiet(int pid, int signal); /** @hide */ diff --git a/core/java/android/os/Registrant.java b/core/java/android/os/Registrant.java index 8fb123aa3da4..572b975fbafd 100644 --- a/core/java/android/os/Registrant.java +++ b/core/java/android/os/Registrant.java @@ -114,6 +114,7 @@ public class Registrant } } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public Handler getHandler() { diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java index 6e562ffc88ea..e9bc6371f043 100644 --- a/core/java/android/os/RegistrantList.java +++ b/core/java/android/os/RegistrantList.java @@ -70,6 +70,7 @@ public class RegistrantList return registrants.size(); } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public synchronized Object get(int index) { diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java index 047ba1d20056..da58d0fac160 100644 --- a/core/java/android/os/RemoteCallback.java +++ b/core/java/android/os/RemoteCallback.java @@ -21,6 +21,8 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; +import dalvik.annotation.compat.UnsupportedAppUsage; + /** * @hide */ @@ -33,6 +35,7 @@ public final class RemoteCallback implements Parcelable { } private final OnResultListener mListener; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private final Handler mHandler; private final IRemoteCallback mCallback; diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index b377e8dbe14f..6165146ece0a 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -123,6 +123,7 @@ public class RemoteCallbackList<E extends IInterface> { IBinder binder = callback.asBinder(); try { Callback cb = new Callback(callback, cookie); + unregister(callback); binder.linkToDeath(cb, 0); mCallbacks.put(binder, cb); return true; diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java index a7edb5eb9d8b..cdae72ebd313 100644 --- a/core/java/android/os/SystemProperties.java +++ b/core/java/android/os/SystemProperties.java @@ -88,12 +88,17 @@ public class SystemProperties { @UnsupportedAppUsage private static native String native_get(String key); + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static native String native_get(String key, String def); + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static native int native_get_int(String key, int def); @UnsupportedAppUsage private static native long native_get_long(String key, long def); + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static native boolean native_get_boolean(String key, boolean def); + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static native void native_set(String key, String def); + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static native void native_add_change_callback(); private static native void native_report_sysprop_change(); diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index d70ba9921bfd..4e17f7e92013 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -354,6 +354,7 @@ public final class UserHandle implements Parcelable { * components -- user, app, isolated, etc. * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public static void formatUid(PrintWriter pw, int uid) { if (uid < Process.FIRST_APPLICATION_UID) { pw.print(uid); diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java index 1f6c3cc76ddd..2e3b000f2b39 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/core/java/android/os/UserManagerInternal.java @@ -221,4 +221,7 @@ public abstract class UserManagerInternal { */ public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value, int callingUid); + + /** @return a specific user restriction that's in effect currently. */ + public abstract boolean hasUserRestriction(String restriction, int userId); } diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java index 0b4a56121038..114de2378a1f 100644 --- a/core/java/android/os/WorkSource.java +++ b/core/java/android/os/WorkSource.java @@ -39,14 +39,17 @@ public class WorkSource implements Parcelable { * The WorkSource object itself is not thread safe, but we need to * hold sTmpWorkSource lock while working with these statics. */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) static final WorkSource sTmpWorkSource = new WorkSource(0); /** * For returning newbie work from a modification operation. */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) static WorkSource sNewbWork; /** * For returning gone work form a modification operation. */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) static WorkSource sGoneWork; /** @@ -619,6 +622,7 @@ public class WorkSource implements Parcelable { return changed; } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) { if (mNames == null && other.mNames == null) { return updateUidsLocked(other, set, returnNewbs); diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 69c1295df4f9..5b9205d16898 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1987,11 +1987,31 @@ public class StorageManager { */ public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2; + /** + * Flag indicating that a disk space check should not take into account + * freeable cached space when determining allocatable space. + * + * Intended for use with {@link #getAllocatableBytes()}. + * @hide + */ + public static final int FLAG_ALLOCATE_NON_CACHE_ONLY = 1 << 3; + + /** + * Flag indicating that a disk space check should only return freeable + * cached space when determining allocatable space. + * + * Intended for use with {@link #getAllocatableBytes()}. + * @hide + */ + public static final int FLAG_ALLOCATE_CACHE_ONLY = 1 << 4; + /** @hide */ @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = { FLAG_ALLOCATE_AGGRESSIVE, FLAG_ALLOCATE_DEFY_ALL_RESERVED, FLAG_ALLOCATE_DEFY_HALF_RESERVED, + FLAG_ALLOCATE_NON_CACHE_ONLY, + FLAG_ALLOCATE_CACHE_ONLY, }) @Retention(RetentionPolicy.SOURCE) public @interface AllocateFlags {} diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index d0401e38e927..4f7c8c5d87e2 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -346,6 +346,20 @@ public final class DeviceConfig { "system_gestures_excluded_by_pre_q_sticky_immersive"; /** + * The minimum duration between gesture exclusion logging for a given window in + * milliseconds. + * + * Events that happen in-between will be silently dropped. + * + * A non-positive value disables logging. + * + * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER + * @hide + */ + String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS = + "system_gesture_exclusion_log_debounce_millis"; + + /** * Key for controlling which packages are explicitly blocked from running at refresh rates * higher than 90hz. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5308cd3a0926..7df1ebe15d44 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5959,6 +5959,18 @@ public final class Settings { public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED; /** + * Indicates whether a DPC has been downloaded during provisioning. + * + * <p>Type: int (0 for false, 1 for true) + * + * <p>If this is true, then any attempts to begin setup again should result in factory reset + * + * @hide + */ + public static final String MANAGED_PROVISIONING_DPC_DOWNLOADED = + "managed_provisioning_dpc_downloaded"; + + /** * Indicates whether the current user has completed setup via the setup wizard. * <p> * Type: int (0 for false, 1 for true) diff --git a/core/java/android/service/carrier/ICarrierMessagingService.aidl b/core/java/android/service/carrier/ICarrierMessagingService.aidl index 2d96c3da6487..c4dfb57bb6a0 100644 --- a/core/java/android/service/carrier/ICarrierMessagingService.aidl +++ b/core/java/android/service/carrier/ICarrierMessagingService.aidl @@ -36,6 +36,7 @@ oneway interface ICarrierMessagingService { * @param subId SMS subscription ID of the SIM * @param callback the callback to notify upon completion */ + @UnsupportedAppUsage(maxTargetSdk = 28) void filterSms( in MessagePdu pdu, String format, int destPort, int subId, in ICarrierMessagingCallback callback); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 60dbf84d555c..e784ad3e3188 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -196,7 +196,6 @@ public abstract class WallpaperService extends Service { final WindowManager.LayoutParams mLayout = new WindowManager.LayoutParams(); IWindowSession mSession; - InputChannel mInputChannel; final Object mLock = new Object(); boolean mOffsetMessageEnqueued; @@ -819,11 +818,11 @@ public abstract class WallpaperService extends Service { mLayout.setTitle(WallpaperService.this.getClass().getName()); mLayout.windowAnimations = com.android.internal.R.style.Animation_Wallpaper; - mInputChannel = new InputChannel(); + InputChannel inputChannel = new InputChannel(); if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE, mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets, - mOutsets, mDisplayCutout, mInputChannel, + mOutsets, mDisplayCutout, inputChannel, mInsetsState) < 0) { Log.w(TAG, "Failed to add window while updating wallpaper surface."); return; @@ -831,7 +830,7 @@ public abstract class WallpaperService extends Service { mCreated = true; mInputEventReceiver = new WallpaperInputEventReceiver( - mInputChannel, Looper.myLooper()); + inputChannel, Looper.myLooper()); } mSurfaceHolder.mSurfaceLock.lock(); @@ -1267,13 +1266,6 @@ public abstract class WallpaperService extends Service { } mSurfaceHolder.mSurface.release(); mCreated = false; - - // Dispose the input channel after removing the window so the Window Manager - // doesn't interpret the input channel being closed as an abnormal termination. - if (mInputChannel != null) { - mInputChannel.dispose(); - mInputChannel = null; - } } } diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java index f04e7cbc9e8f..3cbf727d7718 100644 --- a/core/java/android/util/LruCache.java +++ b/core/java/android/util/LruCache.java @@ -17,6 +17,7 @@ package android.util; import android.annotation.UnsupportedAppUsage; + import java.util.LinkedHashMap; import java.util.Map; @@ -260,7 +261,7 @@ public class LruCache<K, V> { * @param evicted true if the entry is being removed to make space, false * if the removal was caused by a {@link #put} or {@link #remove}. * @param newValue the new value for {@code key}, if it exists. If non-null, - * this removal was caused by a {@link #put}. Otherwise it was caused by + * this removal was caused by a {@link #put} or a {@link #get}. Otherwise it was caused by * an eviction or a {@link #remove}. */ protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java index dcdef3eaa275..ea66656bfc45 100644 --- a/core/java/android/view/FrameMetrics.java +++ b/core/java/android/view/FrameMetrics.java @@ -220,7 +220,7 @@ public final class FrameMetrics { int SWAP_BUFFERS = 12; int FRAME_COMPLETED = 13; - int FRAME_STATS_COUNT = 16; // must always be last + int FRAME_STATS_COUNT = 17; // must always be last } /* diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl index a032625547d2..9c2f9a6a192c 100644 --- a/core/java/android/view/ISystemGestureExclusionListener.aidl +++ b/core/java/android/view/ISystemGestureExclusionListener.aidl @@ -28,7 +28,14 @@ oneway interface ISystemGestureExclusionListener { * Called when the system gesture exclusion for the given display changed. * @param displayId the display whose system gesture exclusion changed * @param systemGestureExclusion a {@code Region} where the app would like priority over the - * system gestures, in display coordinates. + * system gestures, in display coordinates. Certain restrictions + * might be applied such that apps don't get all the exclusions + * they request. + * @param systemGestureExclusionUnrestricted a {@code Region} where the app would like priority + * over the system gestures, in display coordinates, without + * any restrictions applied. Null if no restrictions have been + * applied. */ - void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion); + void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion, + in Region systemGestureExclusionUnrestricted); }
\ No newline at end of file diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index b347a78a8780..bb9867a298c3 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -151,6 +151,7 @@ interface IWindowManager float getCurrentAnimatorScale(); // For testing + @UnsupportedAppUsage(maxTargetSdk = 28) void setInTouchMode(boolean showFocus); // For StrictMode flashing a red border on violations from the UI @@ -158,6 +159,7 @@ interface IWindowManager // Manager uses that to determine whether or not the red border should // actually be shown. (it will be ignored that pid doesn't have windows // on screen) + @UnsupportedAppUsage(maxTargetSdk = 28) void showStrictModeViolation(boolean on); // Proxy to set the system property for whether the flashing diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 7260a658a027..ed8492e482c7 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -102,7 +102,11 @@ public abstract class InputEventReceiver { nativeDispose(mReceiverPtr); mReceiverPtr = 0; } - mInputChannel = null; + + if (mInputChannel != null) { + mInputChannel.dispose(); + mInputChannel = null; + } mMessageQueue = null; } diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index bc2fe545a8ac..c686440171a2 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -55,6 +55,7 @@ public class RemoteAnimationAdapter implements Parcelable { /** @see #getCallingPid */ private int mCallingPid; + private int mCallingUid; /** * @param runner The interface that gets notified when we actually need to start the animation. @@ -103,10 +104,11 @@ public class RemoteAnimationAdapter implements Parcelable { } /** - * To be called by system_server to keep track which pid is running this animation. + * To be called by system_server to keep track which pid and uid is running this animation. */ - public void setCallingPid(int pid) { + public void setCallingPidUid(int pid, int uid) { mCallingPid = pid; + mCallingUid = uid; } /** @@ -116,6 +118,13 @@ public class RemoteAnimationAdapter implements Parcelable { return mCallingPid; } + /** + * @return The uid of the process running the animation. + */ + public int getCallingUid() { + return mCallingUid; + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index 884cae440bed..da599efb6eee 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -118,9 +118,9 @@ public class RemoteAnimationDefinition implements Parcelable { * To be called by system_server to keep track which pid is running the remote animations inside * this definition. */ - public void setCallingPid(int pid) { + public void setCallingPidUid(int pid, int uid) { for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) { - mTransitionAnimationMap.valueAt(i).adapter.setCallingPid(pid); + mTransitionAnimationMap.valueAt(i).adapter.setCallingPidUid(pid, uid); } } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 1a6689838545..90e69f3abc6c 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -38,6 +38,7 @@ import android.os.Looper; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; +import android.view.SurfaceControl.Transaction; import com.android.internal.view.SurfaceCallbackHelper; @@ -118,7 +119,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall boolean mDrawFinished = false; final Rect mScreenRect = new Rect(); - SurfaceSession mSurfaceSession; + private final SurfaceSession mSurfaceSession = new SurfaceSession(); SurfaceControl mSurfaceControl; // In the case of format changes we switch out the surface in-place @@ -193,6 +194,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction(); private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction(); + private int mParentSurfaceGenerationId; public SurfaceView(Context context) { this(context, null); @@ -644,13 +646,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } - private void updateBackgroundVisibilityInTransaction(SurfaceControl viewRoot) { + private void updateBackgroundVisibilityInTransaction() { if (mBackgroundControl == null) { return; } if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) { mBackgroundControl.show(); - mBackgroundControl.setRelativeLayer(viewRoot, Integer.MIN_VALUE); } else { mBackgroundControl.hide(); } @@ -742,11 +743,24 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); if (creating) { - viewRoot.createBoundsSurface(mSubLayer); - mSurfaceSession = new SurfaceSession(); mDeferredDestroySurfaceControl = mSurfaceControl; updateOpaqueFlag(); + // SurfaceView hierarchy + // ViewRootImpl surface + // - bounds layer (crops all child surfaces to parent surface insets) + // - SurfaceView surface (drawn relative to ViewRootImpl surface) + // - Background color layer (drawn behind all SurfaceView surfaces) + // + // The bounds layer is used to crop the surface view so it does not draw into + // the parent surface inset region. Since there can be multiple surface views + // below or above the parent surface, one option is to create multiple bounds + // layer for each z order. The other option, the one implement is to create + // a single bounds layer and set z order for each child surface relative to the + // parent surface. + // When creating the surface view, we parent it to the bounds layer and then + // set the relative z order. When the parent surface changes, we have to + // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback. final String name = "SurfaceView - " + viewRoot.getTitle().toString(); mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) @@ -754,7 +768,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) - .setParent(viewRoot.getSurfaceControl()) + .setParent(viewRoot.getBoundsLayer()) .setFlags(mSurfaceFlags) .build(); mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) @@ -779,14 +793,23 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall SurfaceControl.openTransaction(); try { - mSurfaceControl.setLayer(mSubLayer); + // If we are creating the surface control or the parent surface has not + // changed, then set relative z. Otherwise allow the parent + // SurfaceChangedCallback to update the relative z. This is needed so that + // we do not change the relative z before the server is ready to swap the + // parent surface. + if (creating || (mParentSurfaceGenerationId + == viewRoot.mSurface.getGenerationId())) { + SurfaceControl.mergeToGlobalTransaction(updateRelativeZ()); + } + mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId(); if (mViewVisibility) { mSurfaceControl.show(); } else { mSurfaceControl.hide(); } - updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl()); + updateBackgroundVisibilityInTransaction(); if (mUseAlpha) { mSurfaceControl.setAlpha(alpha); mSurfaceAlpha = alpha; @@ -1369,11 +1392,22 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } /** - * Called when a valid ViewRootImpl surface is replaced by another valid surface. + * Called when a valid ViewRootImpl surface is replaced by another valid surface. In this + * case update relative z to the new parent surface. * @hide */ @Override - public void surfaceReplaced(SurfaceControl.Transaction t) { + public void surfaceReplaced(Transaction t) { + if (mSurfaceControl != null && mBackgroundControl != null) { + t.merge(updateRelativeZ()); + } + } + private Transaction updateRelativeZ() { + Transaction t = new Transaction(); + SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl(); + t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE); + t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer); + return t; } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e1984894a85a..1779a80b5d09 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -11074,6 +11074,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * <p>Do not modify the provided list after this method is called.</p> * + * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the + * exclusions it takes into account. The limit does not apply while the navigation + * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the + * {@link android.inputmethodservice.InputMethodService input method} and + * {@link Intent#CATEGORY_HOME home activity}. + * </p> + * * @param rects A list of precision gesture regions that this view needs to function correctly */ public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 354cc9645635..3a51eaa5d7d1 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -399,7 +399,6 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage final View.AttachInfo mAttachInfo; - InputChannel mInputChannel; InputQueue.Callback mInputQueueCallback; InputQueue mInputQueue; @UnsupportedAppUsage @@ -484,15 +483,13 @@ public final class ViewRootImpl implements ViewParent, */ private final Transaction mSurfaceChangedTransaction = new Transaction(); /** - * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds - * are set to the parent's bounds adjusted for surface insets. This surface is created when - * {@link ViewRootImpl#createBoundsSurface(int)} is called. - * By parenting to this bounds surface, child surfaces can ensure they do not draw into the - * surface inset regions set by the parent window. + * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to + * the surface insets. This surface is created only if a client requests it via {@link + * #getBoundsLayer()}. By parenting to this bounds surface, child surfaces can ensure they do + * not draw into the surface inset region set by the parent window. */ - public final Surface mBoundsSurface = new Surface(); - private SurfaceSession mSurfaceSession; - private SurfaceControl mBoundsSurfaceControl; + private SurfaceControl mBoundsLayer; + private final SurfaceSession mSurfaceSession = new SurfaceSession(); private final Transaction mTransaction = new Transaction(); @UnsupportedAppUsage @@ -884,9 +881,10 @@ public final class ViewRootImpl implements ViewParent, // manager, to make sure we do the relayout before receiving // any other events from the system. requestLayout(); + InputChannel inputChannel = null; if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { - mInputChannel = new InputChannel(); + inputChannel = new InputChannel(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; @@ -897,14 +895,14 @@ public final class ViewRootImpl implements ViewParent, res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, - mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, + mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, inputChannel, mTempInsets); setFrame(mTmpFrame); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; - mInputChannel = null; + inputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocus(null, null); @@ -980,12 +978,12 @@ public final class ViewRootImpl implements ViewParent, mInputQueueCallback = ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); } - if (mInputChannel != null) { + if (inputChannel != null) { if (mInputQueueCallback != null) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); } - mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, + mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper()); } @@ -1614,66 +1612,55 @@ public final class ViewRootImpl implements ViewParent, } } - /** - * Creates a surface as a child of {@code mSurface} with the same bounds as its parent and - * crop bounds set to the parent's bounds adjusted for surface insets. + * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the + * surface insets. If the layer does not exist, it is created. * - * @param zOrderLayer Z order relative to the parent surface. + * <p>Parenting to this layer will ensure that its children are cropped by the view's surface + * insets. */ - public void createBoundsSurface(int zOrderLayer) { - if (mSurfaceSession == null) { - mSurfaceSession = new SurfaceSession(); - } - if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) { - return; // surface control for bounds surface already exists. + public SurfaceControl getBoundsLayer() { + if (mBoundsLayer == null) { + mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession) + .setContainerLayer() + .setName("Bounds for - " + getTitle().toString()) + .setParent(mSurfaceControl) + .build(); + setBoundsLayerCrop(); + mTransaction.show(mBoundsLayer).apply(); } - - mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) - .setName("Bounds for - " + getTitle().toString()) - .setParent(mSurfaceControl) - .build(); - - setBoundsSurfaceCrop(); - mTransaction.setLayer(mBoundsSurfaceControl, zOrderLayer) - .show(mBoundsSurfaceControl) - .apply(); - mBoundsSurface.copyFrom(mBoundsSurfaceControl); + return mBoundsLayer; } - private void setBoundsSurfaceCrop() { + private void setBoundsLayerCrop() { // mWinFrame is already adjusted for surface insets. So offset it and use it as // the cropping bounds. mTempBoundsRect.set(mWinFrame); mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left, mWindowAttributes.surfaceInsets.top); - mTransaction.setWindowCrop(mBoundsSurfaceControl, mTempBoundsRect); + mTransaction.setWindowCrop(mBoundsLayer, mTempBoundsRect); } /** - * Called after window layout to update the bounds surface. If the surface insets have - * changed or the surface has resized, update the bounds surface. + * Called after window layout to update the bounds surface. If the surface insets have changed + * or the surface has resized, update the bounds surface. */ - private void updateBoundsSurface() { - if (mBoundsSurfaceControl != null && mSurface.isValid()) { - setBoundsSurfaceCrop(); - mTransaction.deferTransactionUntilSurface(mBoundsSurfaceControl, + private void updateBoundsLayer() { + if (mBoundsLayer != null) { + setBoundsLayerCrop(); + mTransaction.deferTransactionUntilSurface(mBoundsLayer, mSurface, mSurface.getNextFrameNumber()) .apply(); } } private void destroySurface() { + if (mBoundsLayer != null) { + mBoundsLayer.release(); + mBoundsLayer = null; + } mSurface.release(); mSurfaceControl.release(); - - mSurfaceSession = null; - - if (mBoundsSurfaceControl != null) { - mTransaction.remove(mBoundsSurfaceControl).apply(); - mBoundsSurface.release(); - mBoundsSurfaceControl = null; - } } /** @@ -2649,8 +2636,8 @@ public final class ViewRootImpl implements ViewParent, maybeHandleWindowMove(frame); } - if (surfaceSizeChanged) { - updateBoundsSurface(); + if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) { + updateBoundsLayer(); } final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); @@ -4388,13 +4375,6 @@ public final class ViewRootImpl implements ViewParent, } catch (RemoteException e) { } - // Dispose the input channel after removing the window so the Window Manager - // doesn't interpret the input channel being closed as an abnormal termination. - if (mInputChannel != null) { - mInputChannel.dispose(); - mInputChannel = null; - } - mDisplayManager.unregisterDisplayListener(mDisplayListener); unscheduleTraversals(); diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index 9340b71a5280..bcc6a552f569 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -35,6 +35,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; +import android.content.Intent; import android.graphics.Insets; import android.graphics.Rect; import android.util.SparseArray; @@ -644,6 +645,14 @@ public final class WindowInsets { * {@link View#setSystemGestureExclusionRects} outside of the * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}. * + * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the + * exclusions it takes into account. The limit does not apply while the navigation + * bar is {@link View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the + * {@link android.inputmethodservice.InputMethodService input method} and + * {@link Intent#CATEGORY_HOME home activity}. + * </p> + * + * * <p>Simple taps are guaranteed to reach the window even within the system gesture insets, * as long as they are outside the {@link #getTappableElementInsets() system window insets}. * diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index e1a9898b6292..a26243c7cad5 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -480,7 +480,7 @@ public class EditorInfo implements InputType, Parcelable { * matter what user ID the calling process has. * * <p>Note: This field will be silently ignored when - * {@link android.view.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED} is + * {@link com.android.server.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED} is * {@code true}.</p> * * <p>Note also that pseudo handles such as {@link UserHandle#ALL} are not supported.</p> diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java index 80c728f662c6..12ed4b971e83 100644 --- a/core/java/android/view/textclassifier/SelectionEvent.java +++ b/core/java/android/view/textclassifier/SelectionEvent.java @@ -410,6 +410,15 @@ public final class SelectionEvent implements Parcelable { } /** + * Sets the id of this event's user. + * <p> + * Package-private for SystemTextClassifier's use. + */ + void setUserId(@UserIdInt int userId) { + mUserId = userId; + } + + /** * Returns the id of this event's user. * @hide */ diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java index b5f972aea1d4..a97c3305208a 100644 --- a/core/java/android/view/textclassifier/SystemTextClassifier.java +++ b/core/java/android/view/textclassifier/SystemTextClassifier.java @@ -151,6 +151,7 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { + event.setUserId(mUserId); mManagerService.onSelectionEvent(mSessionId, event); } catch (RemoteException e) { Log.e(LOG_TAG, "Error reporting selection event.", e); @@ -163,6 +164,12 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { + final TextClassificationContext tcContext = event.getEventContext() == null + ? new TextClassificationContext.Builder(mPackageName, WIDGET_TYPE_UNKNOWN) + .build() + : event.getEventContext(); + tcContext.setUserId(mUserId); + event.setEventContext(tcContext); mManagerService.onTextClassifierEvent(mSessionId, event); } catch (RemoteException e) { Log.e(LOG_TAG, "Error reporting textclassifier event.", e); diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java index 57da829b3f44..a041296f97db 100644 --- a/core/java/android/view/textclassifier/TextClassifierEvent.java +++ b/core/java/android/view/textclassifier/TextClassifierEvent.java @@ -139,7 +139,7 @@ public abstract class TextClassifierEvent implements Parcelable { @Nullable private final String[] mEntityTypes; @Nullable - private final TextClassificationContext mEventContext; + private TextClassificationContext mEventContext; @Nullable private final String mResultId; private final int mEventIndex; @@ -289,6 +289,15 @@ public abstract class TextClassifierEvent implements Parcelable { } /** + * Sets the event context. + * <p> + * Package-private for SystemTextClassifier's use. + */ + void setEventContext(@Nullable TextClassificationContext eventContext) { + mEventContext = eventContext; + } + + /** * Returns the id of the text classifier result related to this event. */ @Nullable diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index a46580dcc539..18d4d691f726 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -464,7 +464,9 @@ public abstract class WebSettings { * Note that the feature will continue to be supported on older versions of * Android as before. * - * This function does not have any effect. + * @deprecated In Android O and afterwards, this function does not have + * any effect, the form data will be saved to platform's autofill service + * if applicable. */ @Deprecated public abstract void setSaveFormData(boolean save); diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index 5091eea1898d..ad3563316854 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -42,6 +42,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.LinearInterpolator; import android.widget.RemoteViews.RemoteView; +import com.android.internal.R; + import java.lang.ref.WeakReference; @RemoteView @@ -1241,14 +1243,40 @@ public class StackView extends AdapterViewAnimator { info.setScrollable(getChildCount() > 1); if (isEnabled()) { if (getDisplayedChild() < getChildCount() - 1) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); + if (mStackMode == ITEMS_SLIDE_UP) { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN); + } else { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP); + } } if (getDisplayedChild() > 0) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); + if (mStackMode == ITEMS_SLIDE_UP) { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP); + } else { + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN); + } } } } + private boolean goForward() { + if (getDisplayedChild() < getChildCount() - 1) { + showNext(); + return true; + } + return false; + } + + private boolean goBackward() { + if (getDisplayedChild() > 0) { + showPrevious(); + return true; + } + return false; + } + /** @hide */ @Override public boolean performAccessibilityActionInternal(int action, Bundle arguments) { @@ -1260,17 +1288,25 @@ public class StackView extends AdapterViewAnimator { } switch (action) { case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { - if (getDisplayedChild() < getChildCount() - 1) { - showNext(); - return true; - } - } return false; + return goForward(); + } case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { - if (getDisplayedChild() > 0) { - showPrevious(); - return true; + return goBackward(); + } + case R.id.accessibilityActionPageUp: { + if (mStackMode == ITEMS_SLIDE_UP) { + return goBackward(); + } else { + return goForward(); + } + } + case R.id.accessibilityActionPageDown: { + if (mStackMode == ITEMS_SLIDE_UP) { + return goForward(); + } else { + return goBackward(); } - } return false; + } } return false; } diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 8fe23167755a..7c50337a780f 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -47,6 +47,13 @@ public final class SystemUiDeviceConfigFlags { */ public static final String NAS_MAX_SUGGESTIONS = "nas_max_suggestions"; + // Flags related to controls + + /** + * (boolean) Wether to have split behavior when opening QS + */ + public static final String QS_SPLIT_ENABLED = "qs_split_enabled"; + // Flags related to Smart Suggestions - these are read in SmartReplyConstants. /** (boolean) Whether to enable smart suggestions in notifications. */ diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index ad1ff902b7d8..1d81c59a8f89 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -261,8 +261,21 @@ public class PackageHelper { public static boolean fitsOnInternal(Context context, SessionParams params) throws IOException { final StorageManager storage = context.getSystemService(StorageManager.class); final UUID target = storage.getUuidForPath(Environment.getDataDirectory()); - return (params.sizeBytes <= storage.getAllocatableBytes(target, - translateAllocateFlags(params.installFlags))); + final int flags = translateAllocateFlags(params.installFlags); + + final long allocateableBytes = storage.getAllocatableBytes(target, + flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY); + + // If we fit on internal storage without including freeable cache space, don't bother + // checking to determine how much space is taken up by the cache. + if (params.sizeBytes <= allocateableBytes) { + return true; + } + + final long cacheClearable = storage.getAllocatableBytes(target, + flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY); + + return params.sizeBytes <= allocateableBytes + cacheClearable; } public static boolean fitsOnExternal(Context context, SessionParams params) { diff --git a/core/java/com/android/internal/preference/YesNoPreference.java b/core/java/com/android/internal/preference/YesNoPreference.java index 7abf416bf0af..46d14a16de1e 100644 --- a/core/java/com/android/internal/preference/YesNoPreference.java +++ b/core/java/com/android/internal/preference/YesNoPreference.java @@ -16,6 +16,7 @@ package com.android.internal.preference; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; @@ -40,6 +41,7 @@ public class YesNoPreference extends DialogPreference { this(context, attrs, defStyleAttr, 0); } + @UnsupportedAppUsage public YesNoPreference(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.yesNoPreferenceStyle); } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index c715577cb7d2..cf0394d466ea 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -58,7 +58,7 @@ oneway interface IStatusBar void topAppWindowChanged(int displayId, boolean menuVisible); void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, - boolean showImeSwitcher); + boolean showImeSwitcher, boolean isMultiClientImeEnabled); void setWindowState(int display, int window, int state); void showRecentApps(boolean triggeredFromAltTab); diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 598c3917bf95..85ae18e86793 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -49,7 +49,7 @@ interface IStatusBarService @UnsupportedAppUsage void removeIcon(String slot); void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, - boolean showImeSwitcher); + boolean showImeSwitcher, boolean isMultiClientImeEnabled); void expandSettingsPanel(String subPanel); // ---- Methods below are for use by the status bar policy services ---- diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index b73ecd1974aa..821022f1f917 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -320,23 +320,57 @@ public class ArrayUtils { return array; } + /** + * Combine multiple arrays into a single array. + * + * @param kind The class of the array elements + * @param arrays The arrays to combine + * @param <T> The class of the array elements (inferred from kind). + * @return A single array containing all the elements of the parameter arrays. + */ @SuppressWarnings("unchecked") - public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[] a, @Nullable T[] b) { - final int an = (a != null) ? a.length : 0; - final int bn = (b != null) ? b.length : 0; - if (an == 0 && bn == 0) { - if (kind == String.class) { - return (T[]) EmptyArray.STRING; - } else if (kind == Object.class) { - return (T[]) EmptyArray.OBJECT; + public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { + if (arrays == null || arrays.length == 0) { + return createEmptyArray(kind); + } + + int totalLength = 0; + for (T[] item : arrays) { + if (item == null) { + continue; } + + totalLength += item.length; + } + + // Optimization for entirely empty arrays. + if (totalLength == 0) { + return createEmptyArray(kind); } - final T[] res = (T[]) Array.newInstance(kind, an + bn); - if (an > 0) System.arraycopy(a, 0, res, 0, an); - if (bn > 0) System.arraycopy(b, 0, res, an, bn); - return res; + + final T[] all = (T[]) Array.newInstance(kind, totalLength); + int pos = 0; + for (T[] item : arrays) { + if (item == null || item.length == 0) { + continue; + } + System.arraycopy(item, 0, all, pos, item.length); + pos += item.length; + } + return all; + } + + private static @NonNull <T> T[] createEmptyArray(Class<T> kind) { + if (kind == String.class) { + return (T[]) EmptyArray.STRING; + } else if (kind == Object.class) { + return (T[]) EmptyArray.OBJECT; + } + + return (T[]) Array.newInstance(kind, 0); } + /** * Adds value to given array if not already present, providing set-like * behavior. diff --git a/core/java/com/android/internal/util/DataClass.java b/core/java/com/android/internal/util/DataClass.java index 146f54684c02..da33f996b6a7 100644 --- a/core/java/com/android/internal/util/DataClass.java +++ b/core/java/com/android/internal/util/DataClass.java @@ -177,11 +177,10 @@ public @interface DataClass { /** * @deprecated to be used by code generator exclusively - * @hide */ @Deprecated @Retention(RetentionPolicy.SOURCE) - @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, ANNOTATION_TYPE, CONSTRUCTOR, TYPE}) + @Target({METHOD}) @interface Generated { long time(); String codegenVersion(); @@ -190,7 +189,6 @@ public @interface DataClass { /** * @deprecated to be used by code generator exclusively - * @hide */ @Deprecated @Retention(RetentionPolicy.SOURCE) @@ -199,6 +197,22 @@ public @interface DataClass { } /** + * Opt out of generating {@link #genConstDefs IntDef/StringDef}s for annotated constant + */ + @Retention(RetentionPolicy.SOURCE) + @Target({FIELD}) + @interface SuppressConstDefsGeneration {} + + /** + * A class-level annotation to suppress methods' generation by name + */ + @Retention(RetentionPolicy.SOURCE) + @Target({TYPE}) + @interface Suppress { + String[] value(); + } + + /** * Callback used by {@link #genForEachField}. * * @param <THIS> The enclosing data class instance. diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java index 63530dc389bc..390c5969c08c 100644 --- a/core/java/com/android/internal/util/Parcelling.java +++ b/core/java/com/android/internal/util/Parcelling.java @@ -24,6 +24,8 @@ import java.util.regex.Pattern; /** * Describes a 2-way parcelling contract of type {@code T} into/out of a {@link Parcel} * + * Implementations should be stateless. + * * @param <T> the type being [un]parcelled */ public interface Parcelling<T> { @@ -69,6 +71,7 @@ public interface Parcelling<T> { * instance or reflectively creating one. */ public static <P extends Parcelling<?>> P getOrCreate(Class<P> clazz) { + // No synchronization - creating an extra instance in a race case is ok P cached = get(clazz); if (cached != null) { return cached; diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index 344d7ef8c83f..8799e3d4c6bf 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -26,6 +26,8 @@ import android.util.ArrayMap; import android.util.Base64; import android.util.Xml; +import libcore.util.HexEncoding; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -396,16 +398,7 @@ public class XmlUtils { final int N = val.length; out.attribute(null, "num", Integer.toString(N)); - StringBuilder sb = new StringBuilder(val.length*2); - for (int i=0; i<N; i++) { - int b = val[i]; - int h = (b >> 4) & 0x0f; - sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h))); - h = b & 0x0f; - sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h))); - } - - out.text(sb.toString()); + out.text(HexEncoding.encodeToString(val).toLowerCase()); out.endTag(null, "byte-array"); } @@ -1032,7 +1025,9 @@ public class XmlUtils { "Not a number in num attribute in byte-array"); } - byte[] array = new byte[num]; + // 0 len byte array does not have a text in the XML tag. So, initialize to 0 len array. + // For all other array lens, HexEncoding.decode() below overrides the array. + byte[] array = new byte[0]; int eventType = parser.getEventType(); do { @@ -1043,16 +1038,7 @@ public class XmlUtils { throw new XmlPullParserException( "Invalid value found in byte-array: " + values); } - // This is ugly, but keeping it to mirror the logic in #writeByteArrayXml. - for (int i = 0; i < num; i ++) { - char nibbleHighChar = values.charAt(2 * i); - char nibbleLowChar = values.charAt(2 * i + 1); - int nibbleHigh = nibbleHighChar > 'a' ? (nibbleHighChar - 'a' + 10) - : (nibbleHighChar - '0'); - int nibbleLow = nibbleLowChar > 'a' ? (nibbleLowChar - 'a' + 10) - : (nibbleLowChar - '0'); - array[i] = (byte) ((nibbleHigh & 0x0F) << 4 | (nibbleLow & 0x0F)); - } + array = HexEncoding.decode(values); } } else if (eventType == parser.END_TAG) { if (parser.getName().equals(endTag)) { diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index dfd6f95c00af..cc468f41a7f3 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -33,7 +33,13 @@ import android.view.PointerIcon; import com.android.internal.os.IResultReceiver; +import dalvik.annotation.compat.UnsupportedAppUsage; + public class BaseIWindow extends IWindow.Stub { + + @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P) + public BaseIWindow() {} + private IWindowSession mSession; public int mSeq; diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index dc45f7834748..32867a8949e6 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -558,7 +558,7 @@ public class LockPatternUtils { /** * Returns the password history hash factor, needed to check new password against password - * history with {@link #checkPasswordHistory(String, byte[], int)} + * history with {@link #checkPasswordHistory(byte[], byte[], int)} */ public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) { try { @@ -1242,23 +1242,6 @@ public class LockPatternUtils { return res; } - /** - * Transform a pattern byte array to base zero form. - * @param bytes pattern byte array. - * @return The pattern in base zero form. - */ - public static byte[] patternByteArrayToBaseZero(byte[] bytes) { - if (bytes == null) { - return new byte[0]; - } - final int patternSize = bytes.length; - byte[] res = new byte[patternSize]; - for (int i = 0; i < patternSize; i++) { - res[i] = (byte) (bytes[i] - '1'); - } - return res; - } - /* * Generate an SHA-1 hash for the pattern. Not the most secure, but it is * at least a second level of protection. First level is that the file diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java index 0d87afa42e3e..9bb45012b61a 100644 --- a/core/java/com/android/internal/widget/MediaNotificationView.java +++ b/core/java/com/android/internal/widget/MediaNotificationView.java @@ -175,8 +175,10 @@ public class MediaNotificationView extends FrameLayout { @Override public void onVisibilityAggregated(boolean isVisible) { super.onVisibilityAggregated(isVisible); - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onAggregatedVisibilityChanged(isVisible); + if (mListeners != null) { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onAggregatedVisibilityChanged(isVisible); + } } } diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index 9084f625f9cb..d48034b66266 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -53,6 +53,12 @@ public class PointerLocationView extends View implements InputDeviceListener, // to plot alongside the default one. Useful for testing and comparison purposes. private static final String ALT_STRATEGY_PROPERY_KEY = "debug.velocitytracker.alt"; + /** + * If set to a positive value between 1-255, shows an overlay with the approved (red) and + * rejected (blue) exclusions. + */ + private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion"; + public static class PointerState { // Trace of previous points. private float[] mTraceX = new float[32]; @@ -138,8 +144,10 @@ public class PointerLocationView extends View implements InputDeviceListener, private final PointerCoords mTempCoords = new PointerCoords(); private final Region mSystemGestureExclusion = new Region(); + private final Region mSystemGestureExclusionRejected = new Region(); private final Path mSystemGestureExclusionPath = new Path(); private final Paint mSystemGestureExclusionPaint; + private final Paint mSystemGestureExclusionRejectedPaint; private final VelocityTracker mVelocity; private final VelocityTracker mAltVelocity; @@ -190,6 +198,10 @@ public class PointerLocationView extends View implements InputDeviceListener, mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0); mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mSystemGestureExclusionRejectedPaint = new Paint(); + mSystemGestureExclusionRejectedPaint.setARGB(25, 0, 0, 255); + mSystemGestureExclusionRejectedPaint.setStyle(Paint.Style.FILL_AND_STROKE); + PointerState ps = new PointerState(); mPointers.add(ps); mActivePointerId = 0; @@ -263,6 +275,12 @@ public class PointerLocationView extends View implements InputDeviceListener, canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint); } + if (!mSystemGestureExclusionRejected.isEmpty()) { + mSystemGestureExclusionPath.reset(); + mSystemGestureExclusionRejected.getBoundaryPath(mSystemGestureExclusionPath); + canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionRejectedPaint); + } + // Labels if (mActivePointerId >= 0) { final PointerState ps = mPointers.get(mActivePointerId); @@ -754,6 +772,9 @@ public class PointerLocationView extends View implements InputDeviceListener, } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + final int alpha = systemGestureExclusionOpacity(); + mSystemGestureExclusionPaint.setAlpha(alpha); + mSystemGestureExclusionRejectedPaint.setAlpha(alpha); } else { mSystemGestureExclusion.setEmpty(); } @@ -805,7 +826,12 @@ public class PointerLocationView extends View implements InputDeviceListener, } private static boolean shouldShowSystemGestureExclusion() { - return SystemProperties.getBoolean("debug.pointerlocation.showexclusion", false); + return systemGestureExclusionOpacity() > 0; + } + + private static int systemGestureExclusionOpacity() { + int x = SystemProperties.getInt(GESTURE_EXCLUSION_PROP, 0); + return x >= 0 && x <= 255 ? x : 0; } // HACK @@ -928,12 +954,19 @@ public class PointerLocationView extends View implements InputDeviceListener, private ISystemGestureExclusionListener mSystemGestureExclusionListener = new ISystemGestureExclusionListener.Stub() { @Override - public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) { + public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion, + Region systemGestureExclusionUnrestricted) { Region exclusion = Region.obtain(systemGestureExclusion); + Region rejected = Region.obtain(); + if (systemGestureExclusionUnrestricted != null) { + rejected.set(systemGestureExclusionUnrestricted); + rejected.op(exclusion, Region.Op.DIFFERENCE); + } Handler handler = getHandler(); if (handler != null) { handler.post(() -> { mSystemGestureExclusion.set(exclusion); + mSystemGestureExclusionRejected.set(rejected); exclusion.recycle(); invalidate(); }); diff --git a/core/java/com/android/server/job/JobSchedulerInternal.java b/core/java/com/android/server/job/JobSchedulerInternal.java index 425ec473bc8e..dbf3b984d5fe 100644 --- a/core/java/com/android/server/job/JobSchedulerInternal.java +++ b/core/java/com/android/server/job/JobSchedulerInternal.java @@ -16,7 +16,6 @@ package com.android.server.job; -import android.annotation.UserIdInt; import android.app.job.JobInfo; import java.util.List; @@ -27,31 +26,6 @@ import java.util.List; */ public interface JobSchedulerInternal { - // Bookkeeping about app standby bucket scheduling - - /** - * The current bucket heartbeat ordinal - */ - long currentHeartbeat(); - - /** - * Heartbeat ordinal at which the given standby bucket's jobs next become runnable - */ - long nextHeartbeatForBucket(int bucket); - - /** - * Heartbeat ordinal for the given app. This is typically the heartbeat at which - * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run - * jobs in a long time is immediately runnable even if the app is bucketed into - * an infrequent time allocation. - */ - public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket); - - /** - * Tell the scheduler when a JobServiceContext starts running a job in an app - */ - void noteJobStart(String packageName, int userId); - /** * Returns a list of pending jobs scheduled by the system service. */ diff --git a/core/jni/Android.bp b/core/jni/Android.bp index d42c43b53067..844a89862d5a 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -33,46 +33,10 @@ cc_library_shared { srcs: [ "android_animation_PropertyValuesHolder.cpp", - "android_graphics_Canvas.cpp", - "android_graphics_ColorSpace.cpp", - "android_graphics_drawable_AnimatedVectorDrawable.cpp", - "android_graphics_drawable_VectorDrawable.cpp", - "android_graphics_Picture.cpp", - "android_nio_utils.cpp", "android_os_SystemClock.cpp", "android_os_SystemProperties.cpp", "android_util_EventLog.cpp", "android_util_Log.cpp", - "android_util_PathParser.cpp", - "android_view_DisplayListCanvas.cpp", - "android_view_RenderNode.cpp", - "android/graphics/Bitmap.cpp", - "android/graphics/BitmapFactory.cpp", - "android/graphics/ByteBufferStreamAdaptor.cpp", - "android/graphics/ColorFilter.cpp", - "android/graphics/CreateJavaOutputStreamAdaptor.cpp", - "android/graphics/FontFamily.cpp", - "android/graphics/FontUtils.cpp", - "android/graphics/Graphics.cpp", - "android/graphics/ImageDecoder.cpp", - "android/graphics/MaskFilter.cpp", - "android/graphics/Matrix.cpp", - "android/graphics/NinePatch.cpp", - "android/graphics/NinePatchPeeker.cpp", - "android/graphics/Paint.cpp", - "android/graphics/PaintFilter.cpp", - "android/graphics/Path.cpp", - "android/graphics/PathEffect.cpp", - "android/graphics/PathMeasure.cpp", - "android/graphics/Picture.cpp", - "android/graphics/Region.cpp", - "android/graphics/Shader.cpp", - "android/graphics/Typeface.cpp", - "android/graphics/Utils.cpp", - "android/graphics/fonts/Font.cpp", - "android/graphics/fonts/FontFamily.cpp", - "android/graphics/text/LineBreaker.cpp", - "android/graphics/text/MeasuredText.cpp", "com_android_internal_util_VirtualRefBasePtr.cpp", "com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp", ], @@ -83,21 +47,23 @@ cc_library_shared { "bionic/libc/private", "external/skia/include/private", - "external/skia/src/codec", - "external/skia/src/core", - "external/skia/src/effects", - "external/skia/src/image", - "external/skia/src/images", "frameworks/base/media/jni", "system/media/camera/include", "system/media/private/camera/include", ], + static_libs: [ + "libandroid_graphics", + ], + + whole_static_libs: ["libandroid_graphics"], + shared_libs: [ "libbase", "libcutils", "libharfbuzz_ng", "libhwui", + "libjpeg", "liblog", "libminikin", "libnativehelper", @@ -105,7 +71,6 @@ cc_library_shared { "libziparchive", ], - local_include_dirs: ["android/graphics"], export_include_dirs: [ ".", "include", @@ -141,7 +106,6 @@ cc_library_shared { "android_database_SQLiteDebug.cpp", "android_view_CompositionSamplingListener.cpp", "android_view_DisplayEventReceiver.cpp", - "android_view_TextureLayer.cpp", "android_view_InputChannel.cpp", "android_view_InputDevice.cpp", "android_view_InputEventReceiver.cpp", @@ -157,7 +121,6 @@ cc_library_shared { "android_view_SurfaceControl.cpp", "android_view_SurfaceSession.cpp", "android_view_TextureView.cpp", - "android_view_ThreadedRenderer.cpp", "android_view_VelocityTracker.cpp", "android_text_AndroidCharacter.cpp", "android_text_Hyphenator.cpp", @@ -188,21 +151,6 @@ cc_library_shared { "android_util_StringBlock.cpp", "android_util_XmlBlock.cpp", "android_util_jar_StrictJarFile.cpp", - "android/graphics/AnimatedImageDrawable.cpp", - "android/graphics/Camera.cpp", - "android/graphics/CanvasProperty.cpp", - "android/graphics/GIFMovie.cpp", - "android/graphics/GraphicBuffer.cpp", - "android/graphics/Interpolator.cpp", - "android/graphics/Movie.cpp", - "android/graphics/MovieImpl.cpp", - "android/graphics/BitmapRegionDecoder.cpp", - "android/graphics/SurfaceTexture.cpp", - "android/graphics/YuvToJpegEncoder.cpp", - "android/graphics/pdf/PdfDocument.cpp", - "android/graphics/pdf/PdfEditor.cpp", - "android/graphics/pdf/PdfRenderer.cpp", - "android/graphics/pdf/PdfUtils.cpp", "android_media_AudioEffectDescriptor.cpp", "android_media_AudioRecord.cpp", "android_media_AudioSystem.cpp", @@ -302,7 +250,6 @@ cc_library_shared { "libmeminfo", "libaudioclient", "libaudiopolicy", - "libjpeg", "libusbhost", "libpdfium", "libimg_utils", @@ -328,9 +275,6 @@ cc_library_shared { // our headers include libnativewindow's public headers "libnativewindow", - - // GraphicsJNI.h includes hwui headers - "libhwui", ], generated_sources: ["android_util_StatsLogInternal.cpp"], }, @@ -344,6 +288,8 @@ cc_library_shared { ], include_dirs: [ "external/vulkan-headers/include", + "frameworks/native/libs/nativebase/include", + "frameworks/native/libs/nativewindow/include" ], shared_libs: [ "libicui18n", @@ -353,6 +299,7 @@ cc_library_shared { "libandroidfw", "libcompiler_rt", "libutils", + "libhostgraphics", ], }, linux_glibc: { @@ -367,3 +314,140 @@ cc_library_shared { }, }, } + +cc_library_static { + name: "libandroid_graphics", + host_supported: true, + cflags: [ + "-Wno-unused-parameter", + "-Wno-non-virtual-dtor", + "-Wno-maybe-uninitialized", + "-Wno-parentheses", + + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + + "-DU_USING_ICU_NAMESPACE=0", + + "-Wall", + "-Werror", + "-Wno-error=deprecated-declarations", + "-Wunused", + "-Wunreachable-code", + ], + + cppflags: ["-Wno-conversion-null"], + + srcs: [ + "android_graphics_Canvas.cpp", + "android_graphics_ColorSpace.cpp", + "android_graphics_drawable_AnimatedVectorDrawable.cpp", + "android_graphics_drawable_VectorDrawable.cpp", + "android_graphics_Picture.cpp", + "android_nio_utils.cpp", + "android_view_DisplayListCanvas.cpp", + "android_view_RenderNode.cpp", + "android_util_PathParser.cpp", + + "android/graphics/AnimatedImageDrawable.cpp", + "android/graphics/Bitmap.cpp", + "android/graphics/BitmapFactory.cpp", + "android/graphics/ByteBufferStreamAdaptor.cpp", + "android/graphics/Camera.cpp", + "android/graphics/CanvasProperty.cpp", + "android/graphics/ColorFilter.cpp", + "android/graphics/CreateJavaOutputStreamAdaptor.cpp", + "android/graphics/FontFamily.cpp", + "android/graphics/FontUtils.cpp", + "android/graphics/Graphics.cpp", + "android/graphics/ImageDecoder.cpp", + "android/graphics/Interpolator.cpp", + "android/graphics/MaskFilter.cpp", + "android/graphics/Matrix.cpp", + "android/graphics/NinePatch.cpp", + "android/graphics/NinePatchPeeker.cpp", + "android/graphics/Paint.cpp", + "android/graphics/PaintFilter.cpp", + "android/graphics/Path.cpp", + "android/graphics/PathEffect.cpp", + "android/graphics/PathMeasure.cpp", + "android/graphics/Picture.cpp", + "android/graphics/Region.cpp", + "android/graphics/Shader.cpp", + "android/graphics/Typeface.cpp", + "android/graphics/Utils.cpp", + "android/graphics/YuvToJpegEncoder.cpp", + "android/graphics/fonts/Font.cpp", + "android/graphics/fonts/FontFamily.cpp", + "android/graphics/text/LineBreaker.cpp", + "android/graphics/text/MeasuredText.cpp", + ], + + local_include_dirs: [ + "include", // NEEDED FOR ANDROID RUNTIME + "android/graphics", + ], + + export_include_dirs: [ + ".", + ], + + include_dirs: [ + "external/skia/include/private", + "external/skia/src/codec", + "external/skia/src/core", + "external/skia/src/effects", + "external/skia/src/image", + "external/skia/src/images", + ], + + shared_libs: [ + "libbase", + "libcutils", + "libharfbuzz_ng", + "libhwui", + "liblog", + "libminikin", + "libnativehelper", + "libz", + "libziparchive", + "libjpeg", + ], + + target: { + android: { + srcs: [ // sources that depend on android only libraries + "android_view_TextureLayer.cpp", + "android_view_ThreadedRenderer.cpp", + "android/graphics/BitmapRegionDecoder.cpp", + "android/graphics/GIFMovie.cpp", + "android/graphics/GraphicBuffer.cpp", + "android/graphics/Movie.cpp", + "android/graphics/MovieImpl.cpp", + "android/graphics/SurfaceTexture.cpp", + "android/graphics/pdf/PdfDocument.cpp", + "android/graphics/pdf/PdfEditor.cpp", + "android/graphics/pdf/PdfRenderer.cpp", + "android/graphics/pdf/PdfUtils.cpp", + ], + shared_libs: [ + "libandroidfw", + "libnativewindow", + "libgui", + "libpdfium", + ], + static_libs: [ + "libgif", + ], + }, + host: { + cflags: [ + "-Wno-unused-const-variable", + "-Wno-unused-function", + ], + static_libs: [ + "libandroidfw", + ], + } + }, +} diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp index 00e5ba3ff16d..706a2b8c8ad5 100644 --- a/core/jni/android_hardware_HardwareBuffer.cpp +++ b/core/jni/android_hardware_HardwareBuffer.cpp @@ -20,7 +20,6 @@ #include <nativehelper/JNIHelp.h> #include "android_os_Parcel.h" -#include "android/graphics/GraphicsJNI.h" #include "android/graphics/GraphicBuffer.h" #include <android/hardware_buffer.h> diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index f390930e17a5..c75c54beb8b9 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -27,7 +27,6 @@ #include "android_os_Parcel.h" #include "android_view_MotionEvent.h" #include "android_util_Binder.h" -#include "android/graphics/Matrix.h" #include "core_jni_helpers.h" diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 0d95f99441ae..8eb9c9abecff 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -57,8 +57,8 @@ namespace android { -static const char* const OutOfResourcesException = - "android/view/Surface$OutOfResourcesException"; +static const char* const IllegalArgumentException = "java/lang/IllegalArgumentException"; +static const char* const OutOfResourcesException = "android/view/Surface$OutOfResourcesException"; static struct { jclass clazz; @@ -155,7 +155,7 @@ static jlong nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz, jobject surfaceTextureObj) { sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj)); if (producer == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", + jniThrowException(env, IllegalArgumentException, "SurfaceTexture has already been released"); return 0; } @@ -183,7 +183,7 @@ static jboolean nativeIsValid(JNIEnv* env, jclass clazz, jlong nativeObject) { static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jlong nativeObject) { sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(sur)) { - doThrowIAE(env); + jniThrowException(env, IllegalArgumentException, NULL); return JNI_FALSE; } int value = 0; @@ -212,7 +212,7 @@ static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { - doThrowIAE(env); + jniThrowException(env, IllegalArgumentException, NULL); return 0; } @@ -293,7 +293,7 @@ static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, // unlock surface status_t err = surface->unlockAndPost(); if (err < 0) { - doThrowIAE(env); + jniThrowException(env, IllegalArgumentException, NULL); } } @@ -344,7 +344,7 @@ static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (parcel == NULL) { - doThrowNPE(env); + jniThrowNullPointerException(env, NULL); return 0; } @@ -385,7 +385,7 @@ static void nativeWriteToParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (parcel == NULL) { - doThrowNPE(env); + jniThrowNullPointerException(env, NULL); return; } sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index a5792293e4bd..5cbf81c30a3f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -20,7 +20,6 @@ #include "android_os_Parcel.h" #include "android_util_Binder.h" #include "android_hardware_input_InputWindowHandle.h" -#include "android/graphics/Bitmap.h" #include "android/graphics/Region.h" #include "core_jni_helpers.h" diff --git a/core/proto/OWNERS b/core/proto/OWNERS index 71e386011253..6ab0fc91d744 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -15,3 +15,6 @@ jjaggi@google.com # Launcher hyunyoungs@google.com + +# Graphics stats +jreck@google.com diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index c534aa419595..5d4be5502138 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -38,10 +38,10 @@ message JobSchedulerServiceDumpProto { optional ConstantsProto settings = 1; - optional int32 current_heartbeat = 14; - repeated int32 next_heartbeat = 15; - optional int64 last_heartbeat_time_millis = 16; - optional int64 next_heartbeat_time_millis = 17; + reserved 14; // current_heartbeat + reserved 15; // next_heartbeat + reserved 16; // last_heartbeat_time_millis + reserved 17; // next_heartbeat_time_millis optional bool in_parole = 18; optional bool in_thermal = 19; @@ -64,7 +64,7 @@ message JobSchedulerServiceDumpProto { optional bool is_uid_backing_up = 7; optional bool is_component_present = 8; - optional int64 last_run_heartbeat = 9; + reserved 9; // last_run_heartbeat } repeated RegisteredJob registered_jobs = 3; @@ -214,13 +214,13 @@ message ConstantsProto { // assignment. This should be prime relative to common time interval lengths // such as a quarter-hour or day, so that the heartbeat drifts relative to // wall-clock milestones. - optional int64 standby_heartbeat_time_ms = 19; + reserved 19; // standby_heartbeat_time_ms // Mapping: standby bucket -> number of heartbeats between each sweep of // that bucket's jobs. // Bucket assignments as recorded in the JobStatus objects are normalized to // be indices into this array, rather than the raw constants used by // AppIdleHistory. - repeated int32 standby_beats = 20; + reserved 20; // standby_beats // The fraction of a job's running window that must pass before we // consider running it when the network is congested. optional double conn_congestion_delay_frac = 21; @@ -229,7 +229,7 @@ message ConstantsProto { optional double conn_prefetch_relax_frac = 22; // Whether to use heartbeats or rolling window for quota management. True // will use heartbeats, false will use a rolling window. - optional bool use_heartbeats = 23; + reserved 23; // use_heartbeats message QuotaController { option (.android.msg_privacy).dest = DEST_AUTOMATIC; diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto index 11f046748b32..557075cc5bfa 100644 --- a/core/proto/android/service/graphicsstats.proto +++ b/core/proto/android/service/graphicsstats.proto @@ -51,6 +51,9 @@ message GraphicsStatsProto { // The frame time histogram for the package. repeated GraphicsStatsHistogramBucketProto histogram = 6; + + // The gpu frame time histogram for the package + repeated GraphicsStatsHistogramBucketProto gpu_histogram = 7; } message GraphicsStatsJankSummaryProto { diff --git a/core/proto/android/stats/textclassifier/textclassifier_enums.proto b/core/proto/android/stats/textclassifier/textclassifier_enums.proto new file mode 100644 index 000000000000..1885f19c6377 --- /dev/null +++ b/core/proto/android/stats/textclassifier/textclassifier_enums.proto @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 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. + */ + +syntax = "proto2"; +package android.stats.textclassifier; +option java_multiple_files = true; + +enum EventType { + TYPE_UNKNOWN = 0; + // User started a new selection. + SELECTION_STARTED = 1; + // User modified an existing selection. + SELECTION_MODIFIED = 2; + // Smart selection triggered for a single token (word). + SMART_SELECTION_SINGLE = 3; + // Smart selection triggered spanning multiple tokens (words). + SMART_SELECTION_MULTI = 4; + // Something else other than user or the default TextClassifier triggered a selection. + AUTO_SELECTION = 5; + // Smart actions shown to the user. + ACTIONS_SHOWN = 6; + // User clicked a link. + LINK_CLICKED = 7; + // User typed over the selection. + OVERTYPE = 8; + // User clicked on Copy action. + COPY_ACTION = 9; + // User clicked on Paste action. + PASTE_ACTION = 10; + // User clicked on Cut action. + CUT_ACTION = 11; + // User clicked on Share action. + SHARE_ACTION = 12; + // User clicked on a Smart action. + SMART_ACTION = 13; + // User dragged+dropped the selection. + SELECTION_DRAG = 14; + // Selection is destroyed. + SELECTION_DESTROYED = 15; + // User clicked on a custom action. + OTHER_ACTION = 16; + // User clicked on Select All action + SELECT_ALL = 17; + // User reset the smart selection. + SELECTION_RESET = 18; + // User composed a reply. + MANUAL_REPLY = 19; + // TextClassifier generated some actions + ACTIONS_GENERATED = 20; +} + +enum WidgetType { + WIDGET_TYPE_UNKNOWN = 0; + // Standard TextView + WIDGET_TYPE_TEXTVIEW = 1; + // EditText + WIDGET_TYPE_EDITTEXT = 2; + // Not selectable textview + WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = 3; + // Standard Webview + WIDGET_TYPE_WEBVIEW = 4; + // Editable TextView + WIDGET_TYPE_EDIT_WEBVIEW = 5; + // Custom text widget + WIDGET_TYPE_CUSTOM_TEXTVIEW = 6; + // Custom editable text widget. + WIDGET_TYPE_CUSTOM_EDITTEXT = 7; + // Non-selectable text widget. + WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = 8; + // Notification + WIDGET_TYPE_NOTIFICATION = 9; +} diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 7a0d475a7285..878cda122b68 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Stemboodskappe"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-oproepe"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Hoëprioriteit-SIM-status"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Ander party het TTY-modus VOL versoek"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Ander party het TTY-modus GOD versoek"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Ander party het TTY-modus SOD versoek"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 11ab44de7fea..f5ef6ca79493 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"የድምጽ መልዕክቶች"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"የWi-Fi ጥሪ"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"የሲም ሁኔታ"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ከፍተኛ ቅድሚያ ተሰጪ የሲም ኹናቴ"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ FULL ጠይቋል"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ HCO ጠይቋል"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ቢጤ መልዕክት መጻጻፊያ ስልክ ሁነታ VCO ጠይቋል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 6edc9339008c..217c3cf9b815 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -99,6 +99,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"رسائل البريد الصوتي"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"الاتصال عبر Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"حالة شريحة SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"حالة شريحة SIM ذات أولوية"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"طلب النظير وضع TTY الكامل"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"طلب النظير وضع TTY على HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"طلب النظير وضع TTY على VCO"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 36604039d884..6ea6a52f2bd5 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভইচমেইলৰ বাৰ্তাসমূহ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"ৱাই-ফাই কলিং"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"ছিমৰ স্থিতি"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ অগ্ৰাধিকাৰযুক্ত ছিমৰ স্থিতি"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড FULLলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index e2b399850af7..47572bc87065 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Səsli e-poçt mesajları"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi zəngi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Yüksək Prioritetli SIM statusu"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Eskpert TTY Rejimi FULL-u sorğuladı"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Ekspert TTY Rejimi HCO-nu sorğuladı"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Ekspert TTY Rejimi VCO-nu sorğuladı"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 821b73039c89..9bd9e930f948 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -96,6 +96,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Pozivanje preko Wi-Fi mreže"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Obaveštenja SIM kartice sa statusom „visok prioritet“"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Korisnik zahteva POTPUN režim TTY"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Korisnik zahteva PRENOS ZVUKA za režim TTY"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Korisnik zahteva PRENOS GLASA za režim TTY"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index d5732028981e..2b5d8c96ec8c 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Паведамленні галасавой пошты"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-тэлефанія"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карты"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Стан SIM-карты з высокім прыярытэтам"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Аднарангавая прылада запытала рэжым TTY FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Аднарангавая прылада запытала рэжым TTY НСО"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Аднарангавая прылада запытала рэжым TTY VCO"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index e073b7d9948b..c9220a0fce07 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Съобщения в гласовата поща"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Обаждания през Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Състояние на SIM картата"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Състояние на SIM картата с висок приоритет"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Отсрещният потребител заяви пълен TTY режим (FULL)"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Отсрещният потребител заяви TTY режим с пренос на слух (HCO)"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Отсрещният потребител заяви TTY режим с пренос на глас (VCО)"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 368ff90b5368..b6a924090649 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভয়েসমেল মেসেজ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"ওয়াই-ফাই কলিং"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"সিম কার্ডের স্টাটাস"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ প্রায়রিটি সিম স্ট্যাটাস"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"পির TTY মোড FULL অনুরোধ করেছে"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"পির TTY মোড HCO অনুরোধ করেছে"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"পির TTY মোড VCO অনুরোধ করেছে"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index ce852b6a01dd..02d65e36404b 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -96,6 +96,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Pozivanje putem WiFi-ja"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status visokog prioriteta SIM-a"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Ravnopravni uređaj zatražio načina rada TTY FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Ravnopravni uređaj zatražio načina rada TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Ravnopravni uređaj zatražio načina rada TTY VCO"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index bbf1736bb913..0ec04b618813 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Missatges de veu"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Trucades per Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Estat de la SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estat de la SIM d\'alta prioritat"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"L\'altre dispositiu ha sol·licitat el mode TTY COMPLET."</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"L\'altre dispositiu ha sol·licitat el mode TTY HCO."</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"L\'altre dispositiu ha sol·licitat el mode TTY VCO."</string> @@ -573,9 +574,9 @@ <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Torna a registrar la teva cara."</string> <string name="face_acquired_too_different" msgid="7663983770123789694">"Ja no es reconeix la teva cara. Torna-ho a provar."</string> <string name="face_acquired_too_similar" msgid="1508776858407646460">"És massa semblant; canvia de postura."</string> - <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"Inclina el cap una mica menys."</string> - <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"Inclina el cap una mica menys."</string> - <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No inclinis tant el cap."</string> + <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"No giris tant el cap."</string> + <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"No inclinis tant el cap."</string> + <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No giris tant el cap."</string> <string name="face_acquired_obscured" msgid="5357207702967893283">"Suprimeix qualsevol cosa que amagui la teva cara."</string> <string name="face_acquired_sensor_dirty" msgid="7905138627046865579">"Neteja la part superior de la pantalla, inclosa la barra negra"</string> <string-array name="face_acquired_vendor"> @@ -1483,7 +1484,7 @@ <string name="back_button_label" msgid="2300470004503343439">"Enrere"</string> <string name="next_button_label" msgid="1080555104677992408">"Següent"</string> <string name="skip_button_label" msgid="1275362299471631819">"Omet"</string> - <string name="no_matches" msgid="8129421908915840737">"Cap coincidència"</string> + <string name="no_matches" msgid="8129421908915840737">"No s\'ha trobat cap coincidència"</string> <string name="find_on_page" msgid="1946799233822820384">"Troba-ho a la pàgina"</string> <plurals name="matches_found" formatted="false" msgid="1210884353962081884"> <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 4171a8bce984..3a77e9cebb80 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Hlasové zprávy"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Volání přes Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Stav SIM karty"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stav SIM karty: vysoká priorita"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner požádal o přechod na režim TTY FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner požádal o přechod na režim TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner požádal o přechod na režim TTY VCO"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index b6cb874eb647..c10680e67197 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talebeskeder"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-opkald"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-kort med høj prioritet"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Den anden enhed har skiftet til FULD TTY-tilstand"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Den anden enhed har skiftet til TTY-tilstanden HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Den anden enhed har skiftet til TTY-tilstanden VCO"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 114d8019207d..933741a0a862 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mailboxnachrichten"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"WLAN-Telefonie"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status der SIM-Karte"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Benachrichtigungen mit hoher Priorität von der SIM-Karte"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer hat TTY-Modus \"Vollständig\" angefordert."</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer hat TTY-Modus \"HCO\" angefordert."</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer hat TTY-Modus \"VC\" angefordert."</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 44357ff161b5..e5ff8a8aa132 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Μηνύματα αυτόματου τηλεφωνητή"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Κλήση Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Κατάσταση SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Κατάσταση SIM υψηλής προτεραιότητας"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Αίτημα peer για TTY ΠΛΗΡΗΣ Λειτουργία"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Αίτημα peer για TTY Λειτουργία HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Αίτημα peer για TTY Λειτουργία VCO"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index cc389f3189f1..4f0ebc58caa9 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 0e6d49cef10f..d1ac6dc68be2 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index cc389f3189f1..4f0ebc58caa9 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index cc389f3189f1..4f0ebc58caa9 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi Calling"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index dade85ebf851..66aa94650f2e 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemail messages"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi calling"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority SIM status"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer requested TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer requested TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer requested TTY Mode VCO"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 3a2ea3e101e7..68604d9ffac6 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensajes del buzón de voz"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Llamada con Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Estado de SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notificaciones de prioridad alta sobre el estado de la SIM"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"El dispositivo del mismo nivel solicitó el modo TTY FULL."</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"El dispositivo del mismo nivel solicitó el modo TTY HCO."</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"El dispositivo del mismo nivel solicitó el modo TTY VCO."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 633759b68cb5..f290fae6a142 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensajes de voz"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Llamada por Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Estado de la tarjeta SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado de SIM de alta prioridad"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Un dispositivo ha solicitado el modo TTY FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Un dispositivo ha solicitado el modo TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Un dispositivo ha solicitado el modo TTY VCO"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 86843c7a3dfd..8e0755515cd4 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Kõnepostisõnumid"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"WiFi-kõned"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kaardi olek"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Kõrge prioriteediga SIM-i olek"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner taotles TTY-režiimi TÄIELIK"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner taotles TTY-režiimi HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner taotles TTY-režiimi VCO"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index d25fe8c24401..730340650a66 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Erantzungailuko mezuak"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi bidezko deiak"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIMaren egoera"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM txartelaren lehentasun handiko jakinarazpenak"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Beste gailuak TTY osagarria FULL moduan erabiltzea eskatu du"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Beste gailuak TTY osagarria HCO moduan erabiltzea eskatu du"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Beste gailuak TTY osagarria VCO moduan erabiltzea eskatu du"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 48cdafcfed47..44428dc56ce5 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"پیامهای پست صوتی"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"تماس ازطریق Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"وضعیت سیمکارت"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"وضعیت سیم با اولویت بالا"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"دستگاه مرتبط درخواست TTY حالت FULL کرد"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"دستگاه مرتبط درخواست TTY حالت HCO کرد"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"دستگاه مرتبط درخواست TTY حالت VCO کرد"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index cd9a71174649..ccc9d334bc08 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Vastaajaviestit"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-puhelut"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kortin tila"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Tärkeät SIM-ilmoitukset"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Toinen käyttäjä vaihtoi TTY-tilaksi TÄYSI"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Toinen käyttäjä vaihtoi TTY-tilaksi HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Toinen käyttäjä vaihtoi TTY-tilaksi VCO"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 2bfef39cf924..99f874d6f43c 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messages vocaux"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Appels Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"État de la carte SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"État SIM de priorité élevée"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Mode TTY COMPLET demandé par un pair"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Mode TTY HCO demandé par un pair"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Mode TTY VCO demandé par un pair"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 041668fdba58..bac6066dc269 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messages vocaux"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Appels Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"État de la carte SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notifications prioritaires de la carte SIM"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Mode TTY demandé par l\'interlocuteur : COMPLET"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Mode TTY demandé par l\'interlocuteur : HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Mode TTY demandé par l\'interlocuteur : VCO"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index b3eed4a59e9f..40c1ed28a594 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensaxes de correo de voz"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por wifi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Estado da SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado da SIM con prioridade alta"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Outro dispositivo solicitou o modo TTY COMPLETO"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Outro dispositivo solicitou o modo TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Outro dispositivo solicitou o modo TTY VCO"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 1b961727da84..bbb344ba523f 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"વૉઇસમેઇલ સંદેશા"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"વાઇ-ફાઇ કૉલિંગ"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"સિમનું સ્ટેટસ"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"સિમ કાર્ડનું ઉચ્ચ પ્રાધાન્યતાનું સ્ટેટસ"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"પીઅરે TTY મોડ પૂર્ણની વિનંતી કરી"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"પીઅરે TTY મોડ HCO ની વિનંતી કરી"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"પીઅરે TTY મોડ VCO ની વિનંતી કરી"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index fd063c4a0b34..f130e015941b 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"वॉइसमेल संदेश"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"वाई-फ़ाई कॉलिंग"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"सिम की स्थिति"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"सिम की ज़रूरी सूचनाओं की स्थिति"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"पीयर ने टेलीटाइपराइटर (TTY) मोड फ़ुल का अनुरोध किया"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"पीयर ने टेलीटाइपराइटर (TTY) मोड एचसीओ (HCO) का अनुरोध किया"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"पीयर ने टेलीटाइपराइटर (TTY) मोड वीसीओ (VCO) का अनुरोध किया"</string> @@ -451,7 +452,7 @@ <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"ऐप को डिवाइस के फ़ोन नंबर का इस्तेमाल करने देती है."</string> <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टैबलेट को सोने (कम बैटरी मोड) से रोकें"</string> <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"टीवी को सोने (कम बैटरी मोड) से रोकें"</string> - <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"टीवी को सोने (कम बैटरी मोड) से रोकें"</string> + <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को सोने (कम बैटरी मोड) से रोकें"</string> <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ऐप्स को टैबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string> <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"ऐप को टीवी को सोने (कम बैटरी मोड) से रोकने की अनुमति देता है."</string> <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ऐप्स को फ़ोन को प्रयोग में नहीं होने से रोकता है."</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 21fdc2ff1072..38bd8a31e45e 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -96,6 +96,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Poruke govorne pošte"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi pozivi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM-a"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM-a visokog prioriteta"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Način TTY FULL koji zahtijeva paralelni uređaj"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Način TTY HCO koji zahtijeva paralelni uređaj"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Način TTY VCO koji zahtijeva paralelni uređaj"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 1198610fe605..d146ca7c4525 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Hangpostaüzenetek"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-hívás"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-kártya állapota"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Elsődleges SIM-kártya állapota"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Partner által kért TTY-mód: FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Partner által kért TTY-mód: HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Partner által kért TTY-mód: VCO"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 7165df91b170..91d255208569 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ձայնային փոստի հաղորդագրություններ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Զանգեր Wi-Fi-ի միջոցով"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM քարտի կարգավիճակը"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM քարտի բարձր առաջնահերթության ծանուցումներ"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Բաժանորդի սարքում ընտրված է հեռատիպի ԲՈԼՈՐԸ ռեժիմը"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Բաժանորդի սարքում ընտրված է հեռատիպի HCO ռեժիմը"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Բաժանորդի սարքում ընտրված է հեռատիպի VCO ռեժիմը"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index ca369ebf8b40..4a8723b5646c 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Notifikasi pesan suara"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Panggilan Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM prioritas tinggi"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Rekan meminta Mode TTY PENUH"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Rekan meminta Mode TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Rekan meminta Mode TTY VCO"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 572313aa0ed6..16bcd27842bf 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talhólfsskilaboð"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi símtöl"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Staða SIM-korts"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Áríðandi staða SIM-korts"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Jafningi bað um FULLA stillingu fjarrita"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Jafningi bað um HCO-stillingu fjarrita"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Jafningi bað um VCO-stillingu fjarrita"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 6c579b85600f..8581eca4cc00 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Messaggi vocali"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Chiamate Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Stato SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stato SIM con priorità elevata"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer ha richiesto la modalità TTY FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer ha richiesto la modalità TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer ha richiesto la modalità TTY VCO"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 437b31b652bb..dc108b4e9d6b 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"הודעות קוליות"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"שיחות Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"סטטוס SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"סטטוס התראות SIM בעדיפות גבוהה"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"העמית ביקש TTY במצב FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"העמית ביקש TTY במצב HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"העמית ביקש TTY במצב VCO"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 471c66603956..5180ab20b19a 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ボイスメール メッセージ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM のステータス"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高優先度: SIM のステータス"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ピアから、TTY モードを FULL にするようリクエストされました"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ピアから、TTYモードをHCOにするようリクエストされました"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ピアから、TTYモードをVCOにするようリクエストされました"</string> @@ -551,11 +552,11 @@ <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"指紋アイコン"</string> - <string name="permlab_manageFace" msgid="7262837876352591553">"フェイスアンロック ハードウェアの管理"</string> + <string name="permlab_manageFace" msgid="7262837876352591553">"顔認証ハードウェアの管理"</string> <string name="permdesc_manageFace" msgid="8919637120670185330">"使用する顔テンプレートの追加や削除を行うメソッドの呼び出しをアプリに許可します。"</string> - <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"フェイスアンロック ハードウェアの使用"</string> - <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"フェイスアンロック ハードウェアを認証に使用することをアプリに許可します"</string> - <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"フェイスアンロック"</string> + <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"顔認証ハードウェアの使用"</string> + <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"顔認証ハードウェアを認証に使用することをアプリに許可します"</string> + <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"顔認証"</string> <string name="face_recalibrate_notification_title" msgid="4087620069451499365">"顔の再登録"</string> <string name="face_recalibrate_notification_content" msgid="5530308842361499835">"認識を改善するには、顔を再登録してください"</string> <string name="face_acquired_insufficient" msgid="2767330364802375742">"顔を認識できませんでした。もう一度お試しください。"</string> @@ -581,15 +582,15 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="396883585636963908">"顔を確認できません。ハードウェアを利用できません。"</string> - <string name="face_error_timeout" msgid="981512090365729465">"フェイスアンロックをもう一度お試しください。"</string> + <string name="face_error_timeout" msgid="981512090365729465">"顔認証をもう一度お試しください。"</string> <string name="face_error_no_space" msgid="2712120617457553825">"新しい顔データを保存できません。古いデータを削除してください。"</string> <string name="face_error_canceled" msgid="283945501061931023">"顔の操作をキャンセルしました。"</string> - <string name="face_error_user_canceled" msgid="5317030072349668946">"フェイスアンロックはユーザーによりキャンセルされました。"</string> + <string name="face_error_user_canceled" msgid="5317030072349668946">"顔認証はユーザーによりキャンセルされました。"</string> <string name="face_error_lockout" msgid="3407426963155388504">"試行回数の上限です。後でもう一度お試しください。"</string> - <string name="face_error_lockout_permanent" msgid="4723594314443097159">"試行回数が上限を超えました。フェイスアンロックを無効にしました。"</string> + <string name="face_error_lockout_permanent" msgid="4723594314443097159">"試行回数が上限を超えたため、顔認証を無効にしました。"</string> <string name="face_error_unable_to_process" msgid="4940944939691171539">"顔を確認できません。もう一度お試しください。"</string> - <string name="face_error_not_enrolled" msgid="4016937174832839540">"フェイスアンロックを設定していません。"</string> - <string name="face_error_hw_not_present" msgid="8302690289757559738">"このデバイスでは、フェイスアンロックはご利用いただけません。"</string> + <string name="face_error_not_enrolled" msgid="4016937174832839540">"顔認証を設定していません。"</string> + <string name="face_error_hw_not_present" msgid="8302690289757559738">"このデバイスでは、顔認証はご利用いただけません。"</string> <string name="face_name_template" msgid="7004562145809595384">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -818,7 +819,7 @@ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"もう一度お試しください"</string> <string name="lockscreen_password_wrong" msgid="5737815393253165301">"もう一度お試しください"</string> <string name="lockscreen_storage_locked" msgid="9167551160010625200">"すべての機能とデータを利用するにはロック解除"</string> - <string name="faceunlock_multiple_failures" msgid="754137583022792429">"フェイスアンロックの最大試行回数を超えました"</string> + <string name="faceunlock_multiple_failures" msgid="754137583022792429">"顔認証の最大試行回数を超えました"</string> <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIMカードが挿入されていません"</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"タブレット内にSIMカードがありません。"</string> <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"テレビにSIMカードが挿入されていません。"</string> @@ -888,7 +889,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ロック解除エリアを拡大します。"</string> <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"スライドロックを解除します。"</string> <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"パターンロックを解除します。"</string> - <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"フェイスアンロックを行います。"</string> + <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"顔認証を行います。"</string> <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PINロックを解除します。"</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"SIM PIN のロックを解除します。"</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"SIM PUK のロックを解除します。"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 3570d4ccecfd..2bba8cb6e808 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ხმოვანი ფოსტის შეტყობინებები"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"დარეკვა Wi-Fi-ს მეშვეობით"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM სტატუსი"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"მაღალპრიორიტეტული SIM სტატუსი"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"მოთხოვნილია კვანძი TTY რეჟიმი FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"მოთხოვნილია კვანძი TTY რეჟიმი HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"მოთხოვნილია კვანძი TTY რეჟიმი VCO"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 2ed1e5bf5541..ec0ab3e2ee33 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Дауыстық пошта хабарлары"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi қоңыраулары"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM күйі"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM картасы туралы маңызды хабарландырулар"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Пир TTY режимі ТОЛЫҚ сұрады"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Пир TTY режимінің HCO сұрады"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Пир TTY режимінің VCO сұрады"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 02c6ba8cc233..e9a140c29eef 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"សារជាសំឡេង"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"ការហៅទូរសព្ទតាម Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"ស្ថានភាពស៊ីម"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ស្ថានភាពស៊ីមដែលមានអាទិភាពខ្ពស់"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ម៉ាស៊ីនកូនបានស្នើ TTY Mode VCO"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 875ecd41eb4a..e82d54bd8dd0 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ಧ್ವನಿಮೇಲ್ ಸಂದೇಶಗಳು"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"ಸಿಮ್ ಸ್ಥಿತಿ"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ಹೆಚ್ಚಿನ ಆದ್ಯತೆಯ ಸಿಮ್ ಸ್ಥಿತಿ"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ VCO"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 90771451866a..4be4bd2e04a1 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"음성사서함 메시지"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 통화"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 상태"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"우선순위가 높은 SIM 상태"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"피어가 TTY 모드 FULL을 요청했습니다."</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"피어가 TTY 모드 HCO를 요청했습니다."</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"피어가 TTY 모드 VCO를 요청했습니다."</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 8cac3638ae28..6607242e5b92 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Үн почтасынын билдирүүлөрү"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi аркылуу чалуу"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-картанын абалы"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM картадагы өтө маанилүү билдирмелер"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer TTY режимин FULL кылууну суранды"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer TTY режимин HCO кылууну суранды"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer TTY режимин VCO кылууну суранды"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 47b0fe49796e..684adc3a456c 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ຂໍ້ຄວາມສຽງ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"ການໂທ Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"ສະຖານະ SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ສະຖານະ SIM ຄວາມສຳຄັນສູງ"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ໂໝດ TTY ທີ່ເພື່ອນຂໍນັ້ນເຕັມແລ້ວ"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ໂໝດ TTY ທີ່ເພື່ອນຂໍ HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ໂໝດ TTY ທີ່ເພື່ອນຂໍ VCO"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 6f8e2df08241..5283f27a2afb 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Balso pašto pranešimai"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"„Wi-Fi“ skambinimas"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM būsena"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Didelio prioriteto SIM kortelės būsena"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Lygiavertis naudotojas pateikė užklausą dėl TTY režimo VCO"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 253ff722ffda..c93ae1fbf126 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -96,6 +96,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Balss pasta ziņojumi"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi zvani"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM kartes statuss"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Augstas prioritātes SIM kartes statuss"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Vienādranga ierīce pieprasīja teksta tālruņa režīmu VCO"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 19c1c85c28d7..70ee0ae9eb03 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Пораки од говорна пошта"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Повикување преку Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Статус на SIM-картичка"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Статус на SIM-известувања со висок приоритет"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Рамноправен уред го побара режимот на TTY „FULL“"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Рамноправен уред го побара режимот на TTY „HCO“"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Рамноправен уред го побара режимот на TTY „VCO“"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index b2e9b643366c..3fb844d0b687 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"വോയ്സ്മെയിൽ സന്ദേശങ്ങൾ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"വൈഫൈ കോളിംഗ്"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"സിം നില"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ഉയർന്ന മുൻഗണനയുള്ള സിം നില"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഫുൾ\'"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index a229713fd61e..254bb0e29bfa 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Дуут шуудангийн мессеж"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi дуудлага"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM статус"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Өндөр ач холбогдолтой SIM-н статус"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Хандлагын цэгт хүсэлт тавьсан TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Хандлагын цэгт хүсэлт тавьсан TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Хандлагын цэгт хүсэлт тавьсан TTY Mode VCO"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index a86caa5c0fc8..5fc2310b1571 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"व्हॉइसमेल मेसेज"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"वाय-फाय कॉलिंग"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"सिम स्थिती"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राधान्य सिम स्थिती"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"समवयस्क व्यक्तीने TTY मोड पूर्ण ची विनंती केली"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"समवयस्क व्यक्तीने TTY मोड HCO ची विनंती केली"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"समवयस्क व्यक्तीने TTY मोड VCO ची विनंती केली"</string> @@ -302,8 +303,8 @@ <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"शारीरिक अॅक्टिव्हिटी अॅक्सेस करा"</string> <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला तुमची शारीरिक अॅक्टिव्हिटी अॅक्सेस करण्याची अनुमती द्यायची का?"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"कॅमेरा"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"चित्रे घेण्याची आणि व्हिडिओ रेकॉर्ड"</string> - <string name="permgrouprequest_camera" msgid="1299833592069671756">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला फोटो घेऊ आणि व्हिडिओ रेकॉर्ड करू द्यायचे?"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"चित्रे काढण्याची आणि व्हिडिओ रेकॉर्ड करण्याची"</string> + <string name="permgrouprequest_camera" msgid="1299833592069671756">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला फोटो काढू आणि व्हिडिओ रेकॉर्ड करू द्यायचे?"</string> <string name="permgrouplab_calllog" msgid="8798646184930388160">"कॉल लॉग"</string> <string name="permgroupdesc_calllog" msgid="3006237336748283775">"फोन कॉल लॉग वाचा आणि लिहा"</string> <string name="permgrouprequest_calllog" msgid="8487355309583773267">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला तुमचे फोन कॉल लॉग अॅक्सेस करण्याची अनुमती द्यायची का?"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index c18e07879512..7d1b76c8d944 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesej mel suara"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Panggilan Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status SIM keutamaan tinggi"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Rakan meminta Mod TTY PENUH"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Rakan meminta Mod TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Rakan meminta Mod TTY VCO"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 55e7b015fe00..e037b7000151 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"အသံမေးလ် မက်ဆေ့ဂျ်များ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ခေါ်ဆိုမှု"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"ဆင်းမ်ကဒ် အခြေအနေ"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"အထူးဦးစားပေး ဆင်းမ်ကတ်အခြေအနေ"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"အခြားစက်မှ TTY မုဒ် FULL ပြုရန် တောင်းဆို၏"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"အခြားစက်မှ TTY မုဒ် HCO ပြုရန် တောင်းဆို၏"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY မုဒ် VCO ပြုရန် အခြားစက်မှ တောင်းဆို၏"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index a5893892bc70..c75c8d1d48ea 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Talepostmeldinger"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-anrop"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM-status"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-status er satt til høy prioritet"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Motpart ba om TTY-modus FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Motpart ba om TTY-modus HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Motpart ba om TTY-modus VCO"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 89e75b4257ac..1422caa0570c 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"भ्वाइस मेल सन्देशहरू"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi कल"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM को स्थिति"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राथमिकता रहेको SIM को स्थिति"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"सहकर्मी अनुरोध गरियो। TTY मोड पूर्ण"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"सहकर्मी अनुरोध गरियो। TTY मोड HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"सहकर्मी अनुरोध गरियो। TTY मोड VCO"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 4194eb15b6af..c668abeb525a 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Voicemailberichten"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Bellen via wifi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Simkaartstatus"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Meldingen met hoge prioriteit voor de simkaartstatus"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Door peer aangevraagde TTY-modus VOL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Door peer aangevraagde TTY-modus HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Door peer aangevraagde TTY-modus VCO"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index df874bceea9b..940fdc1624ee 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ଭଏସମେଲ୍ ମେସେଜ୍"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM ଷ୍ଟାଟସ୍"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ଉଚ୍ଚ ପ୍ରାଥମିକତା SIM ସ୍ଥିତି"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ପୀଆର୍ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍ FULL ଅଟେ"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ପୀଅର୍ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍ HCO ଅଟେ"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ପୀଅର୍ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍ VCO ଅଟେ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 8245546a4436..ddf2fc144660 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ਵੌਇਸਮੇਲ ਸੁਨੇਹੇ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"ਸਿਮ ਅਵਸਥਾ"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ਉੱਚ ਤਰਜੀਹੀ ਸਿਮ ਸਥਿਤੀ"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ਪੀਅਰ ਨੇ TTY Mode FULL ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ਪੀਅਰ ਨੇ TTY Mode HCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ਪੀਅਰ ਨੇ TTY Mode VCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 054a45626778..69fc0e6330e7 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Wiadomości poczty głosowej"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Połączenia przez Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Stan karty SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stan karty SIM – wysoki priorytet"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Drugie urządzenie zażądało trybu „TTY pełny”"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Drugie urządzenie zażądało trybu „TTY HCO”"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Drugie urządzenie zażądało trybu „TTY VCO”"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 742fa81d0e25..f29ea427fbb4 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status de prioridade alta do chip"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 85fb7fddc5d8..696f2f1420a8 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens de correio de voz"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Estado do SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Estado do SIM de elevada prioridade"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"O par solicitou o modo COMPLETO de teletipo"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"O par solicitou o modo HCO de teletipo"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"O par solicitou o modo VCO de teletipo"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 742fa81d0e25..f29ea427fbb4 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Status de prioridade alta do chip"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 2f464e93920a..d80a7ba8f26f 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -96,6 +96,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesaje din mesageria vocală"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Apelare prin Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Starea cardului SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notificări de la SIM cu prioritate ridicată"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Cealaltă persoană a solicitat modul TTY cu setarea COMPLET"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Cealaltă persoană a solicitat modul TTY cu setarea HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Cealaltă persoană a solicitat modul TTY cu setarea VCO"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index c4b61b2f9216..410f4b9c4ce1 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Голосовые сообщения"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Звонки по Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карты"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Важные уведомления SIM-карты"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"На устройстве абонента выбран режим телетайпа \"ВСЕ\""</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"На устройстве абонента выбран режим телетайпа HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"На устройстве абонента выбран режим телетайпа VCO"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index ddeb94ba9ec0..a39cb6e08e34 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"හඬ තැපැල් පණිවිඩ"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ඇමතීම"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM තත්ත්වය"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ඉහළ ප්රමුඛතා SIM තත්ත්වය"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"සම ඉල්ලීම් කළ TTY ප්රකාරය පූර්ණයි"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"සම ඉල්ලීම් කළ TTY ප්රකාරය HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"සම ඉල්ලීම් කළ TTY ප්රකාරය VCO"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 4d19308c15e1..d8a75610f736 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Správy hlasovej schránky"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Volanie cez Wi‑Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Stav SIM karty"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stav SIM karty: vysoká priorita"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Používateľ, s ktorým komunikujete, požiadal o režim FULL textového telefónu"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Používateľ, s ktorým komunikujete, požiadal o režim HCO textového telefónu"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Používateľ, s ktorým komunikujete, požiadal o režim VCO textového telefónu"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index b2b3109b2b60..7e12c2ce90a8 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sporočila v odzivniku"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Klicanje prek Wi-Fi-ja"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Stanje kartice SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stanje kartice SIM z visoko stopnjo prednosti"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Enakovredna naprava je zahtevala način TTY FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Enakovredna naprava je zahtevala način TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Enakovredna naprava je zahtevala način TTY VCO"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index afed336078a2..a958d1b3de8b 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesazhet e postës zanore"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Telefonata me Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Statusi i kartës SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Statusi i kartës SIM me përparësi të lartë"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Homologu yt kërkoi modalitet \"TTY\" të plotë"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Homologu kërkoi modalitet \"TTY\" të llojit \"HCO\""</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Homologu yt kërkoi modalitet \"TTY\" të llojit \"VCO\""</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 110b31d68b97..1adede396eee 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -96,6 +96,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Поруке говорне поште"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Позивање преко Wi-Fi мреже"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-а"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Обавештења SIM картице са статусом „висок приоритет“"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Корисник захтева ПОТПУН режим TTY"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Корисник захтева ПРЕНОС ЗВУКА за режим TTY"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Корисник захтева ПРЕНОС ГЛАСА за режим TTY"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index bc1752e7135d..434f36ac1fe9 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Röstmeddelanden"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi-samtal"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status för SIM-kort"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM-aviseringar med hög prioritet"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Peer-enheten begärde texttelefonläget FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Peer-enheten begärde texttelefonläget HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Peer-enheten begärde texttelefonläget VCO"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 92510ea79f7f..8f18cebe95d0 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ujumbe wa sauti"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Kupiga simu kupitia Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Hali ya SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Hali ya SIM ya kipaumbele cha juu"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Hali ya TTY iliyoombwa na mtandao mwenza KAMILI"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Hali ya TTY iliyoombwa na mtandao mwenza HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Hali ya TTY iliyoombwa na mtandao mwenza VCO"</string> @@ -364,7 +365,7 @@ <string name="permlab_enableCarMode" msgid="5684504058192921098">"Wezesha mtindo wa gari"</string> <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Inaruhusu programu kuwawezesha mtindo wa gari."</string> <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"funga programu zingine"</string> - <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Inaruhusu programu kukamilisha michakato ya usuli ya programu nyingine. Hii inaweza kusababisha programu nyingine kukoma kufanyakazi."</string> + <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Huruhusu programu kukamilisha michakato ya chinichini ya programu nyingine. Hii inaweza kusababisha programu nyingine kuacha kufanya kazi."</string> <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"Programu hii inaweza kuonekana juu ya programu zingine"</string> <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"Programu hii inaweza kuonekana juu ya programu zingine au sehemu zingine za skrini. Hii huenda ikaathiri matumizi ya kawaida ya programu na kubadilisha jinsi ambavyo programu zingine zinavyoonekana."</string> <string name="permlab_runInBackground" msgid="7365290743781858803">"tumia chini chini"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index ab3446f3f3fc..d211e900f20b 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"குரலஞ்சல் செய்திகள்"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"வைஃபை அழைப்பு"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"சிம் நிலை"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"அதிக முன்னுரிமையுடைய சிம்மின் நிலை"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"TTY Mode FULLஐ இணைச் செயல்பாடு கோரியது"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"TTY Mode HCOஐ இணைச் செயல்பாடு கோரியது"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY Mode VCOஐ இணைச் செயல்பாடு கோரியது"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 649e17c4229d..e6a3daf54999 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"వాయిస్ మెయిల్ సందేశాలు"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi కాలింగ్"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM స్థితి"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"అధిక ప్రాధాన్యత గల SIM స్థితి"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"అవతలి వారు FULL TTY మోడ్ని అభ్యర్థించారు"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"అవతలి వారు HCO TTY మోడ్ని అభ్యర్థించారు"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"అవతలి వారు VCO TTY మోడ్ని అభ్యర్థించారు"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 4e6943011d33..045ea3e64b57 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ข้อความเสียง"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"การโทรผ่าน Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"สถานะซิม"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"สถานะซิมลำดับความสำคัญสูง"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"เต็ม\""</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"HCO\""</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"อีกฝั่งหนึ่งขอโหมด TTY เป็น \"VCO\""</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 68435284b9a5..6dcc40c6fcd1 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mga mensahe sa voicemail"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Pagtawag gamit ang Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Status ng SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"High priority na status ng SIM"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Hiniling ng peer ang TTY Mode FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Hiniling ng peer ang TTY Mode HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Hiniling ng peer ang TTY Mode VCO"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 3592df9abe34..c0303ac6a579 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Sesli mesajlar"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Kablosuz çağrı"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM durumu"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Yüksek öncelikli SIM durumu"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Karşı taraf TTY Modunu TAM yaptı"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Karşı taraf TTY Modunu HCO yaptı"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Karşı taraf TTY Modunu VCO yaptı"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 347c81f3af42..3437b51738c9 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -97,6 +97,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Повідомлення голосової пошти"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Дзвінки через Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карти"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Високопріоритетні сповіщення із SIM-карти"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Пристрій змінив режим TTY на FULL"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Пристрій змінив режим TTY на HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Пристрій змінив режим TTY на VCO"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 3fd6fe757bbf..83c3199b360d 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"صوتی میل پیغامات"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi کالنگ"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM کا اسٹیٹس"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"اعلی ترجیحی SIM کی صورتحال"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"ہمسر نے TTY وضع مکمل کی درخواست کی"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"ہمسر نے TTY وضع HCO کی درخواست کی"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"ہمسر نے TTY وضع VCO کی درخواست کی"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 85ebe0035a49..0425010b5212 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Ovozli xabarlar"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi chaqiruv"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM karta holati"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"SIM kartadagi muhim bildirishnomalar"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Teng huquqli ishtirokchi teletayp rejimini FULL (to‘liq) qilib o‘zgartirdi"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Teng huquqli ishtirokchi teletayp rejimini HCO (eshitadi, gapirolmaydi) qilib o‘zgartirdi"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Teng huquqli ishtirokchi teletayp rejimini VCO (gapiradi, eshitolmaydi) qilib o‘zgartirdi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 78c429010f0f..4f7b4fe4ab35 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Thư thoại"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Gọi qua Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Trạng thái SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Trạng thái SIM có mức ưu tiên cao"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ ĐẦY ĐỦ"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY theo yêu cầu của thiết bị ngang hàng ở chế độ VCO"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 9893a0f09ca7..765e1db572d7 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"语音邮件"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"WLAN 通话"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡状态"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高优先顺序 SIM 卡状态"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"对方请求使用“TTY 完整”模式"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"对方请求使用“TTY HCO”模式"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"对方请求使用“TTY VCO”模式"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 884772e7b628..412407952c41 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"留言訊息"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"重要 SIM 卡狀態"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"對方曾要求 TTY 完整模式"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"對方曾要求 TTY 模式 (HCO)"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"對方曾要求 TTY 模式 (VCO)"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 580a1dc6b2b1..1f7b3e25a6d7 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"語音留言"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi 通話"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"SIM 卡狀態"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"高優先順序 SIM 卡狀態"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"通訊對象要求使用 TTY 的 FULL 模式"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"通訊對象要求使用 TTY 的 HCO 模式"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"通訊對象要求使用 TTY 的 VCO 模式"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index c4f8823b1714..c58c77c17ae0 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -95,6 +95,7 @@ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Imilayezo yevoyisimeyili"</string> <string name="notification_channel_wfc" msgid="2130802501654254801">"Ukushaya kwe-Wi-Fi"</string> <string name="notification_channel_sim" msgid="4052095493875188564">"Isimo se-SIM"</string> + <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Isimo se-SIM esiphezulu kakhulu"</string> <string name="peerTtyModeFull" msgid="6165351790010341421">"Umngani ucele imodi ye-TTY ephelele"</string> <string name="peerTtyModeHco" msgid="5728602160669216784">"Umngani ucele imodi ye-TTY HCO"</string> <string name="peerTtyModeVco" msgid="1742404978686538049">"Umngani ucele imodi ye-TTY VCO"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b34c422053df..4d6e7dabde81 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1301,6 +1301,9 @@ <!-- Whether to use the strict phone number matcher in Kazakhstan. --> <bool name="config_use_strict_phone_number_comparation_for_kazakhstan">true</bool> + <!-- The character count of the minimum match for comparison phone numbers --> + <integer name="config_phonenumber_compare_min_match">7</integer> + <!-- Display low battery warning when battery level dips to this value. Also, the battery stats are flushed to disk when we hit this level. --> <integer name="config_criticalBatteryWarningLevel">5</integer> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ac32c95bcd5e..4094bf4a2162 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -320,6 +320,7 @@ <java-symbol type="bool" name="config_use_strict_phone_number_comparation" /> <java-symbol type="bool" name="config_use_strict_phone_number_comparation_for_russia" /> <java-symbol type="bool" name="config_use_strict_phone_number_comparation_for_kazakhstan" /> + <java-symbol type="integer" name="config_phonenumber_compare_min_match" /> <java-symbol type="bool" name="config_single_volume" /> <java-symbol type="bool" name="config_voice_capable" /> <java-symbol type="bool" name="config_requireCallCapableAccountForHandle" /> diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java index f9e37981fa6f..6e65df1bafb6 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java @@ -17,7 +17,6 @@ package com.android.server.broadcastradio.hal2; import static org.junit.Assert.*; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -41,7 +40,6 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; @@ -49,7 +47,6 @@ import org.mockito.stubbing.Answer; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Set; /** * Tests for v2 HAL RadioModule. @@ -293,61 +290,6 @@ public class StartProgramListUpdatesFanoutTest { } ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet, removedSet); - verify(clientMock).onProgramListUpdated(argThat(new ChunkMatcher(expectedChunk))); + verify(clientMock).onProgramListUpdated(expectedChunk); } - - // TODO(b/130750904): Remove this class and replace "argThat(new ChunkMatcher(chunk))" with - // "eq(chunk)". - // - // Ideally, this class wouldn't exist, but currently RadioManager.ProgramInfo#hashCode() can - // return different values for objects that satisfy ProgramInfo#equals(). As a short term - // workaround, this class performs the O(N^2) comparison between the Chunks' mModified sets. - // - // To test if ProgramInfo#hashCode() has been fixed, remove commenting from - // testProgramInfoHashCode() below. - private class ChunkMatcher implements ArgumentMatcher<ProgramList.Chunk> { - private final ProgramList.Chunk mExpected; - - ChunkMatcher(ProgramList.Chunk expected) { - mExpected = expected; - } - - @Override - public boolean matches(ProgramList.Chunk actual) { - if ((mExpected.isPurge() != actual.isPurge()) - || (mExpected.isComplete() != actual.isComplete()) - || (!mExpected.getRemoved().equals(actual.getRemoved()))) { - return false; - } - Set<RadioManager.ProgramInfo> expectedModified = mExpected.getModified(); - Set<RadioManager.ProgramInfo> actualModified = new HashSet<>(actual.getModified()); - if (expectedModified.size() != actualModified.size()) { - return false; - } - for (RadioManager.ProgramInfo expectedInfo : expectedModified) { - boolean found = false; - for (RadioManager.ProgramInfo actualInfo : actualModified) { - if (expectedInfo.equals(actualInfo)) { - found = true; - actualModified.remove(actualInfo); - break; - } - } - if (!found) { - return false; - } - } - return true; - } - } - - // @Test - // public void testProgramInfoHashCode() { - // RadioManager.ProgramInfo info1 = TestUtils.makeProgramInfo( - // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0); - // RadioManager.ProgramInfo info2 = TestUtils.makeProgramInfo( - // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0); - // assertEquals(info1, info2); - // assertEquals(info1.hashCode(), info2.hashCode()); - // } } diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 833c7347926b..1670d49a46c4 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -58,6 +58,8 @@ android_test { resource_dirs: ["res"], resource_zips: [":FrameworksCoreTests_apks_as_resources"], + + data: [":BstatsTestApp"], } // Rules to copy all the test apks to the intermediate raw resource directory diff --git a/core/tests/coretests/BstatsTestApp/Android.bp b/core/tests/coretests/BstatsTestApp/Android.bp index 424c71a4d8d0..a89d72830686 100644 --- a/core/tests/coretests/BstatsTestApp/Android.bp +++ b/core/tests/coretests/BstatsTestApp/Android.bp @@ -15,10 +15,6 @@ android_test_helper_app { name: "BstatsTestApp", - test_suites: [ - "device-tests", - ], - static_libs: ["coretests-aidl"], srcs: ["**/*.java"], diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java index 0eba2edbb3c3..46873b9eb70b 100644 --- a/core/tests/coretests/src/android/os/ParcelTest.java +++ b/core/tests/coretests/src/android/os/ParcelTest.java @@ -43,8 +43,8 @@ public class ParcelTest { // WorkSource can be updated. p.writeInterfaceToken(INTERFACE_TOKEN_1); - assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1)); - assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid()); + assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2)); + assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid()); // WorkSource can be updated to unset value. assertEquals(true, p.replaceCallingWorkSourceUid(Binder.UNSET_WORKSOURCE)); @@ -56,18 +56,16 @@ public class ParcelTest { @Test public void testCallingWorkSourceUidAfterEnforce() { Parcel p = Parcel.obtain(); - // Write headers manually so that we do not invoke #writeInterfaceToken. - p.writeInt(1); // strict mode header - p.writeInt(WORK_SOURCE_1); // worksource header. - p.writeString(INTERFACE_TOKEN_1); // interface token. + p.writeInterfaceToken(INTERFACE_TOKEN_1); + assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1)); p.setDataPosition(0); p.enforceInterface(INTERFACE_TOKEN_1); assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid()); // WorkSource can be updated. - assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1)); - assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid()); + assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2)); + assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid()); p.recycle(); } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 88bda9d64084..89ba3df287b4 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -721,7 +721,8 @@ public class SettingsBackupTest { Settings.Secure.BIOMETRIC_DEBUG_ENABLED, Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, - Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED); + Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED, + Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp new file mode 100644 index 000000000000..12a2b0815050 --- /dev/null +++ b/core/tests/overlaytests/device/Android.bp @@ -0,0 +1,26 @@ +// Copyright (C) 2018 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. + +android_test { + name: "OverlayDeviceTests", + srcs: ["src/**/*.java"], + platform_apis: true, + static_libs: ["androidx.test.rules"], + test_suites: ["device-tests"], + data: [ + ":OverlayDeviceTests_AppOverlayOne", + ":OverlayDeviceTests_AppOverlayTwo", + ":OverlayDeviceTests_FrameworkOverlay", + ], +} diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk deleted file mode 100644 index c6d2a51b5224..000000000000 --- a/core/tests/overlaytests/device/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2018 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. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under,src) -LOCAL_MODULE_TAGS := tests -LOCAL_PACKAGE_NAME := OverlayDeviceTests -LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules -LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_REQUIRED_MODULES := \ - OverlayDeviceTests_AppOverlayOne \ - OverlayDeviceTests_AppOverlayTwo \ - OverlayDeviceTests_FrameworkOverlay -include $(BUILD_PACKAGE) - -# Include to build test-apps. -include $(call all-makefiles-under,$(LOCAL_PATH)) - diff --git a/core/tests/overlaytests/device/test-apps/Android.mk b/core/tests/overlaytests/device/test-apps/Android.mk deleted file mode 100644 index 9af9f444ca59..000000000000 --- a/core/tests/overlaytests/device/test-apps/Android.mk +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (C) 2018 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. - -include $(call all-subdir-makefiles) diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp new file mode 100644 index 000000000000..da3aa007135a --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp @@ -0,0 +1,20 @@ +// Copyright (C) 2018 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. + +android_test { + name: "OverlayDeviceTests_AppOverlayOne", + sdk_version: "current", + + aaptflags: ["--no-resource-removal"], +} diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk deleted file mode 100644 index fa15241b9cc5..000000000000 --- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) 2018 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. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := tests -LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne -LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_USE_AAPT2 := true -LOCAL_AAPT_FLAGS := --no-resource-removal -include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp new file mode 100644 index 000000000000..215b66da36dc --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp @@ -0,0 +1,20 @@ +// Copyright (C) 2018 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. + +android_test { + name: "OverlayDeviceTests_AppOverlayTwo", + sdk_version: "current", + + aaptflags: ["--no-resource-removal"], +} diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk deleted file mode 100644 index ada9b3cb625d..000000000000 --- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) 2018 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. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := tests -LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo -LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_USE_AAPT2 := true -LOCAL_AAPT_FLAGS := --no-resource-removal -include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp new file mode 100644 index 000000000000..50dbc6f054d3 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp @@ -0,0 +1,21 @@ +// Copyright (C) 2018 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. + +android_test { + name: "OverlayDeviceTests_FrameworkOverlay", + sdk_version: "current", + certificate: "platform", + + aaptflags: ["--no-resource-removal"], +} diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk deleted file mode 100644 index e4819e138eba..000000000000 --- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (C) 2018 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. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := tests -LOCAL_PACKAGE_NAME := OverlayDeviceTests_FrameworkOverlay -LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_CERTIFICATE := platform -LOCAL_USE_AAPT2 := true -LOCAL_AAPT_FLAGS := --no-resource-removal -include $(BUILD_PACKAGE) diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java index 39bb84a20d7a..cb30b3fe5b82 100644 --- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java @@ -177,4 +177,40 @@ public class ArrayUtilsTest extends TestCase { assertArrayEquals(new Long[] { 1L, 2L, 3L, 4L }, concatElements(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L })); } + + public void testConcatElements_threeWay() { + String[] array1 = { "1", "2" }; + String[] array2 = { "3", "4" }; + String[] array3 = { "5", "6" }; + String[] expectation = {"1", "2", "3", "4", "5", "6"}; + + String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3); + assertArrayEquals(expectation, concatResult); + } + + + public void testConcatElements_threeWayWithNull() { + String[] array1 = { "1", "2" }; + String[] array2 = null; + String[] array3 = { "5", "6" }; + String[] expectation = {"1", "2", "5", "6"}; + + String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3); + assertArrayEquals(expectation, concatResult); + } + + public void testConcatElements_zeroElements() { + String[] expectation = new String[0]; + + String[] concatResult = ArrayUtils.concatElements(String.class); + assertArrayEquals(expectation, concatResult); + } + + public void testConcatElements_oneNullElement() { + String[] expectation = new String[0]; + + String[] concatResult = ArrayUtils.concatElements(String.class, null); + assertArrayEquals(expectation, concatResult); + } + } diff --git a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java index 2596ecefe53d..27f3596f239b 100644 --- a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java @@ -16,13 +16,22 @@ package com.android.internal.util; +import static org.junit.Assert.assertArrayEquals; + +import android.util.Xml; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; + import junit.framework.TestCase; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlSerializer; + public class XmlUtilsTest extends TestCase { // https://code.google.com/p/android/issues/detail?id=63717 @@ -38,4 +47,23 @@ public class XmlUtilsTest extends TestCase { assertEquals("nullValue", deserialized.get(null)); assertEquals("fooValue", deserialized.get("foo")); } + + public void testreadWriteXmlByteArrayValue() throws Exception { + byte[] testByteArray = {0x1 , 0xa, 0xb, 0x9, 0x34, (byte) 0xaa, (byte) 0xba, (byte) 0x99}; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + XmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(baos, StandardCharsets.UTF_8.name()); + serializer.startDocument(null, true); + XmlUtils.writeValueXml(testByteArray, "testByteArray", serializer); + serializer.endDocument(); + + InputStream bais = new ByteArrayInputStream(baos.toByteArray()); + XmlPullParser pullParser = Xml.newPullParser(); + pullParser.setInput(bais, StandardCharsets.UTF_8.name()); + String[] name = new String[1]; + byte[] testByteArrayDeserialized = (byte[]) XmlUtils.readValueXml(pullParser, name); + assertEquals("testByteArray", name[0]); + assertArrayEquals(testByteArray, testByteArrayDeserialized); + } } diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index 5af0da85bb39..5ad93f411393 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -21,7 +21,6 @@ import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.fonts.FontVariationAxis; import android.text.TextUtils; -import android.util.Log; import dalvik.annotation.optimization.CriticalNative; @@ -145,7 +144,6 @@ public class FontFamily { } return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic); } catch (IOException e) { - Log.e(TAG, "Error mapping font file " + path); return false; } } diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java index 3361fa21e44b..1d294d51a235 100644 --- a/graphics/java/android/graphics/RectF.java +++ b/graphics/java/android/graphics/RectF.java @@ -27,7 +27,7 @@ import java.io.PrintWriter; /** * RectF holds four float coordinates for a rectangle. The rectangle is - * represented by the coordinates of its 4 edges (left, top, right bottom). + * represented by the coordinates of its 4 edges (left, top, right, bottom). * These fields can be accessed directly. Use width() and height() to retrieve * the rectangle's width and height. Note: most methods do not check to see that * the coordinates are sorted correctly (i.e. left <= right and top <= bottom). diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 4a9cf14d04a5..95a8417b6f7f 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -105,7 +105,6 @@ public final class SystemFonts { final long fontSize = fileChannel.size(); return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); } catch (IOException e) { - Log.e(TAG, "Error mapping font file " + fullPath); return null; } } diff --git a/keystore/java/android/security/AttestedKeyPair.java b/keystore/java/android/security/AttestedKeyPair.java index c6bff5c11a5d..2debfee83923 100644 --- a/keystore/java/android/security/AttestedKeyPair.java +++ b/keystore/java/android/security/AttestedKeyPair.java @@ -16,6 +16,9 @@ package android.security; +import android.annotation.NonNull; +import android.annotation.Nullable; + import java.security.KeyPair; import java.security.cert.Certificate; import java.util.ArrayList; @@ -36,9 +39,12 @@ public final class AttestedKeyPair { private final Certificate[] mAttestationRecord; /** - * @hide Only created by the platform, no need to expose as public API. + * Public constructor for creating a new instance (useful for testing). + * + * @param keyPair the key pair associated with the attestation record. + * @param attestationRecord attestation record for the provided key pair. */ - public AttestedKeyPair(KeyPair keyPair, Certificate[] attestationRecord) { + public AttestedKeyPair(@Nullable KeyPair keyPair, @Nullable Certificate[] attestationRecord) { mKeyPair = keyPair; mAttestationRecord = attestationRecord; } @@ -47,7 +53,7 @@ public final class AttestedKeyPair { * Returns the generated key pair associated with the attestation record * in this instance. */ - public KeyPair getKeyPair() { + public @Nullable KeyPair getKeyPair() { return mKeyPair; } @@ -66,7 +72,7 @@ public final class AttestedKeyPair { * and <a href="https://developer.android.com/training/articles/security-key-attestation.html"> * Key Attestation</a> for the format of the attestation record inside the certificate. */ - public List<Certificate> getAttestationRecord() { + public @NonNull List<Certificate> getAttestationRecord() { if (mAttestationRecord == null) { return new ArrayList(); } diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp new file mode 100644 index 000000000000..aedb7522ab08 --- /dev/null +++ b/libs/hostgraphics/Android.bp @@ -0,0 +1,24 @@ +cc_library_host_static { + name: "libhostgraphics", + + srcs: [ + ":libui_host_common", + ], + + include_dirs: [ + // Here we override all the headers automatically included with frameworks/native/include. + // When frameworks/native/include will be removed from the list of automatic includes. + // We will have to copy necessary headers with a pre-build step (generated headers). + ".", + "frameworks/native/libs/nativebase/include", + "frameworks/native/libs/nativewindow/include", + "frameworks/native/libs/arect/include", + ], + export_include_dirs: ["."], + + target: { + windows: { + enabled: true, + } + }, +}
\ No newline at end of file diff --git a/libs/hostgraphics/gui/IGraphicBufferProducer.h b/libs/hostgraphics/gui/IGraphicBufferProducer.h new file mode 100644 index 000000000000..00422136ff76 --- /dev/null +++ b/libs/hostgraphics/gui/IGraphicBufferProducer.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H +#define ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H + +#include <utils/RefBase.h> + +namespace android { + +class IGraphicBufferProducer : virtual public RefBase { +public: + enum class DisconnectMode { + // Disconnect only the specified API. + Api, + // Disconnect any API originally connected from the process calling disconnect. + AllLocal + }; +}; + +} // namespace android + +#endif // ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H diff --git a/libs/hostgraphics/gui/Surface.h b/libs/hostgraphics/gui/Surface.h new file mode 100644 index 000000000000..de1ba00211d3 --- /dev/null +++ b/libs/hostgraphics/gui/Surface.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef ANDROID_GUI_SURFACE_H +#define ANDROID_GUI_SURFACE_H + +#include <gui/IGraphicBufferProducer.h> +#include <ui/ANativeObjectBase.h> +#include <utils/RefBase.h> +#include <system/window.h> + +namespace android { + +class Surface : public ANativeObjectBase<ANativeWindow, Surface, RefBase> { +public: + explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, + bool controlledByApp = false) { + ANativeWindow::perform = hook_perform; + } + static bool isValid(const sp<Surface>& surface) { return surface != nullptr; } + void allocateBuffers() {} + + uint64_t getNextFrameNumber() const { return 0; } + + int setScalingMode(int mode) { return 0; } + + virtual int disconnect(int api, + IGraphicBufferProducer::DisconnectMode mode = + IGraphicBufferProducer::DisconnectMode::Api) { + return 0; + } + + virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) { + // TODO: implement this + return 0; + } + virtual int unlockAndPost() { return 0; } + virtual int query(int what, int* value) const { return 0; } + +protected: + virtual ~Surface() {} + + static int hook_perform(ANativeWindow* window, int operation, ...) { return 0; } + +private: + // can't be copied + Surface& operator=(const Surface& rhs); + Surface(const Surface& rhs); +}; + +} // namespace android + +#endif // ANDROID_GUI_SURFACE_H diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index 0a9d965d0444..a0d3ff995e78 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -18,7 +18,6 @@ #include "Properties.h" -#include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <ui/GraphicTypes.h> diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index 71cc9a81a09f..0698775b0021 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -37,13 +37,14 @@ const std::string FrameInfoNames[] = { "FrameCompleted", "DequeueBufferDuration", "QueueBufferDuration", + "GpuCompleted", }; static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) == static_cast<int>(FrameInfoIndex::NumIndexes), "size mismatch: FrameInfoNames doesn't match the enum!"); -static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 16, +static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 17, "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)"); void FrameInfo::importUiThreadInfo(int64_t* info) { diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index b75192ff8476..51674fbd557e 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -51,6 +51,8 @@ enum class FrameInfoIndex { DequeueBufferDuration, QueueBufferDuration, + GpuCompleted, + // Must be the last value! // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT NumIndexes @@ -143,6 +145,13 @@ public: return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted); } + inline int64_t gpuDrawTime() const { + // GPU start time is approximated to the moment before swapBuffer is invoked. + // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead. + int64_t endTime = get(FrameInfoIndex::GpuCompleted); + return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1; + } + inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; } inline int64_t get(FrameInfoIndex index) const { diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index 53c5ad8eff3c..eae3584465e4 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -232,5 +232,13 @@ void JankTracker::reset() { : FrameInfoIndex::IntendedVsync; } +void JankTracker::finishGpuDraw(const FrameInfo& frame) { + int64_t totalGPUDrawTime = frame.gpuDrawTime(); + if (totalGPUDrawTime >= 0) { + mData->reportGPUFrame(totalGPUDrawTime); + (*mGlobalData)->reportGPUFrame(totalGPUDrawTime); + } +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h index 110211eda23a..08059268f03e 100644 --- a/libs/hwui/JankTracker.h +++ b/libs/hwui/JankTracker.h @@ -58,6 +58,7 @@ public: FrameInfo* startFrame() { return &mFrames.next(); } void finishFrame(const FrameInfo& frame); + void finishGpuDraw(const FrameInfo& frame); void dumpStats(int fd) { dumpData(fd, &mDescription, mData.get()); } void dumpFrames(int fd); diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp index c7f92321b090..7921662b213c 100644 --- a/libs/hwui/ProfileData.cpp +++ b/libs/hwui/ProfileData.cpp @@ -98,6 +98,10 @@ void ProfileData::mergeWith(const ProfileData& other) { if (mStatStartTime > other.mStatStartTime || mStatStartTime == 0) { mStatStartTime = other.mStatStartTime; } + for (size_t i = 0; i < other.mGPUFrameCounts.size(); i++) { + mGPUFrameCounts[i] >>= divider; + mGPUFrameCounts[i] += other.mGPUFrameCounts[i]; + } } void ProfileData::dump(int fd) const { @@ -117,6 +121,14 @@ void ProfileData::dump(int fd) const { histogramForEach([fd](HistogramEntry entry) { dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount); }); + dprintf(fd, "\n50th gpu percentile: %ums", findGPUPercentile(50)); + dprintf(fd, "\n90th gpu percentile: %ums", findGPUPercentile(90)); + dprintf(fd, "\n95th gpu percentile: %ums", findGPUPercentile(95)); + dprintf(fd, "\n99th gpu percentile: %ums", findGPUPercentile(99)); + dprintf(fd, "\nGPU HISTOGRAM:"); + histogramGPUForEach([fd](HistogramEntry entry) { + dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount); + }); } uint32_t ProfileData::findPercentile(int percentile) const { @@ -140,6 +152,7 @@ uint32_t ProfileData::findPercentile(int percentile) const { void ProfileData::reset() { mJankTypeCounts.fill(0); mFrameCounts.fill(0); + mGPUFrameCounts.fill(0); mSlowFrameCounts.fill(0); mTotalFrameCount = 0; mJankFrameCount = 0; @@ -167,5 +180,40 @@ void ProfileData::histogramForEach(const std::function<void(HistogramEntry)>& ca } } +uint32_t ProfileData::findGPUPercentile(int percentile) const { + uint32_t totalGPUFrameCount = 0; // this is usually mTotalFrameCount - 3. + for (int i = mGPUFrameCounts.size() - 1; i >= 0; i--) { + totalGPUFrameCount += mGPUFrameCounts[i]; + } + int pos = percentile * totalGPUFrameCount / 100; + int remaining = totalGPUFrameCount - pos; + for (int i = mGPUFrameCounts.size() - 1; i >= 0; i--) { + remaining -= mGPUFrameCounts[i]; + if (remaining <= 0) { + return GPUFrameTimeForFrameCountIndex(i); + } + } + return 0; +} + +uint32_t ProfileData::GPUFrameTimeForFrameCountIndex(uint32_t index) { + return index != 25 ? index + 1 : 4950; +} + +void ProfileData::reportGPUFrame(int64_t duration) { + uint32_t index = static_cast<uint32_t>(ns2ms(duration)); + if (index > 25) { + index = 25; + } + + mGPUFrameCounts[index]++; +} + +void ProfileData::histogramGPUForEach(const std::function<void(HistogramEntry)>& callback) const { + for (size_t i = 0; i < mGPUFrameCounts.size(); i++) { + callback(HistogramEntry{GPUFrameTimeForFrameCountIndex(i), mGPUFrameCounts[i]}); + } +} + } /* namespace uirenderer */ } /* namespace android */
\ No newline at end of file diff --git a/libs/hwui/ProfileData.h b/libs/hwui/ProfileData.h index 564920b60328..ccbffc6f136e 100644 --- a/libs/hwui/ProfileData.h +++ b/libs/hwui/ProfileData.h @@ -54,8 +54,10 @@ public: void mergeWith(const ProfileData& other); void dump(int fd) const; uint32_t findPercentile(int percentile) const; + uint32_t findGPUPercentile(int percentile) const; void reportFrame(int64_t duration); + void reportGPUFrame(int64_t duration); void reportJank() { mJankFrameCount++; } void reportJankType(JankType type) { mJankTypeCounts[static_cast<int>(type)]++; } @@ -69,15 +71,21 @@ public: uint32_t frameCount; }; void histogramForEach(const std::function<void(HistogramEntry)>& callback) const; + void histogramGPUForEach(const std::function<void(HistogramEntry)>& callback) const; constexpr static int HistogramSize() { return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value + std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value; } + constexpr static int GPUHistogramSize() { + return std::tuple_size<decltype(ProfileData::mGPUFrameCounts)>::value; + } + // Visible for testing static uint32_t frameTimeForFrameCountIndex(uint32_t index); static uint32_t frameTimeForSlowFrameCountIndex(uint32_t index); + static uint32_t GPUFrameTimeForFrameCountIndex(uint32_t index); private: // Open our guts up to unit tests @@ -88,6 +96,9 @@ private: std::array<uint32_t, 57> mFrameCounts; // Holds a histogram of frame times in 50ms increments from 150ms to 5s std::array<uint16_t, 97> mSlowFrameCounts; + // Holds a histogram of GPU draw times in 1ms increments. Frames longer than 25ms are placed in + // last bucket. + std::array<uint32_t, 26> mGPUFrameCounts; uint32_t mTotalFrameCount; uint32_t mJankFrameCount; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 8aee8f5b1848..8eb5e3d3dfbc 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -20,6 +20,7 @@ #include "Debug.h" #include "TreeInfo.h" #include "VectorDrawable.h" +#include "private/hwui/WebViewFunctor.h" #ifdef __ANDROID__ #include "renderthread/CanvasContext.h" #else diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index c7d5f3193f45..d7076d4cf424 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -15,6 +15,7 @@ */ #include "SkiaDisplayList.h" +#include "FunctorDrawable.h" #include "DumpOpsCanvas.h" #ifdef __ANDROID__ // Layoutlib does not support SkiaPipeline diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index b79103787023..e3c3273a726a 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -16,7 +16,6 @@ #pragma once -#include "FunctorDrawable.h" #include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" @@ -34,6 +33,7 @@ class CanvasContext; } class Outline; +struct WebViewSyncData; namespace VectorDrawable { class Tree; @@ -42,6 +42,8 @@ typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; namespace skiapipeline { +class FunctorDrawable; + class SkiaDisplayList { public: size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); } diff --git a/libs/hwui/protos/graphicsstats.proto b/libs/hwui/protos/graphicsstats.proto index 1226d44ceb85..0cd5c6228504 100644 --- a/libs/hwui/protos/graphicsstats.proto +++ b/libs/hwui/protos/graphicsstats.proto @@ -46,6 +46,9 @@ message GraphicsStatsProto { // The frame time histogram for the package repeated GraphicsStatsHistogramBucketProto histogram = 6; + + // The gpu frame time histogram for the package + repeated GraphicsStatsHistogramBucketProto gpu_histogram = 7; } message GraphicsStatsJankSummaryProto { diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 1b638c12ac7b..5469a6810c87 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -28,7 +28,6 @@ #include <SkExecutor.h> #include <SkGraphics.h> #include <SkMathPriv.h> -#include <gui/Surface.h> #include <math.h> #include <set> diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index d19351bf1db9..88a0c6ea3085 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -147,6 +147,7 @@ void CanvasContext::setSurface(sp<Surface>&& surface) { mNativeSurface = new ReliableSurface{std::move(surface)}; // TODO: Fix error handling & re-shorten timeout mNativeSurface->setDequeueTimeout(4000_ms); + mNativeSurface->enableFrameTimestamps(true); } else { mNativeSurface = nullptr; } @@ -294,6 +295,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy // just keep using the previous frame's structure instead if (!wasSkipped(mCurrentFrameInfo)) { mCurrentFrameInfo = mJankTracker.startFrame(); + mLast4FrameInfos.next().first = mCurrentFrameInfo; } mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo); mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued; @@ -445,7 +447,7 @@ void CanvasContext::draw() { mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler())); - int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1; + int64_t frameCompleteNr = getFrameNumber(); waitOnFences(); @@ -500,11 +502,13 @@ void CanvasContext::draw() { } mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration; + mLast4FrameInfos[-1].second = frameCompleteNr; mHaveNewSurface = false; mFrameNumber = -1; } else { mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0; mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0; + mLast4FrameInfos[-1].second = -1; } // TODO: Use a fence for real completion? @@ -537,6 +541,19 @@ void CanvasContext::draw() { mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data()); } + if (mLast4FrameInfos.size() == mLast4FrameInfos.capacity()) { + // By looking 4 frames back, we guarantee all SF stats are available. There are at + // most 3 buffers in BufferQueue. Surface object keeps stats for the last 8 frames. + FrameInfo* forthBehind = mLast4FrameInfos.front().first; + int64_t composedFrameId = mLast4FrameInfos.front().second; + nsecs_t acquireTime = -1; + mNativeSurface->getFrameTimestamps(composedFrameId, nullptr, &acquireTime, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr); + // Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING + forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1; + mJankTracker.finishGpuDraw(*forthBehind); + } + GpuMemoryTracker::onFrameCompleted(); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 0910828da4f8..8a76d6b3fc7a 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -22,12 +22,14 @@ #include "FrameMetricsReporter.h" #include "IContextFactory.h" #include "IRenderPipeline.h" +#include "JankTracker.h" #include "LayerUpdateQueue.h" #include "Lighting.h" #include "ReliableSurface.h" #include "RenderNode.h" #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" +#include "utils/RingBuffer.h" #include <SkBitmap.h> #include <SkRect.h> @@ -40,6 +42,7 @@ #include <future> #include <set> #include <string> +#include <utility> #include <vector> namespace android { @@ -150,8 +153,6 @@ public: void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; } - RenderState& getRenderState() { return mRenderThread.renderState(); } - void addFrameMetricsObserver(FrameMetricsObserver* observer) { if (mFrameMetricsReporter.get() == nullptr) { mFrameMetricsReporter.reset(new FrameMetricsReporter()); @@ -261,6 +262,7 @@ private: std::vector<sp<RenderNode>> mRenderNodes; FrameInfo* mCurrentFrameInfo = nullptr; + RingBuffer<std::pair<FrameInfo*, int64_t>, 4> mLast4FrameInfos; std::string mName; JankTracker mJankTracker; FrameInfoVisualizer mProfiler; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 159cf497384a..12021641518c 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -29,7 +29,6 @@ #include <EGL/eglext.h> #include <GLES/gl.h> -#include <gui/Surface.h> #include <system/window.h> #include <string> #include <vector> @@ -289,6 +288,10 @@ void EglManager::createPBufferSurface() { if (mPBufferSurface == EGL_NO_SURFACE && !EglExtensions.surfacelessContext) { EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs); + LOG_ALWAYS_FATAL_IF(mPBufferSurface == EGL_NO_SURFACE, + "Failed to create a pixel buffer display=%p, " + "mEglConfig=%p, error=%s", + mEglDisplay, mEglConfig, eglErrorString()); } } diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h index 41fc35eca9f7..7f1a0781dd87 100644 --- a/libs/hwui/renderthread/ReliableSurface.h +++ b/libs/hwui/renderthread/ReliableSurface.h @@ -49,6 +49,21 @@ public: return ret; } + status_t getFrameTimestamps(uint64_t frameNumber, + nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime, + nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime, + nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime, + nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime, + nsecs_t* outReleaseTime) { + return mSurface->getFrameTimestamps(frameNumber, outRequestedPresentTime, outAcquireTime, + outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime, + outGlCompositionDoneTime, outDisplayPresentTime, outDequeueReadyTime, outReleaseTime); + } + + void enableFrameTimestamps(bool enable) { + return mSurface->enableFrameTimestamps(enable); + } + private: const sp<Surface> mSurface; diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index c96e284df6b4..df7eeb398847 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -19,8 +19,8 @@ #include "RenderTask.h" -#include "../JankTracker.h" #include "CacheManager.h" +#include "ProfileDataContainer.h" #include "TimeLord.h" #include "WebViewFunctorManager.h" #include "thread/ThreadBase.h" diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 280f7d3489d2..510016585afc 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -17,7 +17,8 @@ #include "VulkanManager.h" #include <android/sync.h> -#include <gui/Surface.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> #include "Properties.h" #include "RenderThread.h" diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index ec217c0fcbf4..4c6a75504cd0 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -31,6 +31,7 @@ #include "Frame.h" #include "IRenderPipeline.h" #include "VulkanSurface.h" +#include "private/hwui/DrawVkInfo.h" class GrVkExtensions; diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index 8a16b2077f6f..8b5912b2081a 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -40,6 +40,7 @@ constexpr int32_t sHeaderSize = 4; static_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong"); constexpr int sHistogramSize = ProfileData::HistogramSize(); +constexpr int sGPUHistogramSize = ProfileData::GPUHistogramSize(); static bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto, const std::string& package, int64_t versionCode, @@ -211,6 +212,37 @@ bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto, const std::str bucket->set_frame_count(bucket->frame_count() + entry.frameCount); index++; }); + if (hitMergeError) return false; + // fill in GPU frame time histogram + creatingHistogram = false; + if (proto->gpu_histogram_size() == 0) { + proto->mutable_gpu_histogram()->Reserve(sGPUHistogramSize); + creatingHistogram = true; + } else if (proto->gpu_histogram_size() != sGPUHistogramSize) { + ALOGE("GPU histogram size mismatch, proto is %d expected %d", proto->gpu_histogram_size(), + sGPUHistogramSize); + return false; + } + index = 0; + data->histogramGPUForEach([&](ProfileData::HistogramEntry entry) { + if (hitMergeError) return; + + protos::GraphicsStatsHistogramBucketProto* bucket; + if (creatingHistogram) { + bucket = proto->add_gpu_histogram(); + bucket->set_render_millis(entry.renderTimeMs); + } else { + bucket = proto->mutable_gpu_histogram(index); + if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) { + ALOGW("GPU frame time mistmatch %d vs. %u", bucket->render_millis(), + entry.renderTimeMs); + hitMergeError = true; + return; + } + } + bucket->set_frame_count(bucket->frame_count() + entry.frameCount); + index++; + }); return !hitMergeError; } @@ -226,6 +258,22 @@ static int32_t findPercentile(protos::GraphicsStatsProto* proto, int percentile) return 0; } +static int32_t findGPUPercentile(protos::GraphicsStatsProto* proto, int percentile) { + uint32_t totalGPUFrameCount = 0; // this is usually proto->summary().total_frames() - 3. + for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) { + totalGPUFrameCount += it->frame_count(); + } + int32_t pos = percentile * totalGPUFrameCount / 100; + int32_t remaining = totalGPUFrameCount - pos; + for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) { + remaining -= it->frame_count(); + if (remaining <= 0) { + return it->render_millis(); + } + } + return 0; +} + void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int fd) { // This isn't a full validation, just enough that we can deref at will if (proto->package_name().empty() || !proto->has_summary()) { @@ -255,6 +303,14 @@ void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int fd) { for (const auto& it : proto->histogram()) { dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count()); } + dprintf(fd, "\n50th gpu percentile: %dms", findGPUPercentile(proto, 50)); + dprintf(fd, "\n90th gpu percentile: %dms", findGPUPercentile(proto, 90)); + dprintf(fd, "\n95th gpu percentile: %dms", findGPUPercentile(proto, 95)); + dprintf(fd, "\n99th gpu percentile: %dms", findGPUPercentile(proto, 99)); + dprintf(fd, "\nGPU HISTOGRAM:"); + for (const auto& it : proto->gpu_histogram()) { + dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count()); + } dprintf(fd, "\n"); } diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp index bae616bbc636..17ee17d5cd1d 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.cpp +++ b/libs/hwui/surfacetexture/ImageConsumer.cpp @@ -71,13 +71,16 @@ public: void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace, GrContext* context); + void newBufferContent(GrContext* context); + private: // The only way to invoke dtor is with unref, when mUsageCount is 0. ~AutoBackendTextureRelease() {} GrBackendTexture mBackendTexture; GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; - GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx; + GrAHardwareBufferUtils::UpdateImageProc mUpdateProc; + GrAHardwareBufferUtils::TexImageCtx mImageCtx; // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs // are held by SkImages. @@ -101,7 +104,8 @@ AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, Graphic buffer->getWidth(), buffer->getHeight(), &mDeleteProc, - &mDeleteCtx, + &mUpdateProc, + &mImageCtx, createProtectedImage, backendFormat, false); @@ -123,7 +127,7 @@ void AutoBackendTextureRelease::unref(bool releaseImage) { mUsageCount--; if (mUsageCount <= 0) { if (mBackendTexture.isValid()) { - mDeleteProc(mDeleteCtx); + mDeleteProc(mImageCtx); mBackendTexture = {}; } delete this; @@ -154,6 +158,12 @@ void AutoBackendTextureRelease::makeImage(sp<GraphicBuffer>& graphicBuffer, } } +void AutoBackendTextureRelease::newBufferContent(GrContext* context) { + if (mBackendTexture.isValid()) { + mUpdateProc(mImageCtx, context); + } +} + void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace, bool forceCreate, GrContext* context) { @@ -166,6 +176,8 @@ void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer, if (!mTextureRelease) { mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get()); + } else { + mTextureRelease->newBufferContent(context); } mDataspace = dataspace; diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h index 2fdece989876..3e2a91a251f7 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -26,11 +26,6 @@ #include <gui/BufferItem.h> #include <system/graphics.h> -namespace GrAHardwareBufferUtils { -typedef void* DeleteImageCtx; -typedef void (*DeleteImageProc)(DeleteImageCtx); -} - namespace android { namespace uirenderer { diff --git a/libs/hwui/tests/scripts/skp-capture.sh b/libs/hwui/tests/scripts/skp-capture.sh index aad31fcc8eb9..4b46fbf86818 100755 --- a/libs/hwui/tests/scripts/skp-capture.sh +++ b/libs/hwui/tests/scripts/skp-capture.sh @@ -29,10 +29,14 @@ fi phase1_timeout_seconds=60 phase2_timeout_seconds=300 package="$1" -filename="$(date '+%H%M%S').skp" +extension="skp" +if (( "$2" > 1 )); then # 2nd arg is number of frames + extension="mskp" # use different extension for multi frame files. +fi +filename="$(date '+%H%M%S').${extension}" remote_path="/data/data/${package}/cache/${filename}" local_path_prefix="$(date '+%Y-%m-%d_%H%M%S')_${package}" -local_path="${local_path_prefix}.skp" +local_path="${local_path_prefix}.${extension}" enable_capture_key='debug.hwui.capture_skp_enabled' enable_capture_value=$(adb shell "getprop '${enable_capture_key}'") diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl index a5716304f0d8..8ae972bde4f9 100644 --- a/location/java/com/android/internal/location/ILocationProvider.aidl +++ b/location/java/com/android/internal/location/ILocationProvider.aidl @@ -29,10 +29,13 @@ import com.android.internal.location.ProviderRequest; */ interface ILocationProvider { + @UnsupportedAppUsage oneway void setLocationProviderManager(in ILocationProviderManager manager); + @UnsupportedAppUsage oneway void setRequest(in ProviderRequest request, in WorkSource ws); + @UnsupportedAppUsage oneway void sendExtraCommand(String command, in Bundle extras); // --- deprecated and will be removed the future --- diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 820d82dd3bd1..65d3ffc78faf 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -824,7 +824,7 @@ public final class AudioAttributes implements Parcelable { if (attributes != null) { mUsage = attributes.mUsage; mContentType = attributes.mContentType; - mFlags = attributes.mFlags; + mFlags = attributes.getAllFlags(); mMuteHapticChannels = attributes.areHapticChannelsMuted(); mTags = attributes.mTags; mBundle = attributes.mBundle; diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java index 45e49a7fb3e1..ac19bb167905 100644 --- a/media/java/android/media/AudioPortConfig.java +++ b/media/java/android/media/AudioPortConfig.java @@ -95,7 +95,6 @@ public class AudioPortConfig { /** * The gain configuration if this port supports gain control, null otherwise - * @see AudioGainConfig. */ public AudioGainConfig gain() { return mGain; diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index 1f2283c6381f..6fd3342fc84e 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -16,6 +16,7 @@ package android.media.session; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -31,6 +32,7 @@ import android.media.MediaSession2; import android.media.Session2Token; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; @@ -50,6 +52,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.Executor; /** * Provides support for interacting with {@link MediaSession media sessions} @@ -86,7 +89,7 @@ public final class MediaSessionManager { @GuardedBy("mLock") private final CallbackStub mCbStub = new CallbackStub(); @GuardedBy("mLock") - private final Map<Callback, Handler> mCallbacks = new HashMap<>(); + private final Map<Callback, Executor> mCallbacks = new HashMap<>(); @GuardedBy("mLock") private MediaSession.Token mCurMediaButtonSession; @GuardedBy("mLock") @@ -765,13 +768,16 @@ public final class MediaSessionManager { */ // TODO: Remove this method once Bluetooth app stop calling it. public void setCallback(@Nullable Callback callback, @Nullable Handler handler) { + if (handler == null) { + handler = new Handler(); + } synchronized (mLock) { if (mLegacyCallback != null) { unregisterCallback(mLegacyCallback); } mLegacyCallback = callback; if (callback != null) { - registerCallback(callback, handler); + registerCallback(new HandlerExecutor(handler), callback); } } } @@ -779,27 +785,29 @@ public final class MediaSessionManager { /** * Register a {@link Callback}. * + * @param executor The executor on which the callback should be invoked * @param callback A {@link Callback}. - * @param handler The handler on which the callback should be invoked, or {@code null} - * if the callback should be invoked on the calling thread's looper. * @hide */ @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) - public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) { + public void registerCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull Callback callback) { + if (executor == null) { + throw new NullPointerException("executor shouldn't be null"); + } if (callback == null) { throw new NullPointerException("callback shouldn't be null"); } synchronized (mLock) { try { - if (handler == null) { - handler = new Handler(); - } - mCallbacks.put(callback, handler); + mCallbacks.put(callback, executor); if (mCurMediaButtonSession != null) { - handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonSession)); + executor.execute( + () -> callback.onAddressedPlayerChanged(mCurMediaButtonSession)); } else if (mCurMediaButtonReceiver != null) { - handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver)); + executor.execute( + () -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver)); } if (mCallbacks.size() == 1) { @@ -1147,8 +1155,8 @@ public final class MediaSessionManager { public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event, MediaSession.Token sessionToken) { synchronized (mLock) { - for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) { - e.getValue().post( + for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { + e.getValue().execute( () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken)); } } @@ -1158,8 +1166,8 @@ public final class MediaSessionManager { public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event, ComponentName mediaButtonReceiver) { synchronized (mLock) { - for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) { - e.getValue().post( + for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { + e.getValue().execute( () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver)); } } @@ -1170,8 +1178,8 @@ public final class MediaSessionManager { synchronized (mLock) { mCurMediaButtonSession = sessionToken; mCurMediaButtonReceiver = null; - for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) { - e.getValue().post(() -> e.getKey().onAddressedPlayerChanged(sessionToken)); + for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { + e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(sessionToken)); } } } @@ -1182,8 +1190,8 @@ public final class MediaSessionManager { synchronized (mLock) { mCurMediaButtonSession = null; mCurMediaButtonReceiver = mediaButtonReceiver; - for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) { - e.getValue().post(() -> e.getKey().onAddressedPlayerChanged( + for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { + e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged( mediaButtonReceiver)); } } diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index 6d8b966f35d5..4a9da62f2517 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -26,6 +26,7 @@ #include <gui/IProducerListener.h> #include <gui/Surface.h> +#include <ui/PublicFormat.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_view_Surface.h> #include <android_runtime/android_hardware_HardwareBuffer.h> @@ -126,7 +127,7 @@ private: Condition mCondition; std::deque<wp<Surface>> mQueue; - static const nsecs_t kWaitDuration = 20000000; // 20 ms + static const nsecs_t kWaitDuration = 500000000; // 500 ms }; sp<DetachThread> mThread; @@ -401,8 +402,28 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje return 0; } } else { + // Set consumer buffer format to user specified format + PublicFormat publicFormat = static_cast<PublicFormat>(userFormat); + int nativeFormat = mapPublicFormatToHalFormat(publicFormat); + android_dataspace nativeDataspace = mapPublicFormatToHalDataspace(publicFormat); + res = native_window_set_buffers_format(anw.get(), nativeFormat); + if (res != OK) { + ALOGE("%s: Unable to configure consumer native buffer format to %#x", + __FUNCTION__, nativeFormat); + jniThrowRuntimeException(env, "Failed to set Surface format"); + return 0; + } + + res = native_window_set_buffers_data_space(anw.get(), nativeDataspace); + if (res != OK) { + ALOGE("%s: Unable to configure consumer dataspace %#x", + __FUNCTION__, nativeDataspace); + jniThrowRuntimeException(env, "Failed to set Surface dataspace"); + return 0; + } surfaceFormat = userFormat; } + ctx->setBufferFormat(surfaceFormat); env->SetIntField(thiz, gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat)); diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp index 357bb5e50eee..46f28152cd6d 100644 --- a/media/native/midi/amidi.cpp +++ b/media/native/midi/amidi.cpp @@ -142,7 +142,7 @@ static media_status_t AMIDI_getDeviceInfo(const AMidiDevice *device, return AMEDIA_OK; } -media_status_t AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj, +media_status_t AMIDI_API AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj, AMidiDevice** devicePtrPtr) { if (j_midiDeviceObj == nullptr) { @@ -188,7 +188,7 @@ media_status_t AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj, return AMEDIA_OK; } -media_status_t AMidiDevice_release(const AMidiDevice *device) +media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *device) { if (device == nullptr || device->midiDeviceObj == nullptr) { return AMEDIA_ERROR_INVALID_PARAMETER; @@ -217,21 +217,21 @@ media_status_t AMidiDevice_release(const AMidiDevice *device) return AMEDIA_OK; } -int32_t AMidiDevice_getType(const AMidiDevice *device) { +int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) { if (device == nullptr) { return AMEDIA_ERROR_INVALID_PARAMETER; } return device->deviceInfo.type; } -ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) { +ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) { if (device == nullptr) { return AMEDIA_ERROR_INVALID_PARAMETER; } return device->deviceInfo.inputPortCount; } -ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) { +ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) { if (device == nullptr) { return AMEDIA_ERROR_INVALID_PARAMETER; } @@ -291,7 +291,7 @@ static void AMIDI_closePort(AMIDI_Port *port) { /* * Output (receiving) API */ -media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber, +media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber, AMidiOutputPort **outOutputPortPtr) { return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outOutputPortPtr); } @@ -350,7 +350,7 @@ private: AMIDI_Port *mPort; }; -ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr, +ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr, uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *timestampPtr) { if (outputPort == nullptr || buffer == nullptr) { @@ -361,19 +361,19 @@ ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opco numBytesReceivedPtr, timestampPtr); } -void AMidiOutputPort_close(const AMidiOutputPort *outputPort) { +void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) { AMIDI_closePort((AMIDI_Port*)outputPort); } /* * Input (sending) API */ -media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber, +media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber, AMidiInputPort **outInputPortPtr) { return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)outInputPortPtr); } -void AMidiInputPort_close(const AMidiInputPort *inputPort) { +void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) { AMIDI_closePort((AMIDI_Port*)inputPort); } @@ -386,12 +386,12 @@ static ssize_t AMIDI_makeSendBuffer( return numBytes + AMIDI_PACKET_OVERHEAD; } -ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer, +ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer, size_t numBytes) { return AMidiInputPort_sendWithTimestamp(inputPort, buffer, numBytes, 0); } -ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort, +ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort, const uint8_t *data, size_t numBytes, int64_t timestamp) { if (inputPort == nullptr || data == nullptr) { return AMEDIA_ERROR_INVALID_PARAMETER; @@ -423,7 +423,7 @@ ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort, return numSent; } -media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) { +media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) { if (inputPort == nullptr) { return AMEDIA_ERROR_INVALID_PARAMETER; } diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h index 76dec0f7e723..0f930b5443e4 100644 --- a/media/native/midi/include/amidi/AMidi.h +++ b/media/native/midi/include/amidi/AMidi.h @@ -37,6 +37,8 @@ extern "C" { #endif +#define AMIDI_API __attribute__((visibility("default"))) + typedef struct AMidiDevice AMidiDevice; typedef struct AMidiInputPort AMidiInputPort; typedef struct AMidiOutputPort AMidiOutputPort; @@ -78,7 +80,7 @@ enum { * is null or already connected to a native AMidiDevice * @see AMEDIA_ERROR_UNKNOWN - an unknown error occurred. */ -media_status_t AMidiDevice_fromJava( +media_status_t AMIDI_API AMidiDevice_fromJava( JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr) __INTRODUCED_IN(29); /** @@ -93,7 +95,7 @@ media_status_t AMidiDevice_fromJava( * @see AMEDIA_ERROR_INVALID_OBJECT - the JNI interface initialization to the associated java MidiDevice failed. * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info. */ -media_status_t AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29); +media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29); /** * Gets the MIDI device type. @@ -108,7 +110,7 @@ media_status_t AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_I * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL. * @see AMEDIA_ERROR_UNKNOWN - Unknown error. */ -int32_t AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29); +int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29); /** * Gets the number of input (sending) ports available on the specified MIDI device. @@ -120,7 +122,7 @@ int32_t AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29); * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL. * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info. */ -ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29); +ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29); /** * Gets the number of output (receiving) ports available on the specified MIDI device. @@ -132,7 +134,7 @@ ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN( * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL. * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info. */ -ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29); +ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29); /* * API for receiving data from the Output port of a device. @@ -150,7 +152,7 @@ ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN * @return AMEDIA_OK, or a negative error code: * @see AMEDIA_ERROR_UNKNOWN - Unknown Error. */ -media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber, +media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber, AMidiOutputPort **outOutputPortPtr) __INTRODUCED_IN(29); /** @@ -158,7 +160,7 @@ media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumbe * * @param outputPort The native API port identifier of the port. */ -void AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29); +void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29); /** * Receives the next pending MIDI message. To retrieve all pending messages, the client should @@ -178,7 +180,7 @@ void AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29 * @return the number of messages received (either 0 or 1), or a negative error code: * @see AMEDIA_ERROR_UNKNOWN - Unknown Error. */ -ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr, +ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr, uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr) __INTRODUCED_IN(29); /* @@ -197,7 +199,7 @@ ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opco * @return AMEDIA_OK, or a negative error code: * @see AMEDIA_ERROR_UNKNOWN - Unknown Error. */ -media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber, +media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber, AMidiInputPort **outInputPortPtr) __INTRODUCED_IN(29); /** @@ -210,7 +212,7 @@ media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber * @return The number of bytes sent, which could be less than specified or a negative error code: * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL. */ -ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer, +ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer, size_t numBytes) __INTRODUCED_IN(29); /** @@ -224,7 +226,7 @@ ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buff * @return The number of bytes sent, which could be less than specified or a negative error code: * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL. */ -ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort, +ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort, const uint8_t *buffer, size_t numBytes, int64_t timestamp) __INTRODUCED_IN(29); /** @@ -238,14 +240,14 @@ ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort, * @see AMEDIA_ERROR_UNSUPPORTED - The FLUSH command couldn't * be sent. */ -media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29); +media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29); /** * Closes the input port. * * @param inputPort Identifies the input (sending) port to close. */ -void AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29); +void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29); #endif /* __ANDROID_API__ >= 29 */ diff --git a/packages/CompanionDeviceManager/OWNERS b/packages/CompanionDeviceManager/OWNERS new file mode 100644 index 000000000000..da723b3b67da --- /dev/null +++ b/packages/CompanionDeviceManager/OWNERS @@ -0,0 +1 @@ +eugenesusla@google.com
\ No newline at end of file diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index d0ca04bb07c2..d11b5c573ca9 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -24,6 +24,7 @@ import static com.android.internal.util.CollectionUtils.emptyIfNull; import static com.android.internal.util.CollectionUtils.size; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; @@ -115,7 +116,8 @@ public class DeviceDiscoveryService extends Service { } mFindCallback = findCallback; mServiceCallback = serviceCallback; - DeviceDiscoveryService.this.startDiscovery(request); + Handler.getMain().sendMessage(obtainMessage( + DeviceDiscoveryService::startDiscovery, DeviceDiscoveryService.this, request)); } }; @@ -145,6 +147,7 @@ public class DeviceDiscoveryService extends Service { sInstance = this; } + @MainThread private void startDiscovery(AssociationRequest request) { if (!request.equals(mRequest)) { mRequest = request; @@ -211,12 +214,13 @@ public class DeviceDiscoveryService extends Service { return !isEmpty(mediumSpecificFilters) || isEmpty(mFilters); } + @MainThread private void reset() { if (DEBUG) Log.i(LOG_TAG, "reset()"); stopScan(); mDevicesFound.clear(); mSelectedDevice = null; - notifyDataSetChanged(); + mDevicesAdapter.notifyDataSetChanged(); } @Override @@ -260,16 +264,17 @@ public class DeviceDiscoveryService extends Service { if (DEBUG) Log.i(LOG_TAG, "Found device " + device); + Handler.getMain().sendMessage(obtainMessage( + DeviceDiscoveryService::onDeviceFoundMainThread, this, device)); + } + + @MainThread + void onDeviceFoundMainThread(@NonNull DeviceFilterPair device) { if (mDevicesFound.isEmpty()) { onReadyToShowUI(); } mDevicesFound.add(device); - notifyDataSetChanged(); - } - - private void notifyDataSetChanged() { - Handler.getMain().sendMessage(obtainMessage( - DevicesAdapter::notifyDataSetChanged, mDevicesAdapter)); + mDevicesAdapter.notifyDataSetChanged(); } //TODO also, on timeout -> call onFailure @@ -286,9 +291,15 @@ public class DeviceDiscoveryService extends Service { } private void onDeviceLost(@Nullable DeviceFilterPair device) { - mDevicesFound.remove(device); - notifyDataSetChanged(); if (DEBUG) Log.i(LOG_TAG, "Lost device " + device.getDisplayName()); + Handler.getMain().sendMessage(obtainMessage( + DeviceDiscoveryService::onDeviceLostMainThread, this, device)); + } + + @MainThread + void onDeviceLostMainThread(@Nullable DeviceFilterPair device) { + mDevicesFound.remove(device); + mDevicesAdapter.notifyDataSetChanged(); } void onDeviceSelected(String callingPackage, String deviceAddress) { diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index b532621cd617..7760e0ef7246 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -23,6 +23,7 @@ android_library { "SettingsLibBarChartPreference", "SettingsLibProgressBar", "SettingsLibAdaptiveIcon", + "SettingsLibRadioButtonPreference", ], // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp index b56181d75e6a..b07176a064f9 100644 --- a/packages/SettingsLib/AppPreference/Android.bp +++ b/packages/SettingsLib/AppPreference/Android.bp @@ -4,9 +4,10 @@ android_library { srcs: ["src/**/*.java"], resource_dirs: ["res"], - libs: [ + static_libs: [ "androidx.annotation_annotation", "androidx.preference_preference", + "SettingsLibSettingsTheme", ], sdk_version: "system_current", min_sdk_version: "21", diff --git a/packages/SettingsLib/EntityHeaderWidgets/Android.bp b/packages/SettingsLib/EntityHeaderWidgets/Android.bp index 3ca4ecd33ce4..280848a0d7c4 100644 --- a/packages/SettingsLib/EntityHeaderWidgets/Android.bp +++ b/packages/SettingsLib/EntityHeaderWidgets/Android.bp @@ -6,7 +6,7 @@ android_library { static_libs: [ "androidx.annotation_annotation", - "SettingsLibAppPreference" + "SettingsLibSettingsTheme" ], sdk_version: "system_current", diff --git a/packages/SettingsLib/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp new file mode 100644 index 000000000000..136d6daad99a --- /dev/null +++ b/packages/SettingsLib/RadioButtonPreference/Android.bp @@ -0,0 +1,14 @@ +android_library { + name: "SettingsLibRadioButtonPreference", + + srcs: ["src/**/*.java"], + resource_dirs: ["res"], + + static_libs: [ + "androidx.preference_preference", + "SettingsLibSettingsTheme", + ], + + sdk_version: "system_current", + min_sdk_version: "21", +} diff --git a/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml b/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml new file mode 100644 index 000000000000..fda7fde29404 --- /dev/null +++ b/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.settingslib.widget"> + + <uses-sdk android:minSdkVersion="21" /> + +</manifest> diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml new file mode 100644 index 000000000000..dcb014d6ed57 --- /dev/null +++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:settings="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/selectableItemBackground" + android:gravity="center_vertical" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> + + <LinearLayout + android:id="@android:id/widget_frame" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center" + android:minWidth="56dp" + android:layout_marginEnd="16dp" + android:orientation="vertical"/> + + <LinearLayout + android:id="@+id/icon_frame" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:minWidth="32dp" + android:orientation="horizontal" + android:layout_marginEnd="16dp" + android:paddingTop="4dp" + android:paddingBottom="4dp"> + <androidx.preference.internal.PreferenceImageView + android:id="@android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + settings:maxWidth="@dimen/secondary_app_icon_size" + settings:maxHeight="@dimen/secondary_app_icon_size"/> + </LinearLayout> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + android:paddingTop="16dp" + android:paddingBottom="16dp"> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" + android:ellipsize="marquee" + android:fadingEdge="horizontal"/> + + <LinearLayout + android:id="@+id/summary_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone"> + <TextView + android:id="@android:id/summary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small" + android:textAlignment="viewStart" + android:textColor="?android:attr/textColorSecondary"/> + + <TextView + android:id="@+id/appendix" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small" + android:textAlignment="viewEnd" + android:textColor="?android:attr/textColorSecondary" + android:maxLines="1" + android:ellipsize="end"/> + </LinearLayout> + <ProgressBar + android:id="@android:id/progress" + style="?android:attr/progressBarStyleHorizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:max="100" + android:visibility="gone"/> + </LinearLayout> + +</LinearLayout> diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml new file mode 100644 index 000000000000..cb7b8eb289ea --- /dev/null +++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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. + --> + +<RadioButton xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:background="@null" + android:focusable="false" + android:clickable="false" /> diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java new file mode 100644 index 000000000000..08287ac628d5 --- /dev/null +++ b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2019 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.settingslib.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TextView; + +import androidx.core.content.res.TypedArrayUtils; +import androidx.preference.CheckBoxPreference; +import androidx.preference.PreferenceViewHolder; + +/** + * Check box preference with check box replaced by radio button. + * + * Functionally speaking, it's actually a CheckBoxPreference. We only modified + * the widget to RadioButton to make it "look like" a RadioButtonPreference. + * + * In other words, there's no "RadioButtonPreferenceGroup" in this + * implementation. When you check one RadioButtonPreference, if you want to + * uncheck all the other preferences, you should do that by code yourself. + */ +public class RadioButtonPreference extends CheckBoxPreference { + + /** + * Interface definition for a callback to be invoked when the preference is clicked. + */ + public interface OnClickListener { + /** + * Called when a preference has been clicked. + * + * @param emiter The clicked preference + */ + void onRadioButtonClicked(RadioButtonPreference emiter); + } + + private OnClickListener mListener = null; + private View mAppendix; + private int mAppendixVisibility = -1; + + + /** + * Perform inflation from XML and apply a class-specific base style. + * + * @param context The {@link Context} this is associated with, through which it can + * access the current theme, resources, {@link SharedPreferences}, etc. + * @param attrs The attributes of the XML tag that is inflating the preference + * @param defStyleAttr An attribute in the current theme that contains a reference to a style + * resource that supplies default values for the view. Can be 0 to not + * look for defaults. + */ + public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setWidgetLayoutResource(R.layout.preference_widget_radiobutton); + setLayoutResource(R.layout.preference_radio); + setIconSpaceReserved(false); + } + + + /** + * Perform inflation from XML and apply a class-specific base style. + * + * @param context The {@link Context} this is associated with, through which it can + * access the current theme, resources, {@link SharedPreferences}, etc. + * @param attrs The attributes of the XML tag that is inflating the preference + */ + public RadioButtonPreference(Context context, AttributeSet attrs) { + this(context, attrs, TypedArrayUtils.getAttr(context, + androidx.preference.R.attr.preferenceStyle, + android.R.attr.preferenceStyle)); + } + + /** + * Constructor to create a preference. + * + * @param context The Context this is associated with. + */ + public RadioButtonPreference(Context context) { + this(context, null); + } + + /** + * Sets the callback to be invoked when this preference is clicked by the user. + * + * @param listener The callback to be invoked + */ + public void setOnClickListener(OnClickListener listener) { + mListener = listener; + } + + /** + * Processes a click on the preference. + */ + @Override + public void onClick() { + if (mListener != null) { + mListener.onRadioButtonClicked(this); + } + } + + /** + * Binds the created View to the data for this preference. + * + * <p>This is a good place to grab references to custom Views in the layout and set + * properties on them. + * + * <p>Make sure to call through to the superclass's implementation. + * + * @param holder The ViewHolder that provides references to the views to fill in. These views + * will be recycled, so you should not hold a reference to them after this method + * returns. + */ + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + + View summaryContainer = holder.findViewById(R.id.summary_container); + if (summaryContainer != null) { + summaryContainer.setVisibility( + TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE); + mAppendix = holder.findViewById(R.id.appendix); + if (mAppendix != null && mAppendixVisibility != -1) { + mAppendix.setVisibility(mAppendixVisibility); + } + } + + TextView title = (TextView) holder.findViewById(android.R.id.title); + if (title != null) { + title.setSingleLine(false); + title.setMaxLines(3); + } + } + + /** + * Set the visibility state of appendix view. + * + * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}. + */ + public void setAppendixVisibility(int visibility) { + if (mAppendix != null) { + mAppendix.setVisibility(visibility); + } + mAppendixVisibility = visibility; + } +} diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp new file mode 100644 index 000000000000..6d505bf8895d --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/Android.bp @@ -0,0 +1,8 @@ +android_library { + name: "SettingsLibSettingsTheme", + + resource_dirs: ["res"], + + sdk_version: "system_current", + min_sdk_version: "21", +} diff --git a/packages/SettingsLib/SettingsTheme/AndroidManifest.xml b/packages/SettingsLib/SettingsTheme/AndroidManifest.xml new file mode 100644 index 000000000000..fda7fde29404 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.settingslib.widget"> + + <uses-sdk android:minSdkVersion="21" /> + +</manifest> diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml index e2a7a191f9de..94856552d6e2 100644 --- a/packages/SettingsLib/AppPreference/res/values/dimens.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (C) 2018 The Android Open Source Project + Copyright (C) 2019 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. @@ -17,4 +17,4 @@ <resources> <dimen name="secondary_app_icon_size">32dp</dimen> -</resources>
\ No newline at end of file +</resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java index 7100acc30646..fcd7ff81ba6f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java @@ -72,7 +72,9 @@ public class FooterPreference extends Preference { } private void init() { - setIcon(R.drawable.ic_info_outline_24); + if (getIcon() == null) { + setIcon(R.drawable.ic_info_outline_24); + } setOrder(ORDER_FOOTER); if (TextUtils.isEmpty(getKey())) { setKey(KEY_FOOTER); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 59754e007fbb..81d1ea5137e0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -1434,7 +1434,7 @@ public class AccessPoint implements Comparable<AccessPoint> { void update(@Nullable WifiConfiguration config) { mConfig = config; - if (mConfig != null) { + if (mConfig != null && !isPasspoint()) { ssid = removeDoubleQuotes(mConfig.SSID); } networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java new file mode 100644 index 000000000000..d58e68a3b387 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2019 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.settingslib.widget; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.Application; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.preference.PreferenceViewHolder; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class RadioButtonPreferenceTest { + + private Application mContext; + private RadioButtonPreference mPreference; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mPreference = new RadioButtonPreference(mContext); + } + + @Test + public void shouldHaveRadioPreferenceLayout() { + assertThat(mPreference.getLayoutResource()).isEqualTo(R.layout.preference_radio); + } + + @Test + public void iconSpaceReservedShouldBeFalse() { + assertThat(mPreference.isIconSpaceReserved()).isFalse(); + } + + @Test + public void summary_containerShouldBeVisible() { + mPreference.setSummary("some summary"); + View summaryContainer = new View(mContext); + View view = mock(View.class); + when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer); + PreferenceViewHolder preferenceViewHolder = + PreferenceViewHolder.createInstanceForTests(view); + mPreference.onBindViewHolder(preferenceViewHolder); + assertEquals(View.VISIBLE, summaryContainer.getVisibility()); + } + + @Test + public void emptySummary_containerShouldBeGone() { + mPreference.setSummary(""); + View summaryContainer = new View(mContext); + View view = mock(View.class); + when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer); + PreferenceViewHolder preferenceViewHolder = + PreferenceViewHolder.createInstanceForTests(view); + mPreference.onBindViewHolder(preferenceViewHolder); + assertEquals(View.GONE, summaryContainer.getVisibility()); + } + + @Test + public void nullSummary_containerShouldBeGone() { + mPreference.setSummary(null); + View summaryContainer = new View(mContext); + View view = mock(View.class); + when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer); + PreferenceViewHolder preferenceViewHolder = + PreferenceViewHolder.createInstanceForTests(view); + mPreference.onBindViewHolder(preferenceViewHolder); + assertEquals(View.GONE, summaryContainer.getVisibility()); + } + + @Test + public void hideAppendix_shouldBeGone() { + mPreference.setAppendixVisibility(View.GONE); + View view = LayoutInflater.from(mContext).inflate(R.layout.preference_radio, null); + PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view); + mPreference.onBindViewHolder(holder); + assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE); + } +} diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 8689eef79583..bb9a5e44f72d 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -123,7 +123,6 @@ <uses-permission android:name="android.permission.BIND_APPWIDGET" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/> - <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" /> <uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" /> <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index a7b44443fc9c..58e1d47e5379 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -199,9 +199,9 @@ public class BugreportProgressService extends Service { // Passed to Message.obtain() when msg.arg2 is not used. private static final int UNUSED_ARG2 = -2; - // Maximum progress displayed (like 99.00%). - private static final int CAPPED_PROGRESS = 9900; - private static final int CAPPED_MAX = 10000; + // Maximum progress displayed in %. + private static final int CAPPED_PROGRESS = 99; + private static final int CAPPED_MAX = 100; /** Show the progress log every this percent. */ private static final int LOG_PROGRESS_STEP = 10; @@ -366,8 +366,10 @@ public class BugreportProgressService extends Service { checkProgressUpdated(mInfo, (int) progress); } - // TODO(b/127431371): Add error code handling for bugreport API errors. - // Logging errors and removing progress notification for now. + /** + * Logs errors and stops the service on which this bugreport was running. + * Also stops progress notification (if any). + */ @Override public void onError(@BugreportErrorCode int errorCode) { trackInfoWithId(); @@ -580,9 +582,9 @@ public class BugreportProgressService extends Service { ParcelFileDescriptor screenshotFd = createReadWriteFile(BUGREPORT_DIR, bugreportName + ".png"); if (screenshotFd == null) { - Log.e(TAG, "Screenshot parcel file descriptor is null."); - // TODO(b/123617758): Delete bugreport file created above + Log.e(TAG, "Screenshot parcel file descriptor is null. Deleting bugreport file"); FileUtils.closeQuietly(bugreportFd); + new File(BUGREPORT_DIR, String.format("%s.zip", bugreportName)).delete(); return; } mBugreportManager = (BugreportManager) mContext.getSystemService( @@ -970,18 +972,8 @@ public class BugreportProgressService extends Service { private void onBugreportFinished(int id) { BugreportInfo info = getInfo(id); final File bugreportFile = new File(BUGREPORT_DIR, info.name + ".zip"); - if (bugreportFile == null) { - // Should never happen, an id always has a file linked to it. - Log.wtf(TAG, "Missing file " + bugreportFile.getPath() + " does not exist."); - return; - } final int max = -1; // this is to log metrics for dumpstate duration. File screenshotFile = new File(BUGREPORT_DIR, info.name + ".png"); - if (screenshotFile == null) { - // Should never happen, an id always has a file linked to it. - Log.wtf(TAG, "Missing file " + screenshotFile.getPath() + " does not exist."); - return; - } // If the screenshot file did not get populated implies this type of bugreport does not // need the screenshot file; setting the file to null so that empty file doesnt get shared if (screenshotFile.length() == 0) { @@ -2162,8 +2154,7 @@ public class BugreportProgressService extends Service { @Override public void onProgress(int progress) throws RemoteException { - updateProgressInfo(info, progress, 100 /* progress is already a percentage; - so max = 100 */); + checkProgressUpdated(info, progress); } @Override @@ -2176,26 +2167,6 @@ public class BugreportProgressService extends Service { // TODO(b/111441001): implement } - @Override - public void onProgressUpdated(int progress) throws RemoteException { - checkProgressUpdated(info, progress); - } - - @Override - public void onMaxProgressUpdated(int maxProgress) throws RemoteException { - Log.d(TAG, "onMaxProgressUpdated: " + maxProgress); - info.realMax = maxProgress; - } - - @Override - public void onSectionComplete(String title, int status, int size, int durationMs) - throws RemoteException { - if (DEBUG) { - Log.v(TAG, "Title: " + title + " Status: " + status + " Size: " + size - + " Duration: " + durationMs + "ms"); - } - } - public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("token: "); pw.println(token); } @@ -2203,27 +2174,10 @@ public class BugreportProgressService extends Service { } private void checkProgressUpdated(BugreportInfo info, int progress) { - /* - * Checks whether the progress changed in a way that should be displayed to the user: - * - info.progress / info.max represents the displayed progress - * - info.realProgress / info.realMax represents the real progress - * - since the real progress can decrease, the displayed progress is only updated if it - * increases - * - the displayed progress is capped at a maximum (like 99%) - */ - info.realProgress = progress; - final int oldPercentage = (CAPPED_MAX * info.progress) / info.max; - int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax; - int max = info.realMax; - - if (newPercentage > CAPPED_PROGRESS) { - progress = newPercentage = CAPPED_PROGRESS; - max = CAPPED_MAX; - } - - if (progress == 0 || newPercentage > oldPercentage) { - updateProgressInfo(info, progress, max); + if (progress > CAPPED_PROGRESS) { + progress = CAPPED_PROGRESS; } + updateProgressInfo(info, progress, CAPPED_MAX); } private void updateProgressInfo(BugreportInfo info, int progress, int max) { diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 21c2c6b879f8..1bfc4c05c92c 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -24,48 +24,7 @@ android:outlineProvider="none" android:elevation="5dp" > <!-- Put it above the status bar header --> - <LinearLayout - android:id="@+id/keyguard_indication_area" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom" - android:layout_gravity="bottom|center_horizontal" - android:orientation="horizontal"> - - <include layout="@layout/left_docked_overlay" /> - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_gravity="center_vertical|center_horizontal" - android:orientation="vertical"> - - <com.android.systemui.statusbar.phone.KeyguardIndicationTextView - android:id="@+id/keyguard_indication_enterprise_disclosure" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:paddingStart="@dimen/keyguard_indication_text_padding" - android:paddingEnd="@dimen/keyguard_indication_text_padding" - android:textAppearance="@style/TextAppearance.Keyguard.BottomArea" - android:visibility="gone" /> - - <com.android.systemui.statusbar.phone.KeyguardIndicationTextView - android:id="@+id/keyguard_indication_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:paddingStart="@dimen/keyguard_indication_text_padding" - android:paddingEnd="@dimen/keyguard_indication_text_padding" - android:textAppearance="@style/TextAppearance.Keyguard.BottomArea" - android:accessibilityLiveRegion="polite" /> - - </LinearLayout> - - <include layout="@layout/right_docked_overlay" /> - - </LinearLayout> + <include layout="@layout/keyguard_indication_area_overlay" /> <FrameLayout android:id="@+id/preview_container" diff --git a/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml new file mode 100644 index 000000000000..cc30a682757c --- /dev/null +++ b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/keyguard_indication_area" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom" + android:layout_gravity="bottom|center_horizontal" + android:orientation="vertical"> + + <include layout="@layout/keyguard_indication_text_view" /> + +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/keyguard_indication_text_view.xml b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml new file mode 100644 index 000000000000..2b2100c850d8 --- /dev/null +++ b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + + <com.android.systemui.statusbar.phone.KeyguardIndicationTextView + android:id="@+id/keyguard_indication_enterprise_disclosure" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingStart="@dimen/keyguard_indication_text_padding" + android:paddingEnd="@dimen/keyguard_indication_text_padding" + android:textAppearance="@style/TextAppearance.Keyguard.BottomArea" + android:visibility="gone"/> + + <com.android.systemui.statusbar.phone.KeyguardIndicationTextView + android:id="@+id/keyguard_indication_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingStart="@dimen/keyguard_indication_text_padding" + android:paddingEnd="@dimen/keyguard_indication_text_padding" + android:textAppearance="@style/TextAppearance.Keyguard.BottomArea" + android:accessibilityLiveRegion="polite"/> +</merge>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/left_docked_overlay.xml b/packages/SystemUI/res/layout/left_docked_overlay.xml deleted file mode 100644 index 430143ca3bc2..000000000000 --- a/packages/SystemUI/res/layout/left_docked_overlay.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 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. - --> - -<!-- empty stub --> -<merge /> diff --git a/packages/SystemUI/res/layout/right_docked_overlay.xml b/packages/SystemUI/res/layout/right_docked_overlay.xml deleted file mode 100644 index 430143ca3bc2..000000000000 --- a/packages/SystemUI/res/layout/right_docked_overlay.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 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. - --> - -<!-- empty stub --> -<merge /> diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 4fae3c500a45..76c1045ef1dd 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -42,6 +42,32 @@ android:visibility="gone" /> + <LinearLayout + android:id="@+id/divider_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:background="@color/transparent" > + + <android.widget.Space + android:layout_height="match_parent" + android:layout_width="0dp" + android:layout_weight="@integer/qqs_split_fraction" /> + + <com.android.systemui.DarkReceiverImpl + android:id="@+id/divider" + android:layout_height="match_parent" + android:layout_width="1dp" + android:layout_marginTop="4dp" + android:layout_marginBottom="4dp" /> + + <android.widget.Space + android:layout_height="match_parent" + android:layout_width="0dp" + android:layout_weight="@integer/qs_split_fraction" /> + + </LinearLayout> + <LinearLayout android:id="@+id/status_bar_contents" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 861187fded15..340cb3ad7358 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -482,4 +482,7 @@ --> <string name="config_rounded_mask" translatable="false">"M8,0C3.6,0,0,3.6,0,8"</string> + <!-- Preferred refresh rate at keyguard, if supported by the display --> + <integer name="config_keyguardRefreshRate">-1</integer> + </resources> diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index a6dae45f4b53..deae7e2c181c 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -27,4 +27,9 @@ performance issues arise. --> <integer name="bubbles_max_rendered">5</integer> + <!-- Ratio of "left" end of status bar that will swipe to QQS. --> + <integer name="qqs_split_fraction">3</integer> + <!-- Ratio of "right" end of status bar that will swipe to QS. --> + <integer name="qs_split_fraction">2</integer> + </resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7feacb469f81..fab724267e3f 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -958,6 +958,9 @@ <!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] --> <string name="keyguard_unlock">Swipe up to open</string> + <!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] --> + <string name="keyguard_retry">Swipe up to try again</string> + <!-- Text on keyguard screen and in Quick Settings footer indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] --> <string name="do_disclosure_generic">This device is managed by your organization</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java index 342cb75b2c14..8a244bf81c7c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java @@ -21,6 +21,9 @@ import android.util.SparseArray; import com.android.systemui.shared.recents.model.Task.TaskKey; +import java.util.ArrayList; +import java.util.Collection; + /** * Base class for both strong and LRU task key cache. */ @@ -76,6 +79,15 @@ public abstract class TaskKeyCache<V> { mKeys.remove(key.id); } + /** @return {@link Collection} of {@link TaskKey} */ + public Collection<TaskKey> getValues() { + Collection<TaskKey> result = new ArrayList<>(mKeys.size()); + for (int i = 0; i < mKeys.size(); i++) { + result.add(mKeys.valueAt(i)); + } + return result; + } + /** Removes all the entries in the cache. */ public final synchronized void evictAll() { evictAllCache(); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 328116dc3c1b..13fc702aa0a0 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -236,7 +236,8 @@ public class ActivityManagerWrapper { @Override public void onAnimationCanceled(boolean deferredWithScreenshot) { - animationHandler.onAnimationCanceled(deferredWithScreenshot); + animationHandler.onAnimationCanceled( + deferredWithScreenshot ? new ThumbnailData() : null); } }; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java index 5850fda617fc..579858a4f9b4 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java @@ -18,6 +18,8 @@ package com.android.systemui.shared.system; import android.graphics.Rect; +import com.android.systemui.shared.recents.model.ThumbnailData; + public interface RecentsAnimationListener { /** @@ -29,5 +31,5 @@ public interface RecentsAnimationListener { /** * Called when the animation into Recents was canceled. This call is made on the binder thread. */ - void onAnimationCanceled(boolean deferredWithScreenshot); + void onAnimationCanceled(ThumbnailData thumbnailData); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java index 9fdecfbd44a0..aeb0415c8c4c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java @@ -34,9 +34,11 @@ public abstract class SystemGestureExclusionListenerCompat { new ISystemGestureExclusionListener.Stub() { @Override public void onSystemGestureExclusionChanged(int displayId, - Region systemGestureExclusion) { + Region systemGestureExclusion, Region unrestrictedOrNull) { if (displayId == mDisplayId) { - onExclusionChanged(systemGestureExclusion); + Region unrestricted = (unrestrictedOrNull == null) + ? systemGestureExclusion : unrestrictedOrNull; + onExclusionChanged(systemGestureExclusion, unrestricted); } } }; @@ -47,11 +49,29 @@ public abstract class SystemGestureExclusionListenerCompat { } /** - * Called when the exclusion region has changed + * Called when the exclusion region has changed. + * + * TODO: remove, once all subclasses have migrated to + * {@link #onExclusionChanged(Region, Region)}. */ public abstract void onExclusionChanged(Region systemGestureExclusion); /** + * Called when the exclusion region has changed. + * + * @param systemGestureExclusion the system gesture exclusion to be applied + * @param systemGestureExclusionUnrestricted what would be the system gesture exclusion, if + * there were no restrictions being applied. For logging purposes only. + * + */ + public void onExclusionChanged(Region systemGestureExclusion, + Region systemGestureExclusionUnrestricted) { + // TODO: make abstract, once all subclasses have migrated away from + // onExclusionChanged(Region) + onExclusionChanged(systemGestureExclusion); + } + + /** * Registers the listener for getting exclusion rect changes. */ public void register() { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java index c215d0fc13d6..77571613f6af 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java @@ -95,6 +95,11 @@ public abstract class TaskStackChangeListener { public void onTaskDisplayChanged(int taskId, int newDisplayId) { } /** + * Called when any additions or deletions to the recent tasks list have been made. + */ + public void onRecentTaskListUpdated() { } + + /** * Checks that the current user matches the process. Since * {@link android.app.ITaskStackListener} is not multi-user aware, handlers of * {@link TaskStackChangeListener} should make this call to verify that we don't act on events diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java index d570a586f961..a7f4396fabed 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java @@ -213,6 +213,11 @@ public class TaskStackChangeListeners extends TaskStackListener { mHandler.obtainMessage(H.ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget(); } + @Override + public void onRecentTaskListUpdated() throws RemoteException { + mHandler.obtainMessage(H.ON_TASK_LIST_UPDATED).sendToTarget(); + } + private final class H extends Handler { private static final int ON_TASK_STACK_CHANGED = 1; private static final int ON_TASK_SNAPSHOT_CHANGED = 2; @@ -234,6 +239,7 @@ public class TaskStackChangeListeners extends TaskStackListener { private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18; private static final int ON_SINGLE_TASK_DISPLAY_DRAWN = 19; private static final int ON_TASK_DISPLAY_CHANGED = 20; + private static final int ON_TASK_LIST_UPDATED = 21; public H(Looper looper) { @@ -382,6 +388,12 @@ public class TaskStackChangeListeners extends TaskStackListener { } break; } + case ON_TASK_LIST_UPDATED: { + for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { + mTaskStackListeners.get(i).onRecentTaskListUpdated(); + } + break; + } } } } diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 11d093f22840..10d132ad2763 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -400,8 +400,11 @@ public class CarrierTextController { } } + if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames); + displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, allSimsMissing); + boolean airplaneMode = false; // APM (airplane mode) != no carrier state. There are carrier services // (e.g. WFC = Wi-Fi calling) which may operate in APM. @@ -410,9 +413,6 @@ public class CarrierTextController { airplaneMode = true; } - if (TextUtils.isEmpty(displayText) && !airplaneMode) { - displayText = joinNotEmpty(mSeparator, carrierNames); - } final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( displayText, carrierNames, diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java index fb3a586677aa..69da990a0a73 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java @@ -123,7 +123,7 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg); } - if (mSecurityMessageDisplay != null) { + if (mSecurityMessageDisplay != null && getVisibility() == VISIBLE) { mSecurityMessageDisplay.setMessage(msg); } mSimImageView.setImageTintList(ColorStateList.valueOf(color)); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 4e7b15715243..6a54782225e7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -182,6 +182,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2; private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000; + /** + * If no cancel signal has been received after this amount of time, set the biometric running + * state to stopped to allow Keyguard to retry authentication. + */ + private static final int DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000; private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName( "com.android.settings", "com.android.settings.FallbackHome"); @@ -264,11 +269,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { */ private static final int BIOMETRIC_CONTINUE_DELAY_MS = 500; - // If FP daemon dies, keyguard should retry after a short delay + // If the HAL dies or is unable to authenticate, keyguard should retry after a short delay private int mHardwareFingerprintUnavailableRetryCount = 0; private int mHardwareFaceUnavailableRetryCount = 0; - private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms - private static final int HW_UNAVAILABLE_RETRY_MAX = 3; + private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms + private static final int HAL_ERROR_RETRY_MAX = 10; + + private final Runnable mCancelNotReceived = new Runnable() { + @Override + public void run() { + Log.w(TAG, "Cancel not received, transitioning to STOPPED"); + mFingerprintRunningState = mFaceRunningState = BIOMETRIC_STATE_STOPPED; + updateBiometricListeningState(); + } + }; private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override @@ -662,6 +676,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { }; private void handleFingerprintError(int msgId, String errString) { + if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED && mHandler.hasCallbacks( + mCancelNotReceived)) { + mHandler.removeCallbacks(mCancelNotReceived); + } + if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED && mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) { setFingerprintRunningState(BIOMETRIC_STATE_STOPPED); @@ -671,10 +690,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) { - if (mHardwareFingerprintUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) { + if (mHardwareFingerprintUnavailableRetryCount < HAL_ERROR_RETRY_MAX) { mHardwareFingerprintUnavailableRetryCount++; mHandler.removeCallbacks(mRetryFingerprintAuthentication); - mHandler.postDelayed(mRetryFingerprintAuthentication, HW_UNAVAILABLE_TIMEOUT); + mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT); } } @@ -822,6 +841,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private void handleFaceError(int msgId, String errString) { if (DEBUG_FACE) Log.d(TAG, "Face error received: " + errString); + if (msgId == FaceManager.FACE_ERROR_CANCELED && mHandler.hasCallbacks(mCancelNotReceived)) { + mHandler.removeCallbacks(mCancelNotReceived); + } + if (msgId == FaceManager.FACE_ERROR_CANCELED && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) { setFaceRunningState(BIOMETRIC_STATE_STOPPED); @@ -830,11 +853,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { setFaceRunningState(BIOMETRIC_STATE_STOPPED); } - if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE) { - if (mHardwareFaceUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) { + if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE + || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) { + if (mHardwareFaceUnavailableRetryCount < HAL_ERROR_RETRY_MAX) { mHardwareFaceUnavailableRetryCount++; mHandler.removeCallbacks(mRetryFaceAuthentication); - mHandler.postDelayed(mRetryFaceAuthentication, HW_UNAVAILABLE_TIMEOUT); + mHandler.postDelayed(mRetryFaceAuthentication, HAL_ERROR_RETRY_TIMEOUT); } } @@ -843,11 +867,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { getCurrentUser()); } - // The face timeout message is not very actionable, let's ask the user to - // manually retry. - if (msgId == FaceManager.FACE_ERROR_TIMEOUT) { - errString = mContext.getString(R.string.keyguard_unlock); - } for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1802,6 +1821,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { if (mFingerprintCancelSignal != null) { mFingerprintCancelSignal.cancel(); mFingerprintCancelSignal = null; + if (!mHandler.hasCallbacks(mCancelNotReceived)) { + mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT); + } } setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING); } @@ -1816,6 +1838,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { if (mFaceCancelSignal != null) { mFaceCancelSignal.cancel(); mFaceCancelSignal = null; + if (!mHandler.hasCallbacks(mCancelNotReceived)) { + mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT); + } } setFaceRunningState(BIOMETRIC_STATE_CANCELLING); } diff --git a/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt b/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt new file mode 100644 index 000000000000..42d38cb3463c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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.systemui + +import android.content.Context +import android.graphics.Rect +import android.util.AttributeSet +import android.view.View +import com.android.systemui.plugins.DarkIconDispatcher + +class DarkReceiverImpl @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0, + defStyleRes: Int = 0 +) : View(context, attrs, defStyle, defStyleRes), DarkIconDispatcher.DarkReceiver { + + private val dualToneHandler = DualToneHandler(context) + + init { + onDarkChanged(Rect(), 1f, DarkIconDispatcher.DEFAULT_ICON_TINT) + } + + override fun onDarkChanged(area: Rect?, darkIntensity: Float, tint: Int) { + val intensity = if (DarkIconDispatcher.isInArea(area, this)) darkIntensity else 0f + setBackgroundColor(dualToneHandler.getSingleColor(intensity)) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java index 75956545432e..0cee030015a2 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java @@ -74,6 +74,7 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac private boolean mHandlesShowing = false; private long mHandlesLastHiddenAt; + private long mShowAndGoEndsAt; /** * This should always be initialized as {@link AssistHandleBehavior#OFF} to ensure proper * behavior lifecycle. @@ -144,7 +145,9 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac private void showAndGoInternal() { maybeShowHandles(/* ignoreThreshold = */ false); - mHandler.postDelayed(mHideHandles, getShowAndGoDuration()); + long showAndGoDuration = getShowAndGoDuration(); + mShowAndGoEndsAt = SystemClock.elapsedRealtime() + showAndGoDuration; + mHandler.postDelayed(mHideHandles, showAndGoDuration); } @Override // AssistHandleCallbacks @@ -162,6 +165,10 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac mHandler.post(() -> maybeShowHandles(/* ignoreThreshold = */ true)); } + public long getShowAndGoRemainingTimeMs() { + return Long.max(mShowAndGoEndsAt - SystemClock.elapsedRealtime(), 0); + } + boolean areHandlesShowing() { return mHandlesShowing; } @@ -271,6 +278,7 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac private void clearPendingCommands() { mHandler.removeCallbacks(mHideHandles); mHandler.removeCallbacks(mShowAndGo); + mShowAndGoEndsAt = 0; } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 97b6e7c58440..4a4feada3c65 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -82,7 +82,7 @@ public class AssistManager implements ConfigurationChangedReceiver { void processBundle(Bundle hints); /** - * Hides the UI. + * Hides any SysUI for the assistant, but _does not_ close the assistant itself. */ void hide(); } @@ -440,6 +440,10 @@ public class AssistManager implements ConfigurationChangedReceiver { mAssistUtils.onLockscreenShown(); } + public long getAssistHandleShowAndGoRemainingDurationMs() { + return mHandleController.getShowAndGoRemainingTimeMs(); + } + /** Returns the logging flags for the given Assistant invocation type. */ public int toLoggingSubType(int invocationType) { return toLoggingSubType(invocationType, mPhoneStateMonitor.getPhoneState()); diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java index 662de3a5b5f5..0c4f05123c79 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java @@ -118,7 +118,6 @@ public class DefaultUiController implements AssistManager.UiController { @Override // AssistManager.UiController public void hide() { - Dependency.get(AssistManager.class).hideAssist(); detach(); if (mInvocationAnimator.isRunning()) { mInvocationAnimator.cancel(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 923ca20b3925..de08a8c9c1b3 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -182,7 +182,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */, true /* singleTaskInstance */); - + // Set ActivityView's alpha value as zero, since there is no view content to be shown. setContentVisibility(false); addView(mActivityView); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 9bca3c7382ca..c09e28426072 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -261,6 +261,12 @@ public class DozeLog { + state + " blocked=" + blocked); } + public static void tracePulseDropped(Context context, String why) { + if (!ENABLED) return; + init(context); + log("pulseDropped why=" + why); + } + public static void tracePulseTouchDisabledByProx(Context context, boolean disabled) { if (!ENABLED) return; init(context); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 2ca85c074a89..310f04abc36c 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -113,11 +113,13 @@ public class DozeTriggers implements DozeMachine.Part { if (!sWakeDisplaySensorState) { Log.d(TAG, "Wake display false. Pulse denied."); runIfNotNull(onPulseSuppressedListener); + DozeLog.tracePulseDropped(mContext, "wakeDisplaySensor"); return; } mNotificationPulseTime = SystemClock.elapsedRealtime(); if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) { runIfNotNull(onPulseSuppressedListener); + DozeLog.tracePulseDropped(mContext, "pulseOnNotificationsDisabled"); return; } requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */, @@ -376,6 +378,7 @@ public class DozeTriggers implements DozeMachine.Part { proximityCheckThenCall((result) -> { if (result == ProximityCheck.RESULT_NEAR) { // in pocket, abort pulse + DozeLog.tracePulseDropped(mContext, "inPocket"); mPulsePending = false; runIfNotNull(onPulseSuppressedListener); } else { diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index df3f36e0291b..3f598ffad709 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -95,6 +95,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.plugins.GlobalActionsPanelPlugin; import com.android.systemui.statusbar.phone.ScrimController; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.phone.UnlockMethodCache; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.EmergencyDialerConstants; @@ -1523,6 +1524,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean mShowing; private float mScrimAlpha; private ResetOrientationData mResetOrientationData; + private boolean mHadTopUi; + private final StatusBarWindowController mStatusBarWindowController; ActionsDialog(Context context, MyAdapter adapter, GlobalActionsPanelPlugin.PanelViewController plugin) { @@ -1531,6 +1534,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mAdapter = adapter; mColorExtractor = Dependency.get(SysuiColorExtractor.class); mStatusBarService = Dependency.get(IStatusBarService.class); + mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); // Window initialization Window window = getWindow(); @@ -1706,6 +1710,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, public void show() { super.show(); mShowing = true; + mHadTopUi = mStatusBarWindowController.getForceHasTopUi(); + mStatusBarWindowController.setForceHasTopUi(true); mBackgroundDrawable.setAlpha(0); mGlobalActionsLayout.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX()); mGlobalActionsLayout.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY()); @@ -1738,7 +1744,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, .translationX(mGlobalActionsLayout.getAnimationOffsetX()) .translationY(mGlobalActionsLayout.getAnimationOffsetY()) .setDuration(300) - .withEndAction(super::dismiss) + .withEndAction(this::completeDismiss) .setInterpolator(new LogAccelerateInterpolator()) .setUpdateListener(animation -> { int alpha = (int) ((1f - (Float) animation.getAnimatedValue()) @@ -1751,10 +1757,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } void dismissImmediately() { - super.dismiss(); mShowing = false; dismissPanel(); resetOrientation(); + completeDismiss(); + } + + private void completeDismiss() { + mStatusBarWindowController.setForceHasTopUi(mHadTopUi); + super.dismiss(); } private void dismissPanel() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 6b2721a8440e..36c3cc68be85 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -90,6 +90,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; @@ -204,6 +205,8 @@ public class KeyguardViewMediator extends SystemUI { private AlarmManager mAlarmManager; private AudioManager mAudioManager; private StatusBarManager mStatusBarManager; + private final StatusBarWindowController mStatusBarWindowController = + Dependency.get(StatusBarWindowController.class); private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class); private boolean mSystemReady; @@ -1779,6 +1782,7 @@ public class KeyguardViewMediator extends SystemUI { adjustStatusBarLocked(); userActivity(); mUpdateMonitor.setKeyguardGoingAway(false /* away */); + mStatusBarWindowController.setKeyguardGoingAway(false /* goingAway */); mShowKeyguardWakeLock.release(); } mKeyguardDisplayManager.show(); @@ -1811,6 +1815,7 @@ public class KeyguardViewMediator extends SystemUI { } mUpdateMonitor.setKeyguardGoingAway(true /* goingAway */); + mStatusBarWindowController.setKeyguardGoingAway(true /* goingAway */); // Don't actually hide the Keyguard at the moment, wait for window // manager until it tells us it's safe to do so with diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index fb8b6c76a35f..75dc39722bcf 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -64,6 +64,8 @@ public class PowerUI extends SystemUI { private static final int CHARGE_CYCLE_PERCENT_RESET = 45; private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis(); public static final int NO_ESTIMATE_AVAILABLE = -1; + private static final String BOOT_COUNT_KEY = "boot_count"; + private static final String PREFS = "powerui_prefs"; private final Handler mHandler = new Handler(); @VisibleForTesting @@ -118,7 +120,7 @@ public class PowerUI extends SystemUI { // Check to see if we need to let the user know that the phone previously shut down due // to the temperature being too high. - showThermalShutdownDialog(); + showWarnOnThermalShutdown(); // Register an observer to configure mEnableSkinTemperatureWarning and perform the // registration of skin thermal event listener upon Settings change. @@ -542,10 +544,23 @@ public class PowerUI extends SystemUI { } } - private void showThermalShutdownDialog() { - if (mPowerManager.getLastShutdownReason() - == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) { - mWarnings.showThermalShutdownWarning(); + private void showWarnOnThermalShutdown() { + int bootCount = -1; + int lastReboot = mContext.getSharedPreferences(PREFS, 0).getInt(BOOT_COUNT_KEY, -1); + try { + bootCount = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.BOOT_COUNT); + } catch (Settings.SettingNotFoundException e) { + Slog.e(TAG, "Failed to read system boot count from Settings.Global.BOOT_COUNT"); + } + // Only show the thermal shutdown warning when there is a thermal reboot. + if (bootCount > lastReboot) { + mContext.getSharedPreferences(PREFS, 0).edit().putInt(BOOT_COUNT_KEY, + bootCount).apply(); + if (mPowerManager.getLastShutdownReason() + == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) { + mWarnings.showThermalShutdownWarning(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 20069ead5e8d..4de42cc2e6c7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -40,8 +40,10 @@ import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; +import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.SignalTileView; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.NetworkController; @@ -78,6 +80,11 @@ public class CellularTile extends QSTileImpl<SignalState> { } @Override + public QSIconView createTileView(Context context) { + return new SignalTileView(context); + } + + @Override public DetailAdapter getDetailAdapter() { return mDetailAdapter; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 19edc94a3871..16f0b15be24c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -546,7 +546,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis navBarFragment.updateSystemUiStateFlags(-1); } if (navBarView != null) { - navBarView.updateSystemUiStateFlags(); + navBarView.updatePanelSystemUiStateFlags(); + navBarView.updateDisabledSystemUiStateFlags(); } if (mStatusBarWinController != null) { mStatusBarWinController.notifyStateChangedCallbacks(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 6329af56077b..fa0fe136b8eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -43,7 +43,6 @@ import android.os.Looper; import android.os.Message; import android.util.Pair; import android.util.SparseArray; -import android.view.inputmethod.InputMethodSystemProperty; import androidx.annotation.VisibleForTesting; @@ -481,7 +480,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, - boolean showImeSwitcher) { + boolean showImeSwitcher, boolean isMultiClientImeEnabled) { synchronized (mLock) { mHandler.removeMessages(MSG_SHOW_IME_BUTTON); SomeArgs args = SomeArgs.obtain(); @@ -489,6 +488,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.argi2 = vis; args.argi3 = backDisposition; args.argi4 = showImeSwitcher ? 1 : 0; + args.argi5 = isMultiClientImeEnabled ? 1 : 0; args.arg1 = token; Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, args); m.sendToTarget(); @@ -801,11 +801,10 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition, - boolean showImeSwitcher) { + boolean showImeSwitcher, boolean isMultiClientImeEnabled) { if (displayId == INVALID_DISPLAY) return; - if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED - && mLastUpdatedImeDisplayId != displayId + if (!isMultiClientImeEnabled && mLastUpdatedImeDisplayId != displayId && mLastUpdatedImeDisplayId != INVALID_DISPLAY) { // Set previous NavBar's IME window status as invisible when IME // window switched to another display for single-session IME case. @@ -891,7 +890,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args = (SomeArgs) msg.obj; handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */, args.argi2 /* vis */, args.argi3 /* backDisposition */, - args.argi4 != 0 /* showImeSwitcher */); + args.argi4 != 0 /* showImeSwitcher */, + args.argi5 != 0 /* isMultiClientImeEnabled */); break; case MSG_SHOW_RECENT_APPS: for (int i = 0; i < mCallbacks.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index d93982889655..5adee40613e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -92,7 +92,7 @@ public class DragDownHelper implements Gefingerpoken { mInitialTouchY = y; mInitialTouchX = x; mDragDownCallback.onTouchSlopExceeded(); - return true; + return mStartingChild != null || mDragDownCallback.isDragDownAnywhereEnabled(); } break; } @@ -162,7 +162,11 @@ public class DragDownHelper implements Gefingerpoken { if (mStartingChild == null) { mStartingChild = findView(x, y); if (mStartingChild != null) { - mCallback.setUserLockedChild(mStartingChild, true); + if (mDragDownCallback.isDragDownEnabledForView(mStartingChild)) { + mCallback.setUserLockedChild(mStartingChild, true); + } else { + mStartingChild = null; + } } } } @@ -237,6 +241,10 @@ public class DragDownHelper implements Gefingerpoken { return mDraggingDown; } + public boolean isDragDownEnabled() { + return mDragDownCallback.isDragDownEnabledForView(null); + } + public interface DragDownCallback { /** @@ -253,5 +261,16 @@ public class DragDownHelper implements Gefingerpoken { void onTouchSlopExceeded(); void setEmptyDragAmount(float amount); boolean isFalsingCheckNeeded(); + + /** + * Is dragging down enabled on a given view + * @param view The view to check or {@code null} to check if it's enabled at all + */ + boolean isDragDownEnabledForView(ExpandableView view); + + /** + * @return if drag down is enabled anywhere, not just on selected views. + */ + boolean isDragDownAnywhereEnabled(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 4be93df0e81a..bba64d96c0f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -562,11 +562,11 @@ public class KeyguardIndicationController implements StateListener, return; } - String message = mContext.getString(R.string.keyguard_unlock); if (mStatusBarKeyguardViewManager.isBouncerShowing()) { + String message = mContext.getString(R.string.keyguard_retry); mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState); } else if (mKeyguardUpdateMonitor.isScreenOn()) { - showTransientIndication(message); + showTransientIndication(mContext.getString(R.string.keyguard_unlock)); hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS); } } @@ -676,7 +676,11 @@ public class KeyguardIndicationController implements StateListener, return; } animatePadlockError(); - if (mStatusBarKeyguardViewManager.isBouncerShowing()) { + if (msgId == FaceManager.FACE_ERROR_TIMEOUT) { + // The face timeout message is not very actionable, let's ask the user to + // manually retry. + showSwipeUpToUnlock(); + } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState); } else if (updateMonitor.isScreenOn()) { showTransientIndication(errString); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java index f34b912a255c..3cb2a2aaeec7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java @@ -63,11 +63,6 @@ public interface NotificationPresenter extends ExpandableNotificationRow.OnExpan int getMaxNotificationsWhileLocked(boolean recompute); /** - * True if the presenter is currently locked. - */ - boolean isPresenterLocked(); - - /** * Called when the row states are updated by {@link NotificationViewHierarchyManager}. */ void onUpdateRowStates(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java index 16bd884fcc58..d9328fa3affd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java @@ -20,8 +20,12 @@ import android.content.Context; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.UnlockMethodCache; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import javax.inject.Inject; import javax.inject.Singleton; @@ -34,22 +38,33 @@ public class DynamicPrivacyController implements UnlockMethodCache.OnUnlockMetho private final UnlockMethodCache mUnlockMethodCache; private final NotificationLockscreenUserManager mLockscreenUserManager; + private final StatusBarStateController mStateController; + private final KeyguardMonitor mKeyguardMonitor; private ArraySet<Listener> mListeners = new ArraySet<>(); private boolean mLastDynamicUnlocked; private boolean mCacheInvalid; + private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Inject DynamicPrivacyController(Context context, - NotificationLockscreenUserManager notificationLockscreenUserManager) { - this(notificationLockscreenUserManager, UnlockMethodCache.getInstance(context)); + KeyguardMonitor keyguardMonitor, + NotificationLockscreenUserManager notificationLockscreenUserManager, + StatusBarStateController stateController) { + this(notificationLockscreenUserManager, keyguardMonitor, + UnlockMethodCache.getInstance(context), + stateController); } @VisibleForTesting DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager, - UnlockMethodCache unlockMethodCache) { + KeyguardMonitor keyguardMonitor, + UnlockMethodCache unlockMethodCache, + StatusBarStateController stateController) { mLockscreenUserManager = notificationLockscreenUserManager; + mStateController = stateController; mUnlockMethodCache = unlockMethodCache; + mKeyguardMonitor = keyguardMonitor; mUnlockMethodCache.addListener(this); mLastDynamicUnlocked = isDynamicallyUnlocked(); } @@ -77,13 +92,39 @@ public class DynamicPrivacyController implements UnlockMethodCache.OnUnlockMetho } public boolean isDynamicallyUnlocked() { - return mUnlockMethodCache.canSkipBouncer() && isDynamicPrivacyEnabled(); + return (mUnlockMethodCache.canSkipBouncer() || mKeyguardMonitor.isKeyguardGoingAway() + || mKeyguardMonitor.isKeyguardFadingAway()) + && isDynamicPrivacyEnabled(); } public void addListener(Listener listener) { mListeners.add(listener); } + /** + * Is the notification shade currently in a locked down mode where it's fully showing but the + * contents aren't revealed yet? + */ + public boolean isInLockedDownShade() { + if (!mStatusBarKeyguardViewManager.isShowing() + || !mStatusBarKeyguardViewManager.isSecure()) { + return false; + } + int state = mStateController.getState(); + if (state != StatusBarState.SHADE && state != StatusBarState.SHADE_LOCKED) { + return false; + } + if (!isDynamicPrivacyEnabled() || isDynamicallyUnlocked()) { + return false; + } + return true; + } + + public void setStatusBarKeyguardViewManager( + StatusBarKeyguardViewManager statusBarKeyguardViewManager) { + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; + } + public interface Listener { void onDynamicPrivacyChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java index c67512c11922..f3201ec73d63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java @@ -54,7 +54,6 @@ import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.SystemUI; import com.android.systemui.UiOffloadThread; -import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.util.NotificationChannels; @@ -138,15 +137,6 @@ public class InstantAppNotifier extends SystemUI } }; - private final TaskStackChangeListener mTaskListener = - new TaskStackChangeListener() { - @Override - public void onTaskStackChanged() { - // Listen for changes to stacks and then check which instant apps are - // foreground. - updateForegroundInstantApps(); - } - }; private void updateForegroundInstantApps() { NotificationManager noMan = mContext.getSystemService(NotificationManager.class); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java index 5bab0ef39326..4fc646119261 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java @@ -23,7 +23,6 @@ import android.app.NotificationManager; import android.content.Context; import android.database.ContentObserver; import android.hardware.display.AmbientDisplayConfiguration; -import android.os.Bundle; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; @@ -32,7 +31,6 @@ import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.service.notification.StatusBarNotification; -import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -51,6 +49,7 @@ public class NotificationInterruptionStateProvider { private static final String TAG = "InterruptionStateProvider"; private static final boolean DEBUG = false; + private static final boolean DEBUG_HEADS_UP = true; private static final boolean ENABLE_HEADS_UP = true; private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up"; @@ -199,7 +198,7 @@ public class NotificationInterruptionStateProvider { boolean inShade = mStatusBarStateController.getState() == SHADE; if (entry.isBubble() && inShade) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: in unlocked shade where notification is shown as a " + "bubble: " + sbn.getKey()); } @@ -207,7 +206,7 @@ public class NotificationInterruptionStateProvider { } if (!canAlertCommon(entry)) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: notification shouldn't alert: " + sbn.getKey()); } return false; @@ -218,7 +217,7 @@ public class NotificationInterruptionStateProvider { } if (entry.importance < NotificationManager.IMPORTANCE_HIGH) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey()); } return false; @@ -233,13 +232,16 @@ public class NotificationInterruptionStateProvider { boolean inUse = mPowerManager.isScreenOn() && !isDreaming; if (!inUse) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: not in use: " + sbn.getKey()); } return false; } if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) { + if (DEBUG_HEADS_UP) { + Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey()); + } return false; } @@ -257,28 +259,28 @@ public class NotificationInterruptionStateProvider { StatusBarNotification sbn = entry.notification; if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No pulsing: disabled by setting: " + sbn.getKey()); } return false; } if (!canAlertCommon(entry)) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey()); } return false; } if (entry.shouldSuppressAmbient()) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No pulsing: ambient effect suppressed: " + sbn.getKey()); } return false; } if (entry.importance < NotificationManager.IMPORTANCE_DEFAULT) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No pulsing: not important enough: " + sbn.getKey()); } return false; @@ -300,7 +302,7 @@ public class NotificationInterruptionStateProvider { StatusBarNotification sbn = entry.notification; if (mNotificationFilter.shouldFilterOut(entry)) { - if (DEBUG) { + if (DEBUG || DEBUG_HEADS_UP) { Log.d(TAG, "No alerting: filtered notification: " + sbn.getKey()); } return false; @@ -308,7 +310,7 @@ public class NotificationInterruptionStateProvider { // Don't alert notifications that are suppressed due to group alert behavior if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) { - if (DEBUG) { + if (DEBUG || DEBUG_HEADS_UP) { Log.d(TAG, "No alerting: suppressed due to group alert behavior"); } return false; @@ -330,28 +332,28 @@ public class NotificationInterruptionStateProvider { StatusBarNotification sbn = entry.notification; if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: no huns or vr mode"); } return false; } if (entry.shouldSuppressPeek()) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey()); } return false; } if (isSnoozedPackage(sbn)) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: snoozed package: " + sbn.getKey()); } return false; } if (entry.hasJustLaunchedFullScreenIntent()) { - if (DEBUG) { + if (DEBUG_HEADS_UP) { Log.d(TAG, "No heads up: recent fullscreen: " + sbn.getKey()); } return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 6e84089e8ff5..03f0c7b481ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -1366,7 +1366,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (isChildInGroup()) { mTranslationWhenRemoved += getNotificationParent().getTranslationY(); } - mPrivateLayout.setRemoved(); + for (NotificationContentView l : mLayouts) { + l.setRemoved(); + } } public boolean wasChildInGroupWhenRemoved() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 90f63249846e..0c5b27b92878 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -1542,6 +1542,15 @@ public class NotificationContentView extends FrameLayout { if (mHeadsUpRemoteInput != null) { mHeadsUpRemoteInput.setRemoved(); } + if (mExpandedWrapper != null) { + mExpandedWrapper.setRemoved(); + } + if (mContractedWrapper != null) { + mContractedWrapper.setRemoved(); + } + if (mHeadsUpWrapper != null) { + mHeadsUpWrapper.setRemoved(); + } } public void setContentHeightAnimating(boolean animating) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java index 38f9bff2a63f..1116106df19d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java @@ -90,12 +90,12 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi } }; - MediaNotificationView.VisibilityChangeListener mVisibilityListener = + private MediaNotificationView.VisibilityChangeListener mVisibilityListener = new MediaNotificationView.VisibilityChangeListener() { @Override public void onAggregatedVisibilityChanged(boolean isVisible) { mIsViewVisible = isVisible; - if (isVisible) { + if (isVisible && mMediaController != null) { // Restart timer if we're currently playing and didn't already have one going PlaybackState state = mMediaController.getPlaybackState(); if (state != null && state.getState() == PlaybackState.STATE_PLAYING @@ -109,6 +109,18 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi } }; + private View.OnAttachStateChangeListener mAttachStateListener = + new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + } + + @Override + public void onViewDetachedFromWindow(View v) { + mIsViewVisible = false; + } + }; + private MediaController.Callback mMediaCallback = new MediaController.Callback() { @Override public void onSessionDestroyed() { @@ -116,6 +128,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi mMediaController.unregisterCallback(this); if (mView instanceof MediaNotificationView) { ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener); + mView.removeOnAttachStateChangeListener(mAttachStateListener); } } @@ -154,6 +167,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi if (mView instanceof MediaNotificationView) { MediaNotificationView mediaView = (MediaNotificationView) mView; mediaView.addVisibilityListener(mVisibilityListener); + mView.addOnAttachStateChangeListener(mAttachStateListener); } } @@ -257,6 +271,18 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi } } + @Override + public void setRemoved() { + clearTimer(); + if (mMediaController != null) { + mMediaController.unregisterCallback(mMediaCallback); + } + if (mView instanceof MediaNotificationView) { + ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener); + mView.removeOnAttachStateChangeListener(mAttachStateListener); + } + } + private boolean canSeekMedia(@Nullable PlaybackState state) { if (state == null) { return false; @@ -292,7 +318,6 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi public void run() { if (mMediaController != null && mSeekBar != null) { PlaybackState playbackState = mMediaController.getPlaybackState(); - if (playbackState != null) { updatePlaybackUi(playbackState); } else { @@ -305,6 +330,10 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi }; private void updatePlaybackUi(PlaybackState state) { + if (mSeekBar == null || mSeekBarElapsedTime == null) { + return; + } + long position = state.getPosition(); mSeekBar.setProgress((int) position); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 47906a7058a3..3950003e64ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -261,6 +261,12 @@ public abstract class NotificationViewWrapper implements TransformableView { mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); } + /** + * Called to indicate this view is removed + */ + public void setRemoved() { + } + public int getCustomBackgroundColor() { // Parent notifications should always use the normal background color return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 1a418665dd2e..6a611a623c69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -179,6 +179,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd */ private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1; private final KeyguardBypassController mKeyguardBypassController; + private final DynamicPrivacyController mDynamicPrivacyController; + private final SysuiStatusBarStateController mStatusbarStateController; private ExpandHelper mExpandHelper; private final NotificationSwipeHelper mSwipeHelper; @@ -605,6 +607,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } }); dynamicPrivacyController.addListener(this); + mDynamicPrivacyController = dynamicPrivacyController; + mStatusbarStateController = (SysuiStatusBarStateController) statusBarStateController; } private void updateDismissRtlSetting(boolean dismissRtl) { @@ -695,6 +699,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public boolean hasActiveClearableNotifications(@SelectedRows int selection) { + if (mDynamicPrivacyController.isInLockedDownShade()) { + return false; + } int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); @@ -5699,7 +5706,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mAnimateBottomOnLayout = true; } // Let's update the footer once the notifications have been updated (in the next frame) - post(this::updateFooter); + post(() -> { + updateFooter(); + updateSectionBoundaries(); + }); } public void setOnPulseHeightChangedListener(Runnable listener) { @@ -6355,6 +6365,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } return true; + } else if (mDynamicPrivacyController.isInLockedDownShade()) { + mStatusbarStateController.setLeaveOpenOnKeyguardHide(true); + mStatusBar.dismissKeyguardThenExecute(() -> false /* dismissAction */, + null /* cancelRunnable */, false /* afterKeyguardGone */); + return true; } else { // abort gesture. return false; @@ -6388,6 +6403,30 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public boolean isFalsingCheckNeeded() { return mStatusBarState == StatusBarState.KEYGUARD; } + + @Override + public boolean isDragDownEnabledForView(ExpandableView view) { + if (isDragDownAnywhereEnabled()) { + return true; + } + if (mDynamicPrivacyController.isInLockedDownShade()) { + if (view == null) { + // Dragging down is allowed in general + return true; + } + if (view instanceof ExpandableNotificationRow) { + // Only drag down on sensitive views, otherwise the ExpandHelper will take this + return ((ExpandableNotificationRow) view).getEntry().isSensitive(); + } + } + return false; + } + + @Override + public boolean isDragDownAnywhereEnabled() { + return mStatusbarStateController.getState() == StatusBarState.KEYGUARD + && !mKeyguardBypassController.getBypassEnabled(); + } }; public DragDownCallback getDragDownCallback() { return mDragDownCallback; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java index d22ad71594b9..fce1dcc998fe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -14,8 +14,6 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.Interpolators.ALPHA_IN; -import static com.android.systemui.Interpolators.ALPHA_OUT; import static com.android.systemui.Interpolators.LINEAR; import android.animation.Animator; @@ -24,6 +22,8 @@ import android.animation.ValueAnimator; import android.view.View; import android.view.View.AccessibilityDelegate; +import com.android.systemui.Dependency; +import com.android.systemui.assist.AssistManager; import com.android.systemui.statusbar.policy.KeyButtonDrawable; import java.util.ArrayList; @@ -33,12 +33,13 @@ import java.util.ArrayList; * multiples of the same nav bar icon appearing. */ public class ButtonDispatcher { - private final static int FADE_DURATION_IN = 150; - private final static int FADE_DURATION_OUT = 1000; + private static final int FADE_DURATION_IN = 150; + private static final int FADE_DURATION_OUT = 250; private final ArrayList<View> mViews = new ArrayList<>(); private final int mId; + private final AssistManager mAssistManager; private View.OnClickListener mClickListener; private View.OnTouchListener mTouchListener; @@ -56,7 +57,10 @@ public class ButtonDispatcher { private AccessibilityDelegate mAccessibilityDelegate; private final ValueAnimator.AnimatorUpdateListener mAlphaListener = animation -> - setAlpha((float) animation.getAnimatedValue()); + setAlpha( + (float) animation.getAnimatedValue(), + false /* animate */, + false /* cancelAnimator */); private final AnimatorListenerAdapter mFadeListener = new AnimatorListenerAdapter() { @Override @@ -68,6 +72,7 @@ public class ButtonDispatcher { public ButtonDispatcher(int id) { mId = id; + mAssistManager = Dependency.get(AssistManager.class); } void clear() { @@ -168,16 +173,30 @@ public class ButtonDispatcher { } public void setAlpha(float alpha, boolean animate) { - setAlpha(alpha, animate, (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT); + setAlpha(alpha, animate, true /* cancelAnimator */); } public void setAlpha(float alpha, boolean animate, long duration) { + setAlpha(alpha, animate, duration, true /* cancelAnimator */); + } + + public void setAlpha(float alpha, boolean animate, boolean cancelAnimator) { + setAlpha( + alpha, + animate, + (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT, + cancelAnimator); + } + + public void setAlpha(float alpha, boolean animate, long duration, boolean cancelAnimator) { + if (mFadeAnimator != null && (cancelAnimator || animate)) { + mFadeAnimator.cancel(); + } if (animate) { - if (mFadeAnimator != null) { - mFadeAnimator.cancel(); - } setVisibility(View.VISIBLE); mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha); + mFadeAnimator.setStartDelay( + mAssistManager.getAssistHandleShowAndGoRemainingDurationMs()); mFadeAnimator.setDuration(duration); mFadeAnimator.setInterpolator(LINEAR); mFadeAnimator.addListener(mFadeListener); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index f9cdde8059d4..e0c6c55c2e59 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -103,7 +103,7 @@ public class EdgeBackGestureHandler implements DisplayListener { new ISystemGestureExclusionListener.Stub() { @Override public void onSystemGestureExclusionChanged(int displayId, - Region systemGestureExclusion) { + Region systemGestureExclusion, Region unrestrictedOrNull) { if (displayId == mDisplayId) { mMainExecutor.execute(() -> mExcludeRegion.set(systemGestureExclusion)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt index 70d3bff9b822..832ea9e3d72e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.content.pm.PackageManager import android.hardware.biometrics.BiometricSourceType -import android.hardware.face.FaceManager import android.provider.Settings import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager @@ -34,6 +33,7 @@ class KeyguardBypassController { private val unlockMethodCache: UnlockMethodCache private val statusBarStateController: StatusBarStateController + private var hasFaceFeature: Boolean /** * The pending unlock type which is set if the bypass was blocked when it happened. @@ -71,11 +71,8 @@ class KeyguardBypassController { unlockMethodCache = UnlockMethodCache.getInstance(context) this.statusBarStateController = statusBarStateController - if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { - return - } - val faceManager = context.getSystemService(FaceManager::class.java) - if (faceManager?.isHardwareDetected != true) { + hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE) + if (!hasFaceFeature) { return } @@ -165,7 +162,7 @@ class KeyguardBypassController { pw.print(" isPulseExpanding: "); pw.println(isPulseExpanding) pw.print(" launchingAffordance: "); pw.println(launchingAffordance) pw.print(" qSExpanded: "); pw.println(qSExpanded) - pw.print(" bouncerShowing: "); pw.println(bouncerShowing) + pw.print(" hasFaceFeature: "); pw.println(hasFaceFeature) } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index c0a1b123fe77..1d4d0bd17f01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -103,10 +103,11 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.USER_SWITCHER_ENABLED, 0) != 0; - if (!UserManager.supportsMultipleUsers() - || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH) + // TODO(b/138661450) Move IPC calls to background + if (!userSwitcherEnabled + || !UserManager.supportsMultipleUsers() || UserManager.isDeviceInDemoMode(mContext) - || !userSwitcherEnabled) { + || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 081e29381a65..6bfa048eb63d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -323,7 +323,7 @@ public class NavigationBarView extends FrameLayout implements public void setComponents(NotificationPanelView panel, AssistManager assistManager) { mPanelView = panel; - updateSystemUiStateFlags(); + updatePanelSystemUiStateFlags(); } @Override @@ -587,7 +587,7 @@ public class NavigationBarView extends FrameLayout implements updateNavButtonIcons(); updateSlippery(); setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled()); - updateSystemUiStateFlags(); + updateDisabledSystemUiStateFlags(); } public void updateNavButtonIcons() { @@ -710,10 +710,10 @@ public class NavigationBarView extends FrameLayout implements public void onStatusBarPanelStateChanged() { updateSlippery(); - updateSystemUiStateFlags(); + updatePanelSystemUiStateFlags(); } - public void updateSystemUiStateFlags() { + public void updateDisabledSystemUiStateFlags() { int displayId = mContext.getDisplayId(); mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING, ActivityManagerWrapper.getInstance().isScreenPinningActive(), displayId); @@ -723,6 +723,10 @@ public class NavigationBarView extends FrameLayout implements (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId); mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SEARCH_DISABLED, (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0, displayId); + } + + public void updatePanelSystemUiStateFlags() { + int displayId = mContext.getDisplayId(); if (mPanelView != null) { mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED, mPanelView.isFullyExpanded() && !mPanelView.isInSettings(), displayId); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index d0626ed780e2..c17173063fc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -41,6 +41,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.os.PowerManager; import android.os.SystemClock; +import android.provider.DeviceConfig; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; @@ -54,6 +55,7 @@ import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.KeyguardClockSwitch; @@ -135,6 +137,8 @@ public class NotificationPanelView extends PanelView implements */ public static final int FLING_HIDE = 2; + private double mQqsSplitFraction; + // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is // changed. private static final int CAP_HEIGHT = 1456; @@ -527,6 +531,9 @@ public class NotificationPanelView extends PanelView implements com.android.internal.R.dimen.status_bar_height); mHeadsUpInset = statusbarHeight + getResources().getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); + mQqsSplitFraction = ((float) getResources().getInteger(R.integer.qqs_split_fraction)) / ( + getResources().getInteger(R.integer.qqs_split_fraction) + + getResources().getInteger(R.integer.qs_split_fraction)); } /** @@ -1259,6 +1266,15 @@ public class NotificationPanelView extends PanelView implements // earlier so the state is already up to date when dragging down. setListening(true); } + if (isQsSplitEnabled() && !mKeyguardShowing) { + if (mQsExpandImmediate) { + mNotificationStackScroller.setVisibility(View.GONE); + mQsFrame.setVisibility(View.VISIBLE); + } else { + mNotificationStackScroller.setVisibility(View.VISIBLE); + mQsFrame.setVisibility(View.GONE); + } + } return false; } @@ -1269,6 +1285,17 @@ public class NotificationPanelView extends PanelView implements || y <= mQs.getView().getY() + mQs.getView().getHeight()); } + private boolean isOnQsEndArea(float x) { + if (!isQsSplitEnabled()) return false; + if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) { + return x >= mQsFrame.getX() + mQqsSplitFraction * mQsFrame.getWidth() + && x <= mQsFrame.getX() + mQsFrame.getWidth(); + } else { + return x >= mQsFrame.getX() + && x <= mQsFrame.getX() + (1 - mQqsSplitFraction) * mQsFrame.getWidth(); + } + } + private boolean isOpenQsEvent(MotionEvent event) { final int pointerCount = event.getPointerCount(); final int action = event.getActionMasked(); @@ -1284,7 +1311,9 @@ public class NotificationPanelView extends PanelView implements && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY) || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY)); - return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag; + final boolean onHeaderRight = isOnQsEndArea(event.getX()); + + return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag || onHeaderRight; } private void handleQsDown(MotionEvent event) { @@ -1519,6 +1548,10 @@ public class NotificationPanelView extends PanelView implements mBarState = statusBarState; mKeyguardShowing = keyguardShowing; + if (mKeyguardShowing && isQsSplitEnabled()) { + mNotificationStackScroller.setVisibility(View.VISIBLE); + mQsFrame.setVisibility(View.VISIBLE); + } if (oldState == StatusBarState.KEYGUARD && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) { @@ -1538,6 +1571,7 @@ public class NotificationPanelView extends PanelView implements } else { mKeyguardStatusBar.setAlpha(1f); mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE); + ((PhoneStatusBarView) mBar).maybeShowDivider(keyguardShowing); if (keyguardShowing && oldState != mBarState) { if (mQs != null) { mQs.hideImmediately(); @@ -3098,10 +3132,8 @@ public class NotificationPanelView extends PanelView implements /** * Whether the camera application can be launched for the camera launch gesture. - * - * @param keyguardIsShowing whether keyguard is being shown */ - public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) { + public boolean canCameraGestureBeLaunched() { if (!mStatusBar.isCameraAllowedByAdmin()) { return false; } @@ -3110,7 +3142,7 @@ public class NotificationPanelView extends PanelView implements String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null) ? null : resolveInfo.activityInfo.packageName; return packageToLaunch != null && - (keyguardIsShowing || !isForegroundApp(packageToLaunch)) + (mBarState != StatusBarState.SHADE || !isForegroundApp(packageToLaunch)) && !mAffordanceHelper.isSwipingInProgress(); } @@ -3424,4 +3456,8 @@ public class NotificationPanelView extends PanelView implements mOnReinflationListener = onReinflationListener; } + public static boolean isQsSplitEnabled() { + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED, false); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java index a7d5acaac765..96b4b22d0580 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java @@ -32,7 +32,7 @@ public final class PhoneStatusBarTransitions extends BarTransitions { private final PhoneStatusBarView mView; private final float mIconAlphaWhenOpaque; - private View mLeftSide, mStatusIcons, mBattery, mClock; + private View mLeftSide, mStatusIcons, mBattery, mClock, mDivider; private Animator mCurrentAnimation; public PhoneStatusBarTransitions(PhoneStatusBarView view) { @@ -46,6 +46,7 @@ public final class PhoneStatusBarTransitions extends BarTransitions { mLeftSide = mView.findViewById(R.id.status_bar_left_side); mStatusIcons = mView.findViewById(R.id.statusIcons); mBattery = mView.findViewById(R.id.battery); + mDivider = mView.findViewById(R.id.divider); applyModeBackground(-1, getMode(), false /*animate*/); applyMode(getMode(), false /*animate*/); } @@ -88,6 +89,7 @@ public final class PhoneStatusBarTransitions extends BarTransitions { anims.playTogether( animateTransitionTo(mLeftSide, newAlpha), animateTransitionTo(mStatusIcons, newAlpha), + animateTransitionTo(mDivider, newAlpha), animateTransitionTo(mBattery, newAlphaBC) ); if (isLightsOut(mode)) { @@ -98,6 +100,7 @@ public final class PhoneStatusBarTransitions extends BarTransitions { } else { mLeftSide.setAlpha(newAlpha); mStatusIcons.setAlpha(newAlpha); + mDivider.setAlpha(newAlpha); mBattery.setAlpha(newAlphaBC); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 8efd952e67c5..53e146758116 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; +import android.provider.DeviceConfig; import android.util.AttributeSet; import android.util.EventLog; import android.util.Pair; @@ -40,6 +41,8 @@ import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import android.widget.LinearLayout; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; +import com.android.systemui.DarkReceiverImpl; import com.android.systemui.Dependency; import com.android.systemui.EventLogTags; import com.android.systemui.R; @@ -78,6 +81,10 @@ public class PhoneStatusBarView extends PanelBar { private View mCutoutSpace; @Nullable private DisplayCutout mDisplayCutout; + + private DarkReceiverImpl mSplitDivider; + private View mDividerContainer; + private QsSplitPropertyListener mPropertyListener; /** * Draw this many pixels into the left/right side of the cutout to optimally use the space */ @@ -109,6 +116,10 @@ public class PhoneStatusBarView extends PanelBar { mBattery = findViewById(R.id.battery); mCutoutSpace = findViewById(R.id.cutout_space_view); mCenterIconSpace = findViewById(R.id.centered_icon_area); + mSplitDivider = findViewById(R.id.divider); + mDividerContainer = findViewById(R.id.divider_container); + maybeShowDivider(true); + mPropertyListener = new QsSplitPropertyListener(mDividerContainer); updateResources(); } @@ -118,16 +129,26 @@ public class PhoneStatusBarView extends PanelBar { super.onAttachedToWindow(); // Always have Battery meters in the status bar observe the dark/light modes. Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery); + Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSplitDivider); + maybeShowDivider(true); if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) { updateLayoutForCutout(); } + if (mPropertyListener != null) { + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, + mContext.getMainExecutor(), mPropertyListener); + } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery); + Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSplitDivider); mDisplayCutout = null; + if (mPropertyListener != null) { + DeviceConfig.removeOnPropertiesChangedListener(mPropertyListener); + } } @Override @@ -196,6 +217,7 @@ public class PhoneStatusBarView extends PanelBar { public void onPanelPeeked() { super.onPanelPeeked(); mBar.makeExpandedVisible(false); + maybeShowDivider(!mBar.mPanelExpanded); } @Override @@ -204,6 +226,7 @@ public class PhoneStatusBarView extends PanelBar { // Close the status bar in the next frame so we can show the end of the animation. post(mHideExpandedRunnable); mIsFullyOpenedPanel = false; + maybeShowDivider(!mBar.mPanelExpanded); } public void removePendingHideExpandedRunnables() { @@ -217,6 +240,7 @@ public class PhoneStatusBarView extends PanelBar { mPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } mIsFullyOpenedPanel = true; + maybeShowDivider(!mBar.mPanelExpanded); } @Override @@ -240,24 +264,28 @@ public class PhoneStatusBarView extends PanelBar { mBar.onTrackingStarted(); mScrimController.onTrackingStarted(); removePendingHideExpandedRunnables(); + maybeShowDivider(!mBar.mPanelExpanded); } @Override public void onClosingFinished() { super.onClosingFinished(); mBar.onClosingFinished(); + maybeShowDivider(!mBar.mPanelExpanded); } @Override public void onTrackingStopped(boolean expand) { super.onTrackingStopped(expand); mBar.onTrackingStopped(expand); + maybeShowDivider(!mBar.mPanelExpanded); } @Override public void onExpandingFinished() { super.onExpandingFinished(); mScrimController.onExpandingFinished(); + maybeShowDivider(!mBar.mPanelExpanded); } @Override @@ -390,4 +418,30 @@ public class PhoneStatusBarView extends PanelBar { protected boolean shouldPanelBeVisible() { return mHeadsUpVisible || super.shouldPanelBeVisible(); } + + void maybeShowDivider(boolean showDivider) { + int state = + showDivider && NotificationPanelView.isQsSplitEnabled() ? View.VISIBLE : View.GONE; + mDividerContainer.setVisibility(state); + } + + private static class QsSplitPropertyListener implements + DeviceConfig.OnPropertiesChangedListener { + private final View mDivider; + + QsSplitPropertyListener(View divider) { + mDivider = divider; + } + + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (properties.getNamespace().equals(DeviceConfig.NAMESPACE_SYSTEMUI) + && properties.getKeyset().contains( + SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED)) { + boolean splitEnabled = properties.getBoolean( + SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED, false); + mDivider.setVisibility(splitEnabled ? VISIBLE : GONE); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index f15b60123a80..4f9df438f08c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -193,6 +193,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationClicker; @@ -375,6 +376,8 @@ public class StatusBar extends SystemUI implements DemoMode, @Inject protected HeadsUpManagerPhone mHeadsUpManager; @Inject + DynamicPrivacyController mDynamicPrivacyController; + @Inject BypassHeadsUpNotifier mBypassHeadsUpNotifier; @Nullable @Inject @@ -591,7 +594,7 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mVibrateOnOpening; private VibratorHelper mVibratorHelper; private ActivityLaunchAnimator mActivityLaunchAnimator; - protected NotificationPresenter mPresenter; + protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; private boolean mPulsing; protected BubbleController mBubbleController; @@ -1066,7 +1069,7 @@ public class StatusBar extends SystemUI implements DemoMode, mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel, mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController, - mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager, + mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController, mNotificationAlertingManager, rowBinder); mNotificationListController = @@ -1243,6 +1246,7 @@ public class StatusBar extends SystemUI implements DemoMode, .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager); + mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); mLightBarController.setBiometricUnlockController(mBiometricUnlockController); @@ -3785,10 +3789,8 @@ public class StatusBar extends SystemUI implements DemoMode, mLaunchCameraOnFinishedGoingToSleep = true; return; } - if (!mNotificationPanel.canCameraGestureBeLaunched( - mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) { - if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " + - mExpandedVisible); + if (!mNotificationPanel.canCameraGestureBeLaunched()) { + if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now"); return; } if (!mDeviceInteractive) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index a87dca45bf75..a870590c08ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -59,6 +59,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -117,9 +118,9 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, private final AccessibilityManager mAccessibilityManager; private final KeyguardManager mKeyguardManager; private final ActivityLaunchAnimator mActivityLaunchAnimator; - private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final int mMaxAllowedKeyguardNotifications; private final IStatusBarService mBarService; + private final DynamicPrivacyController mDynamicPrivacyController; private boolean mReinflateNotificationsOnUserSwitched; private boolean mDispatchUiModeChangeOnUserSwitched; private final UnlockMethodCache mUnlockMethodCache; @@ -136,16 +137,16 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, DozeScrimController dozeScrimController, ScrimController scrimController, ActivityLaunchAnimator activityLaunchAnimator, - StatusBarKeyguardViewManager statusBarKeyguardViewManager, + DynamicPrivacyController dynamicPrivacyController, NotificationAlertingManager notificationAlertingManager, NotificationRowBinderImpl notificationRowBinder) { mContext = context; mNotificationPanel = panel; mHeadsUpManager = headsUp; + mDynamicPrivacyController = dynamicPrivacyController; mCommandQueue = getComponent(context, CommandQueue.class); mAboveShelfObserver = new AboveShelfObserver(stackScroller); mActivityLaunchAnimator = activityLaunchAnimator; - mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mAboveShelfObserver.setListener(statusBarWindow.findViewById( R.id.notification_container_parent)); mAccessibilityManager = context.getSystemService(AccessibilityManager.class); @@ -454,8 +455,15 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, @Override public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) { mHeadsUpManager.setExpanded(clickedEntry, nowExpanded); - if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) { - mShadeController.goToLockedShade(clickedEntry.getRow()); + if (nowExpanded) { + if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { + mShadeController.goToLockedShade(clickedEntry.getRow()); + } else if (clickedEntry.isSensitive() + && mDynamicPrivacyController.isInLockedDownShade()) { + mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); + mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */ + , null /* cancelRunnable */, false /* afterKeyguardGone */); + } } } @@ -464,12 +472,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, return mVrMode; } - @Override - public boolean isPresenterLocked() { - return mStatusBarKeyguardViewManager.isShowing() - && mStatusBarKeyguardViewManager.isSecure(); - } - private void onLockedNotificationImportanceChange(OnDismissAction dismissAction) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); mActivityStarter.dismissKeyguardThenExecute(dismissAction, null, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index d9a9f7cbc2a8..0ef981bdb3de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -29,7 +29,9 @@ import android.graphics.PixelFormat; import android.os.Binder; import android.os.RemoteException; import android.os.SystemProperties; +import android.os.Trace; import android.util.Log; +import android.view.Display; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -57,6 +59,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import javax.inject.Inject; import javax.inject.Singleton; @@ -73,11 +76,13 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat private final WindowManager mWindowManager; private final IActivityManager mActivityManager; private final DozeParameters mDozeParameters; - private final WindowManager.LayoutParams mLpChanged; + private final LayoutParams mLpChanged; private final boolean mKeyguardScreenRotation; private final long mLockScreenDisplayTimeout; + private final Display.Mode mKeyguardDisplayMode; + private final KeyguardBypassController mKeyguardBypassController; private ViewGroup mStatusBarView; - private WindowManager.LayoutParams mLp; + private LayoutParams mLp; private boolean mHasTopUi; private boolean mHasTopUiChanged; private int mBarHeight; @@ -91,27 +96,49 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class); @Inject - public StatusBarWindowController(Context context) { + public StatusBarWindowController(Context context, + StatusBarStateController statusBarStateController, + ConfigurationController configurationController, + KeyguardBypassController keyguardBypassController) { this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(), - DozeParameters.getInstance(context)); + DozeParameters.getInstance(context), statusBarStateController, + configurationController, keyguardBypassController); } @VisibleForTesting public StatusBarWindowController(Context context, WindowManager windowManager, - IActivityManager activityManager, DozeParameters dozeParameters) { + IActivityManager activityManager, DozeParameters dozeParameters, + StatusBarStateController statusBarStateController, + ConfigurationController configurationController, + KeyguardBypassController keyguardBypassController) { mContext = context; mWindowManager = windowManager; mActivityManager = activityManager; mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation(); mDozeParameters = dozeParameters; mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze(); - mLpChanged = new WindowManager.LayoutParams(); + mLpChanged = new LayoutParams(); + mKeyguardBypassController = keyguardBypassController; mLockScreenDisplayTimeout = context.getResources() .getInteger(R.integer.config_lockScreenDisplayTimeout); - ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) + ((SysuiStatusBarStateController) statusBarStateController) .addCallback(mStateListener, SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER); - Dependency.get(ConfigurationController.class).addCallback(this); + configurationController.addCallback(this); + + Display.Mode[] supportedModes = context.getDisplay().getSupportedModes(); + Display.Mode currentMode = context.getDisplay().getMode(); + // Running on the highest frame rate available can be expensive. + // Let's specify a preferred refresh rate, and allow higher FPS only when we + // know that we're not falsing (because we unlocked.) + int keyguardRefreshRate = context.getResources() + .getInteger(R.integer.config_keyguardRefreshRate); + // Find supported display mode with the same resolution and requested refresh rate. + mKeyguardDisplayMode = Arrays.stream(supportedModes).filter(mode -> + (int) mode.getRefreshRate() == keyguardRefreshRate + && mode.getPhysicalWidth() == currentMode.getPhysicalWidth() + && mode.getPhysicalHeight() == currentMode.getPhysicalHeight()) + .findFirst().orElse(null); } /** @@ -144,19 +171,19 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat // Now that the status bar window encompasses the sliding panel and its // translucent backdrop, the entire thing is made TRANSLUCENT and is // hardware-accelerated. - mLp = new WindowManager.LayoutParams( + mLp = new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, barHeight, - WindowManager.LayoutParams.TYPE_STATUS_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + LayoutParams.TYPE_STATUS_BAR, + LayoutParams.FLAG_NOT_FOCUSABLE + | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING + | LayoutParams.FLAG_SPLIT_TOUCH + | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, PixelFormat.TRANSLUCENT); mLp.token = new Binder(); mLp.gravity = Gravity.TOP; - mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE; mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; @@ -189,9 +216,9 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat private void applyKeyguardFlags(State state) { if (state.keyguardShowing) { - mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; + mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_KEYGUARD; } else { - mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; + mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_KEYGUARD; } final boolean scrimsOccludingWallpaper = @@ -199,9 +226,9 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat final boolean keyguardOrAod = state.keyguardShowing || (state.dozing && mDozeParameters.getAlwaysOn()); if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) { - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER; } else { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER; } if (state.dozing) { @@ -209,6 +236,18 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat } else { mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; } + + if (mKeyguardDisplayMode != null) { + boolean bypassOnKeyguard = mKeyguardBypassController.getBypassEnabled() + && state.statusBarState == StatusBarState.KEYGUARD && !state.keyguardFadingAway + && !state.keyguardGoingAway; + if (state.dozing || bypassOnKeyguard) { + mLpChanged.preferredDisplayModeId = mKeyguardDisplayMode.getModeId(); + } else { + mLpChanged.preferredDisplayModeId = 0; + } + Trace.setCounter("display_mode_id", mLpChanged.preferredDisplayModeId); + } } private void adjustScreenOrientation(State state) { @@ -228,17 +267,17 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput) || ENABLE_REMOTE_INPUT && state.remoteInputActive || state.bubbleExpanded) { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE; + mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM; } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE; + mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM; } else { - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mLpChanged.flags |= LayoutParams.FLAG_NOT_FOCUSABLE; + mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM; } - mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + mLpChanged.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } private void applyForceShowNavigationFlag(State state) { @@ -296,19 +335,19 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat && state.statusBarState == StatusBarState.KEYGUARD && !state.qsExpanded && !state.forceUserActivity) { mLpChanged.inputFeatures |= - WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; + LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; } else { mLpChanged.inputFeatures &= - ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; + ~LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; } } private void applyStatusBarColorSpaceAgnosticFlag(State state) { if (!isExpanded(state)) { - mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; + mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; } else { mLpChanged.privateFlags &= - ~WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; + ~LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; } } @@ -357,16 +396,16 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat mLpChanged.privateFlags |= WindowManager .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; } else { - mLpChanged.privateFlags &= ~WindowManager - .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; + mLpChanged.privateFlags + &= ~LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; } } private void applyModalFlag(State state) { if (state.headsUpShowing) { - mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCH_MODAL; } else { - mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCH_MODAL; } } @@ -374,12 +413,12 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat if (state.forceDozeBrightness) { mLpChanged.screenBrightness = mScreenBrightnessDoze; } else { - mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE; + mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE; } } private void applyHasTopUi(State state) { - mHasTopUiChanged = isExpanded(state); + mHasTopUiChanged = state.forceHasTopUi || isExpanded(state); } private void applyNotTouchable(State state) { @@ -575,7 +614,8 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("StatusBarWindowController state:"); + pw.println("StatusBarWindowController:"); + pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode); pw.println(mCurrentState); } @@ -594,6 +634,23 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat setKeyguardDark(useDarkText); } + /** + * When keyguard will be dismissed but didn't start animation yet. + */ + public void setKeyguardGoingAway(boolean goingAway) { + mCurrentState.keyguardGoingAway = goingAway; + apply(mCurrentState); + } + + public boolean getForceHasTopUi() { + return mCurrentState.forceHasTopUi; + } + + public void setForceHasTopUi(boolean forceHasTopUi) { + mCurrentState.forceHasTopUi = forceHasTopUi; + apply(mCurrentState); + } + private static class State { boolean keyguardShowing; boolean keyguardOccluded; @@ -603,6 +660,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat boolean statusBarFocusable; boolean bouncerShowing; boolean keyguardFadingAway; + boolean keyguardGoingAway; boolean qsExpanded; boolean headsUpShowing; boolean forceStatusBarVisible; @@ -614,6 +672,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat boolean notTouchable; boolean bubblesShowing; boolean bubbleExpanded; + boolean forceHasTopUi; /** * The {@link StatusBar} state from the status bar. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index f1049f005dea..6789930ab76e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -66,6 +66,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility; import com.android.systemui.tuner.TunerService; @@ -416,9 +417,8 @@ public class StatusBarWindowView extends FrameLayout { } boolean intercept = false; if (mNotificationPanel.isFullyExpanded() - && mStatusBarStateController.getState() == StatusBarState.KEYGUARD + && mDragDownHelper.isDragDownEnabled() && !mService.isBouncerShowing() - && !mBypassController.getBypassEnabled() && !mService.isDozing()) { intercept = mDragDownHelper.onInterceptTouchEvent(ev); } @@ -441,9 +441,7 @@ public class StatusBarWindowView extends FrameLayout { if (mService.isDozing()) { handled = !mService.isPulsing(); } - if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled - && !mBypassController.getBypassEnabled()) - || mDragDownHelper.isDraggingDown()) { + if ((mDragDownHelper.isDragDownEnabled() && !handled) || mDragDownHelper.isDraggingDown()) { // we still want to finish our drag down gesture when locking the screen handled = mDragDownHelper.onTouchEvent(ev); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index db45ad788bfc..0044ca7c0409 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -36,6 +36,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; +import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -65,6 +66,8 @@ import java.util.List; public class CarrierTextControllerTest extends SysuiTestCase { private static final CharSequence SEPARATOR = " \u2014 "; + private static final CharSequence INVALID_CARD_TEXT = "Invalid card"; + private static final CharSequence AIRPLANE_MODE_TEXT = "Airplane mode"; private static final String TEST_CARRIER = "TEST_CARRIER"; private static final String TEST_CARRIER_2 = "TEST_CARRIER_2"; private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24"; @@ -106,6 +109,10 @@ public class CarrierTextControllerTest extends SysuiTestCase { mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager); mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); + mContext.getOrCreateTestableResources().addOverride( + R.string.keyguard_sim_error_message_short, INVALID_CARD_TEXT); + mContext.getOrCreateTestableResources().addOverride( + R.string.airplane_mode, AIRPLANE_MODE_TEXT); mDependency.injectMockDependency(WakefulnessLifecycle.class); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, new Handler(mTestableLooper.getLooper())); @@ -122,6 +129,53 @@ public class CarrierTextControllerTest extends SysuiTestCase { } @Test + public void testAirplaneMode() { + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); + reset(mCarrierTextCallback); + List<SubscriptionInfo> list = new ArrayList<>(); + list.add(TEST_SUBSCRIPTION); + when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY); + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); + + mCarrierTextController.updateCarrierText(); + + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = + ArgumentCaptor.forClass( + CarrierTextController.CarrierTextCallbackInfo.class); + + mTestableLooper.processAllMessages(); + verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); + assertEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText); + } + + @Test + public void testCardIOError() { + reset(mCarrierTextCallback); + List<SubscriptionInfo> list = new ArrayList<>(); + list.add(TEST_SUBSCRIPTION); + when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY); + when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn( + IccCardConstants.State.CARD_IO_ERROR); + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); + + mCarrierTextController.mCallback.onSimStateChanged(3, 1, + IccCardConstants.State.CARD_IO_ERROR); + + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = + ArgumentCaptor.forClass( + CarrierTextController.CarrierTextCallbackInfo.class); + + mTestableLooper.processAllMessages(); + verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); + assertEquals("TEST_CARRIER" + SEPARATOR + INVALID_CARD_TEXT, captor.getValue().carrierText); + // There's only one subscription in the list + assertEquals(1, captor.getValue().listOfCarriers.length); + assertEquals(TEST_CARRIER, captor.getValue().listOfCarriers[0]); + } + + @Test public void testWrongSlots() { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index b3f6f4ecdf0c..2221915a627a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -60,6 +60,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoveInterceptor; import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; @@ -67,6 +68,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -105,6 +107,10 @@ public class BubbleControllerTest extends SysuiTestCase { private ZenModeController mZenModeController; @Mock private ZenModeConfig mZenModeConfig; + @Mock + private SysuiStatusBarStateController mStatusBarStateController; + @Mock + private KeyguardBypassController mKeyguardBypassController; private FrameLayout mStatusBarView; @Captor @@ -143,7 +149,8 @@ public class BubbleControllerTest extends SysuiTestCase { // Bubbles get added to status bar window view mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, - mActivityManager, mDozeParameters); + mActivityManager, mDozeParameters, mStatusBarStateController, + mConfigurationController, mKeyguardBypassController); mStatusBarWindowController.add(mStatusBarView, 120 /* height */); // Need notifications for bubbles diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 84a7d4f0ff15..1e1f21568377 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -129,7 +129,7 @@ public class CommandQueueTest extends SysuiTestCase { @Test public void testShowImeButton() { - mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true); + mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true, false); waitForIdleSync(); verify(mCallbacks).setImeWindowStatus( eq(DEFAULT_DISPLAY), eq(null), eq(1), eq(2), eq(true)); @@ -137,7 +137,7 @@ public class CommandQueueTest extends SysuiTestCase { @Test public void testShowImeButtonForSecondaryDisplay() { - mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true); + mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true, false); waitForIdleSync(); verify(mCallbacks).setImeWindowStatus( eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java index 6ca5d2c7f687..d804b6f5c5ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java @@ -29,9 +29,12 @@ import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.UnlockMethodCache; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import org.junit.Assert; import org.junit.Before; @@ -51,12 +54,17 @@ public class DynamicPrivacyControllerTest extends SysuiTestCase { = mock(NotificationLockscreenUserManager.class); private DynamicPrivacyController.Listener mListener = mock(DynamicPrivacyController.Listener.class); + private KeyguardMonitor mKeyguardMonitor = mock(KeyguardMonitor.class); @Before public void setUp() throws Exception { when(mCache.canSkipBouncer()).thenReturn(false); + when(mKeyguardMonitor.isShowing()).thenReturn(true); mDynamicPrivacyController = new DynamicPrivacyController( - mLockScreenUserManager, mCache); + mLockScreenUserManager, mKeyguardMonitor, mCache, + mock(StatusBarStateController.class)); + mDynamicPrivacyController.setStatusBarKeyguardViewManager( + mock(StatusBarKeyguardViewManager.class)); mDynamicPrivacyController.addListener(mListener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index c1911eef6671..31054260eb15 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -62,6 +62,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationData; @@ -105,7 +106,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); @Mock private StatusBar mBar; - @Mock private StatusBarStateController mBarState; + @Mock private SysuiStatusBarStateController mBarState; @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationBlockingHelperManager mBlockingHelperManager; @Mock private NotificationGroupManager mGroupManager; @@ -136,7 +137,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mDependency.injectTestDependency( NotificationBlockingHelperManager.class, mBlockingHelperManager); - mDependency.injectTestDependency(StatusBarStateController.class, mBarState); + mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); mDependency.injectTestDependency(NotificationRemoteInputManager.class, mRemoteInputManager); @@ -162,7 +163,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mock(DynamicPrivacyController.class), mock(ConfigurationController.class), mock(ActivityStarterDelegate.class), - mock(StatusBarStateController.class), + mock(SysuiStatusBarStateController.class), mHeadsUpManager, mKeyguardBypassController, new FalsingManagerFake()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index 3da9a4bdf759..db8af3975cc8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -183,7 +183,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { // Set IME window status for default NavBar. mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, - BACK_DISPOSITION_DEFAULT, true); + BACK_DISPOSITION_DEFAULT, true, false); Handler.getMain().runWithScissors(() -> { }, 500); // Verify IME window state will be updated in default NavBar & external NavBar state reset. @@ -194,7 +194,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { // Set IME window status for external NavBar. mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, - IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); + IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true, false); Handler.getMain().runWithScissors(() -> { }, 500); // Verify IME window state will be updated in external NavBar & default NavBar state reset. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index e811e1d955ee..186a8c7dcee1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -40,6 +40,7 @@ import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; @@ -75,7 +76,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class), statusBarWindowView, mock(NotificationListContainerViewGroup.class), mock(DozeScrimController.class), mock(ScrimController.class), - mock(ActivityLaunchAnimator.class), mock(StatusBarKeyguardViewManager.class), + mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class), mock(NotificationAlertingManager.class), mock(NotificationRowBinderImpl.class)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index cffd57b35f04..fa235bd46d7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -157,7 +157,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private RemoteInputController mRemoteInputController; @Mock private StatusBarStateControllerImpl mStatusBarStateController; @Mock private DeviceProvisionedController mDeviceProvisionedController; - @Mock private NotificationPresenter mNotificationPresenter; + @Mock private StatusBarNotificationPresenter mNotificationPresenter; @Mock private NotificationEntryListener mEntryListener; @Mock @@ -780,7 +780,7 @@ public class StatusBarTest extends SysuiTestCase { NotificationShelf notificationShelf, NotificationLockscreenUserManager notificationLockscreenUserManager, CommandQueue commandQueue, - NotificationPresenter notificationPresenter, + StatusBarNotificationPresenter notificationPresenter, BubbleController bubbleController, NavigationBarController navBarController, AutoHideController autoHideController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java index fea41a441065..4ffaeaef77b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java @@ -33,6 +33,8 @@ import android.view.WindowManager; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.policy.ConfigurationController; import org.junit.Before; import org.junit.Test; @@ -54,6 +56,12 @@ public class StatusBarWindowControllerTest extends SysuiTestCase { private ViewGroup mStatusBarView; @Mock private IActivityManager mActivityManager; + @Mock + private SysuiStatusBarStateController mStatusBarStateController; + @Mock + private ConfigurationController mConfigurationController; + @Mock + private KeyguardBypassController mKeyguardBypassController; private StatusBarWindowController mStatusBarWindowController; @@ -63,7 +71,8 @@ public class StatusBarWindowControllerTest extends SysuiTestCase { when(mDozeParameters.getAlwaysOn()).thenReturn(true); mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, - mActivityManager, mDozeParameters); + mActivityManager, mDozeParameters, mStatusBarStateController, + mConfigurationController, mKeyguardBypassController); mStatusBarWindowController.add(mStatusBarView, 100 /* height */); } @@ -88,7 +97,8 @@ public class StatusBarWindowControllerTest extends SysuiTestCase { @Test public void testOnThemeChanged_doesntCrash() { mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, - mActivityManager, mDozeParameters); + mActivityManager, mDozeParameters, mStatusBarStateController, + mConfigurationController, mKeyguardBypassController); mStatusBarWindowController.onThemeChanged(); } @@ -100,7 +110,8 @@ public class StatusBarWindowControllerTest extends SysuiTestCase { @Test public void testSetForcePluginOpen_beforeStatusBarInitialization() { mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, - mActivityManager, mDozeParameters); + mActivityManager, mDozeParameters, mStatusBarStateController, + mConfigurationController, mKeyguardBypassController); mStatusBarWindowController.setForcePluginOpen(true); } } diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index d923bedd15c1..6b88f5a9a6d7 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -398,7 +398,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ if (!mSecurityPolicy.checkAccessibilityAccess(this)) { return null; } - AccessibilityWindowInfo window = mA11yWindowManager.findA11yWindowInfoById(windowId); + AccessibilityWindowInfo window = + mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId); if (window != null) { AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window); windowClone.setConnectionId(mId); @@ -1362,11 +1363,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ || (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS); if (!isA11yFocusAction) { final WindowInfo windowInfo = - mA11yWindowManager.findWindowInfoById(resolvedWindowId); + mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId); if (windowInfo != null) activityToken = windowInfo.activityToken; } final AccessibilityWindowInfo a11yWindowInfo = - mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId); + mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId); if (a11yWindowInfo != null && a11yWindowInfo.isInPictureInPictureMode() && mA11yWindowManager.getPictureInPictureActionReplacingConnection() != null && !isA11yFocusAction) { @@ -1419,11 +1420,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ int interactionId, int interrogatingPid, long interrogatingTid) { final RemoteAccessibilityConnection pipActionReplacingConnection = mA11yWindowManager.getPictureInPictureActionReplacingConnection(); - final AccessibilityWindowInfo windowInfo = - mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId); - if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode() + synchronized (mLock) { + final AccessibilityWindowInfo windowInfo = + mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId); + if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode() || (pipActionReplacingConnection == null)) { - return originalCallback; + return originalCallback; + } } return new ActionReplacingCallback(originalCallback, pipActionReplacingConnection.getRemote(), interactionId, diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 5111bec4913b..18b6f90f921f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -29,6 +29,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.accessibility.AccessibilityEvent; +import com.android.server.accessibility.gestures.TouchExplorer; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 814853694347..b5b3cd2fe530 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -542,7 +542,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (event.getWindowId() == AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) { // The replacer window isn't shown to services. Move its events into the pip. - AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindow(); + AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked(); if (pip != null) { int pipId = pip.getId(); event.setWindowId(pipId); @@ -771,7 +771,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (resolvedUserId != mCurrentUserId) { return null; } - if (mA11yWindowManager.findA11yWindowInfoById(windowId) == null) { + if (mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId) == null) { return null; } return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, windowId); @@ -816,7 +816,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } - boolean onGesture(AccessibilityGestureInfo gestureInfo) { + public boolean onGesture(AccessibilityGestureInfo gestureInfo) { synchronized (mLock) { boolean handled = notifyGestureLocked(gestureInfo, false); if (!handled) { @@ -905,15 +905,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action); } - int getActiveWindowId() { + public int getActiveWindowId() { return mA11yWindowManager.getActiveWindowId(mCurrentUserId); } - void onTouchInteractionStart() { + public void onTouchInteractionStart() { mA11yWindowManager.onTouchInteractionStart(); } - void onTouchInteractionEnd() { + public void onTouchInteractionEnd() { mA11yWindowManager.onTouchInteractionEnd(); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java index 1e224cfaea85..315d6fa287f2 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java @@ -429,7 +429,7 @@ public class AccessibilitySecurityPolicy { if (windowId == mAccessibilityWindowManager.getActiveWindowId(userId)) { return true; } - return mAccessibilityWindowManager.findA11yWindowInfoById(windowId) != null; + return mAccessibilityWindowManager.findA11yWindowInfoByIdLocked(windowId) != null; } private boolean isShellAllowedToRetrieveWindowLocked(int userId, int windowId) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java index 961168a46c7d..02f7821bd0d5 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java @@ -361,7 +361,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId); if (motionEventInjector != null && isTouchableDisplay) { motionEventInjector.injectEvents( - gestureSteps.getList(), mServiceInterface, sequence); + gestureSteps.getList(), mServiceInterface, sequence, displayId); } else { try { mServiceInterface.onPerformGestureResult(sequence, false); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java index c12929153781..9687098b6f3f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java @@ -52,13 +52,10 @@ import java.util.Collections; import java.util.List; /** - * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to receive - * {@link WindowInfo}s from window manager when there's an accessibility change in window. It also - * provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and + * This class provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and * {@link WindowInfo}s. */ -public class AccessibilityWindowManager - implements WindowManagerInternal.WindowsForAccessibilityCallback { +public class AccessibilityWindowManager { private static final String LOG_TAG = "AccessibilityWindowManager"; private static final boolean DEBUG = false; @@ -71,9 +68,6 @@ public class AccessibilityWindowManager private final AccessibilitySecurityPolicy mSecurityPolicy; private final AccessibilityUserManager mAccessibilityUserManager; - private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById = new SparseArray<>(); - private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>(); - // Connections and window tokens for cross-user windows private final SparseArray<RemoteAccessibilityConnection> mGlobalInteractionConnections = new SparseArray<>(); @@ -84,9 +78,6 @@ public class AccessibilityWindowManager mInteractionConnections = new SparseArray<>(); private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>(); - private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>(); - private List<AccessibilityWindowInfo> mWindows; - private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection; private int mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; @@ -95,15 +86,641 @@ public class AccessibilityWindowManager private long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; private boolean mTouchInteractionInProgress; - private boolean mHasWatchOutsideTouchWindow; - private boolean mTrackingWindows = false; + // TO-DO [Multi-Display] : make DisplayWindowObserver to plural + private DisplayWindowsObserver mDisplayWindowsObserver; + + /** + * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to + * receive {@link WindowInfo}s from window manager when there's an accessibility change in + * window and holds window lists information per display. + */ + private final class DisplayWindowsObserver implements + WindowManagerInternal.WindowsForAccessibilityCallback { + + private final int mDisplayId; + private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById = + new SparseArray<>(); + private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>(); + private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>(); + private List<AccessibilityWindowInfo> mWindows; + private boolean mTrackingWindows = false; + private boolean mHasWatchOutsideTouchWindow; + + /** + * Constructor for DisplayWindowsObserver. + */ + DisplayWindowsObserver(int displayId) { + mDisplayId = displayId; + } + + /** + * Starts tracking windows changes from window manager by registering callback. + * + * @return true if callback registers successful. + */ + boolean startTrackingWindowsLocked() { + boolean result = true; + + if (!mTrackingWindows) { + // Turns on the flag before setup the callback. + // In some cases, onWindowsForAccessibilityChanged will be called immediately in + // setWindowsForAccessibilityCallback. We'll lost windows if flag is false. + mTrackingWindows = true; + result = mWindowManagerInternal.setWindowsForAccessibilityCallback( + mDisplayId, this); + if (!result) { + mTrackingWindows = false; + Slog.w(LOG_TAG, "set windowsObserver callbacks fail, displayId:" + + mDisplayId); + } + } + return result; + } + + /** + * Stops tracking windows changes from window manager, and clear all windows info. + */ + void stopTrackingWindowsLocked() { + if (mTrackingWindows) { + mWindowManagerInternal.setWindowsForAccessibilityCallback( + mDisplayId, null); + mTrackingWindows = false; + clearWindowsLocked(); + } + } + + /** + * Returns true if windows changes tracking. + * + * @return true if windows changes tracking + */ + boolean isTrackingWindowsLocked() { + return mTrackingWindows; + } + + /** + * Returns accessibility windows. + * @return accessibility windows. + */ + @Nullable + List<AccessibilityWindowInfo> getWindowListLocked() { + return mWindows; + } + + /** + * Returns accessibility window info according to given windowId. + * + * @param windowId The windowId + * @return The accessibility window info + */ + @Nullable + AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) { + return mA11yWindowInfoById.get(windowId); + } + + /** + * Returns the window info according to given windowId. + * + * @param windowId The windowId + * @return The window info + */ + @Nullable + WindowInfo findWindowInfoByIdLocked(int windowId) { + return mWindowInfoById.get(windowId); + } + + /** + * Returns {@link AccessibilityWindowInfo} of PIP window. + * + * @return PIP accessibility window info + */ + @Nullable + AccessibilityWindowInfo getPictureInPictureWindowLocked() { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int i = 0; i < windowCount; i++) { + final AccessibilityWindowInfo window = mWindows.get(i); + if (window.isInPictureInPictureMode()) { + return window; + } + } + } + return null; + } + + /** + * Sets the active flag of the window according to given windowId, others set to inactive. + * + * @param windowId The windowId + */ + void setActiveWindowLocked(int windowId) { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int i = 0; i < windowCount; i++) { + AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == windowId) { + window.setActive(true); + mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( + AccessibilityEvent.obtainWindowsChangedEvent(windowId, + AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); + } else { + window.setActive(false); + } + } + } + } + + /** + * Sets the window accessibility focused according to given windowId, others set + * unfocused. + * + * @param windowId The windowId + */ + void setAccessibilityFocusedWindowLocked(int windowId) { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int i = 0; i < windowCount; i++) { + AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == windowId) { + window.setAccessibilityFocused(true); + mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( + AccessibilityEvent.obtainWindowsChangedEvent( + windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); + + } else { + window.setAccessibilityFocused(false); + } + } + } + } + + /** + * Computes partial interactive region of given windowId. + * + * @param windowId The windowId + * @param outRegion The output to which to write the bounds. + * @return true if outRegion is not empty. + */ + boolean computePartialInteractiveRegionForWindowLocked(int windowId, + @NonNull Region outRegion) { + if (mWindows == null) { + return false; + } + + // Windows are ordered in z order so start from the bottom and find + // the window of interest. After that all windows that cover it should + // be subtracted from the resulting region. Note that for accessibility + // we are returning only interactive windows. + Region windowInteractiveRegion = null; + boolean windowInteractiveRegionChanged = false; + + final int windowCount = mWindows.size(); + final Region currentWindowRegions = new Region(); + for (int i = windowCount - 1; i >= 0; i--) { + AccessibilityWindowInfo currentWindow = mWindows.get(i); + if (windowInteractiveRegion == null) { + if (currentWindow.getId() == windowId) { + currentWindow.getRegionInScreen(currentWindowRegions); + outRegion.set(currentWindowRegions); + windowInteractiveRegion = outRegion; + continue; + } + } else if (currentWindow.getType() + != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) { + currentWindow.getRegionInScreen(currentWindowRegions); + if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) { + windowInteractiveRegionChanged = true; + } + } + } + + return windowInteractiveRegionChanged; + } + + List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) { + final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId); + if (targetWindow != null && mHasWatchOutsideTouchWindow) { + final List<Integer> outsideWindowsId = new ArrayList<>(); + for (int i = 0; i < mWindowInfoById.size(); i++) { + final WindowInfo window = mWindowInfoById.valueAt(i); + if (window != null && window.layer < targetWindow.layer + && window.hasFlagWatchOutsideTouch) { + outsideWindowsId.add(mWindowInfoById.keyAt(i)); + } + } + return outsideWindowsId; + } + return Collections.emptyList(); + } + + /** + * Callbacks from window manager when there's an accessibility change in windows. + * + * @param forceSend Send the windows for accessibility even if they haven't changed. + * @param windows The windows for accessibility. + */ + @Override + public void onWindowsForAccessibilityChanged(boolean forceSend, + @NonNull List<WindowInfo> windows) { + synchronized (mLock) { + if (DEBUG) { + Slog.i(LOG_TAG, "Display Id = " + mDisplayId); + Slog.i(LOG_TAG, "Windows changed: " + windows); + } + if (shouldUpdateWindowsLocked(forceSend, windows)) { + cacheWindows(windows); + // Lets the policy update the focused and active windows. + updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), + windows); + // Someone may be waiting for the windows - advertise it. + mLock.notifyAll(); + } + } + } + + private boolean shouldUpdateWindowsLocked(boolean forceSend, + @NonNull List<WindowInfo> windows) { + if (forceSend) { + return true; + } + + final int windowCount = windows.size(); + // We computed the windows and if they changed notify the client. + if (mCachedWindowInfos.size() != windowCount) { + // Different size means something changed. + return true; + } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) { + // Since we always traverse windows from high to low layer + // the old and new windows at the same index should be the + // same, otherwise something changed. + for (int i = 0; i < windowCount; i++) { + WindowInfo oldWindow = mCachedWindowInfos.get(i); + WindowInfo newWindow = windows.get(i); + // We do not care for layer changes given the window + // order does not change. This brings no new information + // to the clients. + if (windowChangedNoLayer(oldWindow, newWindow)) { + return true; + } + } + } + + return false; + } + + private void cacheWindows(List<WindowInfo> windows) { + final int oldWindowCount = mCachedWindowInfos.size(); + for (int i = oldWindowCount - 1; i >= 0; i--) { + mCachedWindowInfos.remove(i).recycle(); + } + final int newWindowCount = windows.size(); + for (int i = 0; i < newWindowCount; i++) { + WindowInfo newWindow = windows.get(i); + mCachedWindowInfos.add(WindowInfo.obtain(newWindow)); + } + } + + private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) { + if (oldWindow == newWindow) { + return false; + } + if (oldWindow == null) { + return true; + } + if (newWindow == null) { + return true; + } + if (oldWindow.type != newWindow.type) { + return true; + } + if (oldWindow.focused != newWindow.focused) { + return true; + } + if (oldWindow.token == null) { + if (newWindow.token != null) { + return true; + } + } else if (!oldWindow.token.equals(newWindow.token)) { + return true; + } + if (oldWindow.parentToken == null) { + if (newWindow.parentToken != null) { + return true; + } + } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) { + return true; + } + if (oldWindow.activityToken == null) { + if (newWindow.activityToken != null) { + return true; + } + } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) { + return true; + } + if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) { + return true; + } + if (oldWindow.childTokens != null && newWindow.childTokens != null + && !oldWindow.childTokens.equals(newWindow.childTokens)) { + return true; + } + if (!TextUtils.equals(oldWindow.title, newWindow.title)) { + return true; + } + if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) { + return true; + } + if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) { + return true; + } + if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) { + return true; + } + if (oldWindow.displayId != newWindow.displayId) { + return true; + } + return false; + } + + /** + * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s. + */ + private void clearWindowsLocked() { + final List<WindowInfo> windows = Collections.emptyList(); + final int activeWindowId = mActiveWindowId; + // UserId is useless in updateWindowsLocked, when we update a empty window list. + // Just pass current userId here. + updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows); + // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility + // interaction connection removed. + mActiveWindowId = activeWindowId; + mWindows = null; + } + + /** + * Updates windows info according to specified userId and windows. + * + * @param userId The userId to update + * @param windows The windows to update + */ + private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) { + if (mWindows == null) { + mWindows = new ArrayList<>(); + } + + final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows); + final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone(); + + mWindows.clear(); + mA11yWindowInfoById.clear(); + + for (int i = 0; i < mWindowInfoById.size(); i++) { + mWindowInfoById.valueAt(i).recycle(); + } + mWindowInfoById.clear(); + mHasWatchOutsideTouchWindow = false; + mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + if (!mTouchInteractionInProgress) { + mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + } + + // If the active window goes away while the user is touch exploring we + // reset the active window id and wait for the next hover event from + // under the user's finger to determine which one is the new one. It + // is possible that the finger is not moving and the input system + // filters out such events. + boolean activeWindowGone = true; + + final int windowCount = windows.size(); + + // We'll clear accessibility focus if the window with focus is no longer visible to + // accessibility services + boolean shouldClearAccessibilityFocus = + mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + if (windowCount > 0) { + for (int i = 0; i < windowCount; i++) { + final WindowInfo windowInfo = windows.get(i); + final AccessibilityWindowInfo window; + if (isTrackingWindowsLocked()) { + window = populateReportedWindowLocked(userId, windowInfo); + } else { + window = null; + } + if (window != null) { + + // Flip layers in list to be consistent with AccessibilityService#getWindows + window.setLayer(windowCount - 1 - window.getLayer()); + + final int windowId = window.getId(); + if (window.isFocused()) { + mFocusedWindowId = windowId; + if (!mTouchInteractionInProgress) { + mActiveWindowId = windowId; + window.setActive(true); + } else if (windowId == mActiveWindowId) { + activeWindowGone = false; + } + } + if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) { + mHasWatchOutsideTouchWindow = true; + } + mWindows.add(window); + mA11yWindowInfoById.put(windowId, window); + mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo)); + } + } + + if (mTouchInteractionInProgress && activeWindowGone) { + mActiveWindowId = mFocusedWindowId; + } + + // Focused window may change the active one, so set the + // active window once we decided which it is. + final int accessibilityWindowCount = mWindows.size(); + for (int i = 0; i < accessibilityWindowCount; i++) { + final AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == mActiveWindowId) { + window.setActive(true); + } + if (window.getId() == mAccessibilityFocusedWindowId) { + window.setAccessibilityFocused(true); + shouldClearAccessibilityFocus = false; + } + } + } + + sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById); + + final int oldWindowCount = oldWindowList.size(); + for (int i = oldWindowCount - 1; i >= 0; i--) { + oldWindowList.remove(i).recycle(); + } + + if (shouldClearAccessibilityFocus) { + clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); + } + } + + private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows, + SparseArray<AccessibilityWindowInfo> oldWindowsById) { + List<AccessibilityEvent> events = new ArrayList<>(); + // Sends events for all removed windows. + final int oldWindowsCount = oldWindows.size(); + for (int i = 0; i < oldWindowsCount; i++) { + final AccessibilityWindowInfo window = oldWindows.get(i); + if (mA11yWindowInfoById.get(window.getId()) == null) { + events.add(AccessibilityEvent.obtainWindowsChangedEvent( + window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED)); + } + } + + // Looks for other changes. + final int newWindowCount = mWindows.size(); + for (int i = 0; i < newWindowCount; i++) { + final AccessibilityWindowInfo newWindow = mWindows.get(i); + final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId()); + if (oldWindow == null) { + events.add(AccessibilityEvent.obtainWindowsChangedEvent( + newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED)); + } else { + int changes = newWindow.differenceFrom(oldWindow); + if (changes != 0) { + events.add(AccessibilityEvent.obtainWindowsChangedEvent( + newWindow.getId(), changes)); + } + } + } + + final int numEvents = events.size(); + for (int i = 0; i < numEvents; i++) { + mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i)); + } + } + + private AccessibilityWindowInfo populateReportedWindowLocked(int userId, + WindowInfo window) { + final int windowId = findWindowIdLocked(userId, window.token); + if (windowId < 0) { + return null; + } + + final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain(); + + reportedWindow.setId(windowId); + reportedWindow.setType(getTypeForWindowManagerWindowType(window.type)); + reportedWindow.setLayer(window.layer); + reportedWindow.setFocused(window.focused); + reportedWindow.setRegionInScreen(window.regionInScreen); + reportedWindow.setTitle(window.title); + reportedWindow.setAnchorId(window.accessibilityIdOfAnchor); + reportedWindow.setPictureInPicture(window.inPictureInPicture); + reportedWindow.setDisplayId(window.displayId); + + final int parentId = findWindowIdLocked(userId, window.parentToken); + if (parentId >= 0) { + reportedWindow.setParentId(parentId); + } + + if (window.childTokens != null) { + final int childCount = window.childTokens.size(); + for (int i = 0; i < childCount; i++) { + final IBinder childToken = window.childTokens.get(i); + final int childId = findWindowIdLocked(userId, childToken); + if (childId >= 0) { + reportedWindow.addChild(childId); + } + } + } + + return reportedWindow; + } + + private int getTypeForWindowManagerWindowType(int windowType) { + switch (windowType) { + case WindowManager.LayoutParams.TYPE_APPLICATION: + case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: + case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: + case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: + case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION: + case WindowManager.LayoutParams.TYPE_PHONE: + case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: + case WindowManager.LayoutParams.TYPE_TOAST: + case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: { + return AccessibilityWindowInfo.TYPE_APPLICATION; + } + + case WindowManager.LayoutParams.TYPE_INPUT_METHOD: + case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: { + return AccessibilityWindowInfo.TYPE_INPUT_METHOD; + } + + case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: + case WindowManager.LayoutParams.TYPE_SEARCH_BAR: + case WindowManager.LayoutParams.TYPE_STATUS_BAR: + case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL: + case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: + case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: + case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: + case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: + case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: + case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY: + case WindowManager.LayoutParams.TYPE_SCREENSHOT: { + return AccessibilityWindowInfo.TYPE_SYSTEM; + } + + case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { + return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER; + } + + case TYPE_ACCESSIBILITY_OVERLAY: { + return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; + } + + default: { + return -1; + } + } + } + + /** + * Dumps all {@link AccessibilityWindowInfo}s here. + */ + void dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args) { + if (mWindows != null) { + final int windowCount = mWindows.size(); + for (int j = 0; j < windowCount; j++) { + if (j == 0) { + pw.append("Display["); + pw.append(Integer.toString(mDisplayId)); + pw.append("] : "); + pw.println(); + } + if (j > 0) { + pw.append(','); + pw.println(); + } + pw.append("Window["); + AccessibilityWindowInfo window = mWindows.get(j); + pw.append(window.toString()); + pw.append(']'); + } + pw.println(); + } + } + } /** * Interface to send {@link AccessibilityEvent}. */ public interface AccessibilityEventSender { /** - * Send {@link AccessibilityEvent} for current user. + * Sends {@link AccessibilityEvent} for current user. */ void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event); } @@ -171,166 +788,24 @@ public class AccessibilityWindowManager mAccessibilityEventSender = accessibilityEventSender; mSecurityPolicy = securityPolicy; mAccessibilityUserManager = accessibilityUserManager; - + mDisplayWindowsObserver = new DisplayWindowsObserver(Display.DEFAULT_DISPLAY); } /** - * Callbacks from window manager when there's an accessibility change in windows. - * - * @param forceSend Send the windows for accessibility even if they haven't changed. - * @param windows The windows of current display for accessibility. - */ - @Override - public void onWindowsForAccessibilityChanged(boolean forceSend, - @NonNull List<WindowInfo> windows) { - synchronized (mLock) { - if (DEBUG) { - Slog.i(LOG_TAG, "Windows changed: " + windows); - } - - if (shouldUpdateWindowsLocked(forceSend, windows)) { - cacheWindows(windows); - // Let the policy update the focused and active windows. - updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows); - // Someone may be waiting for the windows - advertise it. - mLock.notifyAll(); - } - } - } - - private boolean shouldUpdateWindowsLocked(boolean forceSend, - @NonNull List<WindowInfo> windows) { - if (forceSend) { - return true; - } - - final int windowCount = windows.size(); - // We computed the windows and if they changed notify the client. - if (mCachedWindowInfos.size() != windowCount) { - // Different size means something changed. - return true; - } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) { - // Since we always traverse windows from high to low layer - // the old and new windows at the same index should be the - // same, otherwise something changed. - for (int i = 0; i < windowCount; i++) { - WindowInfo oldWindow = mCachedWindowInfos.get(i); - WindowInfo newWindow = windows.get(i); - // We do not care for layer changes given the window - // order does not change. This brings no new information - // to the clients. - if (windowChangedNoLayer(oldWindow, newWindow)) { - return true; - } - } - } - - return false; - } - - private void cacheWindows(List<WindowInfo> windows) { - final int oldWindowCount = mCachedWindowInfos.size(); - for (int i = oldWindowCount - 1; i >= 0; i--) { - mCachedWindowInfos.remove(i).recycle(); - } - final int newWindowCount = windows.size(); - for (int i = 0; i < newWindowCount; i++) { - WindowInfo newWindow = windows.get(i); - mCachedWindowInfos.add(WindowInfo.obtain(newWindow)); - } - } - - private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) { - if (oldWindow == newWindow) { - return false; - } - if (oldWindow == null) { - return true; - } - if (newWindow == null) { - return true; - } - if (oldWindow.type != newWindow.type) { - return true; - } - if (oldWindow.focused != newWindow.focused) { - return true; - } - if (oldWindow.token == null) { - if (newWindow.token != null) { - return true; - } - } else if (!oldWindow.token.equals(newWindow.token)) { - return true; - } - if (oldWindow.parentToken == null) { - if (newWindow.parentToken != null) { - return true; - } - } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) { - return true; - } - if (oldWindow.activityToken == null) { - if (newWindow.activityToken != null) { - return true; - } - } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) { - return true; - } - if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) { - return true; - } - if (oldWindow.childTokens != null && newWindow.childTokens != null - && !oldWindow.childTokens.equals(newWindow.childTokens)) { - return true; - } - if (!TextUtils.equals(oldWindow.title, newWindow.title)) { - return true; - } - if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) { - return true; - } - if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) { - return true; - } - if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) { - return true; - } - if (oldWindow.displayId != newWindow.displayId) { - return true; - } - return false; - } - - /** - * Start tracking windows changes from window manager. + * Starts tracking windows changes from window manager. */ public void startTrackingWindows() { synchronized (mLock) { - if (!mTrackingWindows) { - // Turn on the flag before setup the callback. - // In some cases, onWindowsForAccessibilityChanged will be called immediately in - // setWindowsForAccessibilityCallback. We'll lost windows if flag is false. - mTrackingWindows = true; - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY - mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY, - this); - } + mDisplayWindowsObserver.startTrackingWindowsLocked(); } } /** - * stop tracking windows changes from window manager, and clear all windows info. + * Stops tracking windows changes from window manager, and clear all windows info. */ public void stopTrackingWindows() { synchronized (mLock) { - if (mTrackingWindows) { - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY - mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY, - null); - mTrackingWindows = false; - clearWindowsLocked(); - } + mDisplayWindowsObserver.stopTrackingWindowsLocked(); } } @@ -340,127 +815,7 @@ public class AccessibilityWindowManager * @return true if windows changes tracking */ public boolean isTrackingWindowsLocked() { - return mTrackingWindows; - } - - /** - * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s. - */ - private void clearWindowsLocked() { - final List<WindowInfo> windows = Collections.emptyList(); - final int activeWindowId = mActiveWindowId; - // userId is useless in updateWindowsLocked, when we update a empty window list. Just pass - // current userId here. - updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows); - // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility - // interaction connection removed. - mActiveWindowId = activeWindowId; - mWindows = null; - } - - /** - * Update windows info according to specified userId and windows. - * - * @param userId The userId to update - * @param windows The windows to update - */ - private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) { - if (mWindows == null) { - mWindows = new ArrayList<>(); - } - - final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows); - final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone(); - - mWindows.clear(); - mA11yWindowInfoById.clear(); - - for (int i = 0; i < mWindowInfoById.size(); i++) { - mWindowInfoById.valueAt(i).recycle(); - } - mWindowInfoById.clear(); - mHasWatchOutsideTouchWindow = false; - - mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - if (!mTouchInteractionInProgress) { - mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - } - - // If the active window goes away while the user is touch exploring we - // reset the active window id and wait for the next hover event from - // under the user's finger to determine which one is the new one. It - // is possible that the finger is not moving and the input system - // filters out such events. - boolean activeWindowGone = true; - - final int windowCount = windows.size(); - - // We'll clear accessibility focus if the window with focus is no longer visible to - // accessibility services - boolean shouldClearAccessibilityFocus = - mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - if (windowCount > 0) { - for (int i = 0; i < windowCount; i++) { - final WindowInfo windowInfo = windows.get(i); - final AccessibilityWindowInfo window; - if (isTrackingWindowsLocked()) { - window = populateReportedWindowLocked(userId, windowInfo); - } else { - window = null; - } - if (window != null) { - - // Flip layers in list to be consistent with AccessibilityService#getWindows - window.setLayer(windowCount - 1 - window.getLayer()); - - final int windowId = window.getId(); - if (window.isFocused()) { - mFocusedWindowId = windowId; - if (!mTouchInteractionInProgress) { - mActiveWindowId = windowId; - window.setActive(true); - } else if (windowId == mActiveWindowId) { - activeWindowGone = false; - } - } - if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) { - mHasWatchOutsideTouchWindow = true; - } - mWindows.add(window); - mA11yWindowInfoById.put(windowId, window); - mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo)); - } - } - - if (mTouchInteractionInProgress && activeWindowGone) { - mActiveWindowId = mFocusedWindowId; - } - - // Focused window may change the active one, so set the - // active window once we decided which it is. - final int accessibilityWindowCount = mWindows.size(); - for (int i = 0; i < accessibilityWindowCount; i++) { - final AccessibilityWindowInfo window = mWindows.get(i); - if (window.getId() == mActiveWindowId) { - window.setActive(true); - } - if (window.getId() == mAccessibilityFocusedWindowId) { - window.setAccessibilityFocused(true); - shouldClearAccessibilityFocus = false; - } - } - } - - sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById); - - final int oldWindowCount = oldWindowList.size(); - for (int i = oldWindowCount - 1; i >= 0; i--) { - oldWindowList.remove(i).recycle(); - } - - if (shouldClearAccessibilityFocus) { - clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); - } + return mDisplayWindowsObserver.isTrackingWindowsLocked(); } /** @@ -468,7 +823,7 @@ public class AccessibilityWindowManager */ @Nullable public List<AccessibilityWindowInfo> getWindowListLocked() { - return mWindows; + return mDisplayWindowsObserver.getWindowListLocked(); } /** @@ -494,7 +849,7 @@ public class AccessibilityWindowManager .resolveCallingUserIdEnforcingPermissionsLocked(userId); final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId()); - // Make sure the reported package is one the caller has access to. + // Makes sure the reported package is one the caller has access to. packageName = mSecurityPolicy.resolveValidReportedPackageLocked( packageName, UserHandle.getCallingAppId(), resolvedUserId); @@ -576,7 +931,7 @@ public class AccessibilityWindowManager } /** - * Resolve a connection wrapper for a window id + * Resolves a connection wrapper for a window id. * * @param userId The user id for any user-specific windows * @param windowId The id of the window of interest @@ -672,7 +1027,7 @@ public class AccessibilityWindowManager } /** - * Return the userId that owns the given window token, {@link UserHandle#USER_NULL} + * Returns the userId that owns the given window token, {@link UserHandle#USER_NULL} * if not found. * * @param windowToken The winodw token @@ -703,42 +1058,6 @@ public class AccessibilityWindowManager return -1; } - private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows, - SparseArray<AccessibilityWindowInfo> oldWindowsById) { - List<AccessibilityEvent> events = new ArrayList<>(); - // Send events for all removed windows - final int oldWindowsCount = oldWindows.size(); - for (int i = 0; i < oldWindowsCount; i++) { - final AccessibilityWindowInfo window = oldWindows.get(i); - if (mA11yWindowInfoById.get(window.getId()) == null) { - events.add(AccessibilityEvent.obtainWindowsChangedEvent( - window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED)); - } - } - - // Look for other changes - final int newWindowCount = mWindows.size(); - for (int i = 0; i < newWindowCount; i++) { - final AccessibilityWindowInfo newWindow = mWindows.get(i); - final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId()); - if (oldWindow == null) { - events.add(AccessibilityEvent.obtainWindowsChangedEvent( - newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED)); - } else { - int changes = newWindow.differenceFrom(oldWindow); - if (changes != 0) { - events.add(AccessibilityEvent.obtainWindowsChangedEvent( - newWindow.getId(), changes)); - } - } - } - - final int numEvents = events.size(); - for (int i = 0; i < numEvents; i++) { - mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i)); - } - } - /** * Computes partial interactive region of given windowId. * @@ -748,38 +1067,8 @@ public class AccessibilityWindowManager */ public boolean computePartialInteractiveRegionForWindowLocked(int windowId, @NonNull Region outRegion) { - if (mWindows == null) { - return false; - } - - // Windows are ordered in z order so start from the bottom and find - // the window of interest. After that all windows that cover it should - // be subtracted from the resulting region. Note that for accessibility - // we are returning only interactive windows. - Region windowInteractiveRegion = null; - boolean windowInteractiveRegionChanged = false; - - final int windowCount = mWindows.size(); - final Region currentWindowRegions = new Region(); - for (int i = windowCount - 1; i >= 0; i--) { - AccessibilityWindowInfo currentWindow = mWindows.get(i); - if (windowInteractiveRegion == null) { - if (currentWindow.getId() == windowId) { - currentWindow.getRegionInScreen(currentWindowRegions); - outRegion.set(currentWindowRegions); - windowInteractiveRegion = outRegion; - continue; - } - } else if (currentWindow.getType() - != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) { - currentWindow.getRegionInScreen(currentWindowRegions); - if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) { - windowInteractiveRegionChanged = true; - } - } - } - - return windowInteractiveRegionChanged; + return mDisplayWindowsObserver.computePartialInteractiveRegionForWindowLocked(windowId, + outRegion); } /** @@ -846,7 +1135,7 @@ public class AccessibilityWindowManager mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; } // Clear the window with focus if it no longer has focus and we aren't - // just moving focus from one view to the other in the same window + // just moving focus from one view to the other in the same window. if ((mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) && (mAccessibilityFocusedWindowId == windowId) && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)) { @@ -904,7 +1193,7 @@ public class AccessibilityWindowManager } /** - * Get the id of the current active window. + * Gets the id of the current active window. * * @return The userId */ @@ -923,20 +1212,7 @@ public class AccessibilityWindowManager mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); mActiveWindowId = windowId; - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo window = mWindows.get(i); - if (window.getId() == windowId) { - window.setActive(true); - mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( - AccessibilityEvent.obtainWindowsChangedEvent(windowId, - AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); - } else { - window.setActive(false); - } - } - } + mDisplayWindowsObserver.setActiveWindowLocked(windowId); } } @@ -948,21 +1224,7 @@ public class AccessibilityWindowManager WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); mAccessibilityFocusedWindowId = windowId; - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo window = mWindows.get(i); - if (window.getId() == windowId) { - window.setAccessibilityFocused(true); - mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( - AccessibilityEvent.obtainWindowsChangedEvent( - windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); - - } else { - window.setAccessibilityFocused(false); - } - } - } + mDisplayWindowsObserver.setAccessibilityFocusedWindowLocked(windowId); } } @@ -973,8 +1235,8 @@ public class AccessibilityWindowManager * @return The accessibility window info */ @Nullable - public AccessibilityWindowInfo findA11yWindowInfoById(int windowId) { - return mA11yWindowInfoById.get(windowId); + public AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) { + return mDisplayWindowsObserver.findA11yWindowInfoByIdLocked(windowId); } /** @@ -984,8 +1246,8 @@ public class AccessibilityWindowManager * @return The window info */ @Nullable - public WindowInfo findWindowInfoById(int windowId) { - return mWindowInfoById.get(windowId); + public WindowInfo findWindowInfoByIdLocked(int windowId) { + return mDisplayWindowsObserver.findWindowInfoByIdLocked(windowId); } /** @@ -1010,21 +1272,12 @@ public class AccessibilityWindowManager * @return PIP accessibility window info */ @Nullable - public AccessibilityWindowInfo getPictureInPictureWindow() { - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - final AccessibilityWindowInfo window = mWindows.get(i); - if (window.isInPictureInPictureMode()) { - return window; - } - } - } - return null; + public AccessibilityWindowInfo getPictureInPictureWindowLocked() { + return mDisplayWindowsObserver.getPictureInPictureWindowLocked(); } /** - * Set an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture + * Sets an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture * window. */ public void setPictureInPictureActionReplacingConnection( @@ -1060,7 +1313,8 @@ public class AccessibilityWindowManager final List<Integer> outsideWindowsIds; final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>(); synchronized (mLock) { - outsideWindowsIds = getWatchOutsideTouchWindowIdLocked(targetWindowId); + outsideWindowsIds = + mDisplayWindowsObserver.getWatchOutsideTouchWindowIdLocked(targetWindowId); for (int i = 0; i < outsideWindowsIds.size(); i++) { connectionList.add(getConnectionLocked(userId, outsideWindowsIds.get(i))); } @@ -1079,22 +1333,6 @@ public class AccessibilityWindowManager } } - private List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) { - final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId); - if (targetWindow != null && mHasWatchOutsideTouchWindow) { - final List<Integer> outsideWindowsId = new ArrayList<>(); - for (int i = 0; i < mWindowInfoById.size(); i++) { - final WindowInfo window = mWindowInfoById.valueAt(i); - if (window != null && window.layer < targetWindow.layer - && window.hasFlagWatchOutsideTouch) { - outsideWindowsId.add(mWindowInfoById.keyAt(i)); - } - } - return outsideWindowsId; - } - return Collections.emptyList(); - } - /** * Gets current input focused window token from window manager, and returns its windowId. * @@ -1108,96 +1346,6 @@ public class AccessibilityWindowManager } } - private AccessibilityWindowInfo populateReportedWindowLocked(int userId, WindowInfo window) { - final int windowId = findWindowIdLocked(userId, window.token); - if (windowId < 0) { - return null; - } - - final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain(); - - reportedWindow.setId(windowId); - reportedWindow.setType(getTypeForWindowManagerWindowType(window.type)); - reportedWindow.setLayer(window.layer); - reportedWindow.setFocused(window.focused); - reportedWindow.setRegionInScreen(window.regionInScreen); - reportedWindow.setTitle(window.title); - reportedWindow.setAnchorId(window.accessibilityIdOfAnchor); - reportedWindow.setPictureInPicture(window.inPictureInPicture); - reportedWindow.setDisplayId(window.displayId); - - final int parentId = findWindowIdLocked(userId, window.parentToken); - if (parentId >= 0) { - reportedWindow.setParentId(parentId); - } - - if (window.childTokens != null) { - final int childCount = window.childTokens.size(); - for (int i = 0; i < childCount; i++) { - final IBinder childToken = window.childTokens.get(i); - final int childId = findWindowIdLocked(userId, childToken); - if (childId >= 0) { - reportedWindow.addChild(childId); - } - } - } - - return reportedWindow; - } - - private int getTypeForWindowManagerWindowType(int windowType) { - switch (windowType) { - case WindowManager.LayoutParams.TYPE_APPLICATION: - case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: - case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: - case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: - case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: - case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: - case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: - case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION: - case WindowManager.LayoutParams.TYPE_PHONE: - case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: - case WindowManager.LayoutParams.TYPE_TOAST: - case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: { - return AccessibilityWindowInfo.TYPE_APPLICATION; - } - - case WindowManager.LayoutParams.TYPE_INPUT_METHOD: - case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: { - return AccessibilityWindowInfo.TYPE_INPUT_METHOD; - } - - case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: - case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: - case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: - case WindowManager.LayoutParams.TYPE_SEARCH_BAR: - case WindowManager.LayoutParams.TYPE_STATUS_BAR: - case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL: - case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: - case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: - case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: - case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: - case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: - case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: - case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY: - case WindowManager.LayoutParams.TYPE_SCREENSHOT: { - return AccessibilityWindowInfo.TYPE_SYSTEM; - } - - case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { - return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER; - } - - case TYPE_ACCESSIBILITY_OVERLAY: { - return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; - } - - default: { - return -1; - } - } - } - private boolean isValidUserForInteractionConnectionsLocked(int userId) { return mInteractionConnections.indexOfKey(userId) >= 0; } @@ -1251,22 +1399,9 @@ public class AccessibilityWindowManager } /** - * Dump all {@link AccessibilityWindowInfo}s here. + * Dumps all {@link AccessibilityWindowInfo}s here. */ public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { - if (mWindows != null) { - final int windowCount = mWindows.size(); - for (int j = 0; j < windowCount; j++) { - if (j > 0) { - pw.append(','); - pw.println(); - } - pw.append("Window["); - AccessibilityWindowInfo window = mWindows.get(j); - pw.append(window.toString()); - pw.append(']'); - } - pw.println(); - } + mDisplayWindowsObserver.dumpLocked(fd, pw, args); } } diff --git a/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java index ce54586c52ae..16457216801b 100644 --- a/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java +++ b/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java @@ -16,7 +16,7 @@ package com.android.server.accessibility; -abstract class BaseEventStreamTransformation implements EventStreamTransformation { +public abstract class BaseEventStreamTransformation implements EventStreamTransformation { private EventStreamTransformation mNext; @Override diff --git a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java index 7982996e7a4a..61aff9a360ba 100644 --- a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java +++ b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java @@ -54,7 +54,7 @@ import android.view.accessibility.AccessibilityEvent; * For example, if it received a down motion event followed by a cancel motion * event, it should not handle subsequent move and up events until it gets a down. */ -interface EventStreamTransformation { +public interface EventStreamTransformation { /** * Receives a motion event. Passed are the event transformed by previous diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java index 1d58e90bbb38..06ca054db14a 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java @@ -24,7 +24,7 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; -import static com.android.server.accessibility.GestureUtils.distance; +import static com.android.server.accessibility.gestures.GestureUtils.distance; import static java.lang.Math.abs; import static java.util.Arrays.asList; @@ -54,6 +54,7 @@ import android.view.ScaleGestureDetector.OnScaleGestureListener; import android.view.ViewConfiguration; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.accessibility.gestures.GestureUtils; import java.util.ArrayDeque; import java.util.Queue; diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java index 7b6a12822faa..3310cb4e3e79 100644 --- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java +++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java @@ -101,11 +101,12 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement * either complete or cancelled. */ public void injectEvents(List<GestureStep> gestureSteps, - IAccessibilityServiceClient serviceInterface, int sequence) { + IAccessibilityServiceClient serviceInterface, int sequence, int displayId) { SomeArgs args = SomeArgs.obtain(); args.arg1 = gestureSteps; args.arg2 = serviceInterface; args.argi1 = sequence; + args.argi2 = displayId; mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args)); } @@ -146,7 +147,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement if (message.what == MESSAGE_INJECT_EVENTS) { SomeArgs args = (SomeArgs) message.obj; injectEventsMainThread((List<GestureStep>) args.arg1, - (IAccessibilityServiceClient) args.arg2, args.argi1); + (IAccessibilityServiceClient) args.arg2, args.argi1, args.argi2); args.recycle(); return true; } @@ -165,7 +166,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } private void injectEventsMainThread(List<GestureStep> gestureSteps, - IAccessibilityServiceClient serviceInterface, int sequence) { + IAccessibilityServiceClient serviceInterface, int sequence, int displayId) { if (mIsDestroyed) { try { serviceInterface.onPerformGestureResult(sequence, false); @@ -209,6 +210,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement for (int i = 0; i < events.size(); i++) { MotionEvent event = events.get(i); + event.setDisplayId(displayId); int isEndOfSequence = (i == events.size() - 1) ? 1 : 0; Message message = mHandler.obtainMessage( MESSAGE_SEND_MOTION_EVENT, isEndOfSequence, 0, event); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java index b4ac92f0cf55..9101a01bc8fe 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java @@ -14,7 +14,7 @@ ** limitations under the License. */ -package com.android.server.accessibility; +package com.android.server.accessibility.gestures; import android.accessibilityservice.AccessibilityGestureInfo; import android.accessibilityservice.AccessibilityService; diff --git a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java index d5b53bc686da..0f5dd08e02b4 100644 --- a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java @@ -1,4 +1,4 @@ -package com.android.server.accessibility; +package com.android.server.accessibility.gestures; import android.util.MathUtils; import android.view.MotionEvent; @@ -6,7 +6,7 @@ import android.view.MotionEvent; /** * Some helper functions for gesture detection. */ -final class GestureUtils { +public final class GestureUtils { private GestureUtils() { /* cannot be instantiated */ diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 380e853820ff..10c32ee87c13 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -14,11 +14,11 @@ ** limitations under the License. */ -package com.android.server.accessibility; +package com.android.server.accessibility.gestures; import static android.view.MotionEvent.INVALID_POINTER_ID; -import static com.android.server.accessibility.TouchState.ALL_POINTER_ID_BITS; +import static com.android.server.accessibility.gestures.TouchState.ALL_POINTER_ID_BITS; import android.accessibilityservice.AccessibilityGestureInfo; import android.content.Context; @@ -34,6 +34,8 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; +import com.android.server.accessibility.AccessibilityManagerService; +import com.android.server.accessibility.BaseEventStreamTransformation; import com.android.server.policy.WindowManagerPolicy; import java.util.ArrayList; @@ -58,7 +60,7 @@ import java.util.List; * * @hide */ -class TouchExplorer extends BaseEventStreamTransformation +public class TouchExplorer extends BaseEventStreamTransformation implements AccessibilityGestureDetector.Listener { private static final boolean DEBUG = false; diff --git a/services/accessibility/java/com/android/server/accessibility/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java index 7569b05abaac..820c1a794635 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchState.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.accessibility; +package com.android.server.accessibility.gestures; import static android.view.MotionEvent.INVALID_POINTER_ID; diff --git a/services/art-profile-boot b/services/art-profile-boot new file mode 100644 index 000000000000..23d709099cc0 --- /dev/null +++ b/services/art-profile-boot @@ -0,0 +1,326 @@ +Lcom/android/server/SystemServer;->run()V +Lcom/android/server/SystemServer;->main([Ljava/lang/String;)V +Lcom/android/server/SystemServer;->startBootstrapServices()V +Lcom/android/server/pm/PackageManagerService;->main(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)Lcom/android/server/pm/PackageManagerService; +Lcom/android/server/pm/PackageManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)V +Lcom/android/server/pm/Settings;->readLPw(Ljava/util/List;)Z +Lcom/android/server/pm/Settings;->readPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/Settings;->readInstallPermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;)V +Lcom/android/server/pm/permission/PermissionsState;->grantPermission(Lcom/android/server/pm/permission/BasePermission;I)I +Lcom/android/server/pm/permission/PermissionsState;->grantInstallPermission(Lcom/android/server/pm/permission/BasePermission;)I +Lcom/android/server/-$$Lambda$YWiwiKm_Qgqb55C6tTuq_n2JzdY;->run()V +Lcom/android/server/pm/PackageSignatures;->readXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;)V +Lcom/android/server/pm/permission/PermissionsState;->computeGids(I)[I +Lcom/android/server/am/-$$Lambda$BatteryExternalStatsWorker$ddVY5lmqswnSjXppAxPTOHbuzzQ;->run()V +Lcom/android/server/SystemServiceManager;->startService(Lcom/android/server/SystemService;)V +Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/Class;)Lcom/android/server/SystemService; +Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/String;)Lcom/android/server/SystemService; +Lcom/android/server/pm/permission/PermissionsState;->hasPermission(Ljava/lang/String;I)Z +Lcom/android/server/pm/permission/PermissionsState;->hasPermissionRequiringReview(I)Z +Lcom/android/server/am/ActivityManagerService$Lifecycle;-><init>(Landroid/content/Context;)V +Lcom/android/server/am/ActivityManagerService;-><init>(Landroid/content/Context;Lcom/android/server/wm/ActivityTaskManagerService;)V +Lcom/android/server/pm/Settings;->readSharedUserLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/permission/PermissionsState;->updatePermissionFlags(Lcom/android/server/pm/permission/BasePermission;III)Z +Lcom/android/server/pm/permission/PermissionsState;->ensurePermissionData(Lcom/android/server/pm/permission/BasePermission;)Lcom/android/server/pm/permission/PermissionsState$PermissionData; +Lcom/android/server/am/BatteryExternalStatsWorker$1;->run()V +Lcom/android/server/am/BatteryExternalStatsWorker;->updateExternalStatsLocked(Ljava/lang/String;IZZZ)V +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->grant(I)Z +Lcom/android/server/am/BatteryExternalStatsWorker$2;->run()V +Lcom/android/server/pm/permission/PermissionSettings;->getPermission(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; +Lcom/android/server/pm/permission/PermissionSettings;->getPermissionLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; +Lcom/android/server/pm/permission/PermissionSettings;->getPermissionTreeLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; +Lcom/android/server/pm/Settings;->readDisabledSysPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->updateFlags(III)Z +Lcom/android/server/pm/PackageSignatures;->readCertsListXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;Ljava/util/ArrayList;IZLandroid/content/pm/PackageParser$SigningDetails$Builder;)I +Lcom/android/server/pm/permission/PermissionsState$PermissionData;-><init>(Lcom/android/server/pm/permission/PermissionsState$PermissionData;)V +Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Landroid/util/ArrayMap;Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->readStateForUserSyncLPr(I)V +Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parseRuntimePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;I)V +Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parsePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;I)V +Lcom/android/server/pm/permission/BasePermission;->readLPw(Ljava/util/Map;Lorg/xmlpull/v1/XmlPullParser;)Z +Lcom/android/server/pm/Settings;->writeKernelMappingLPr()V +Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Ljava/lang/String;I[I)V +Lcom/android/server/pm/Settings;->readPackageRestrictionsLPr(I)V +Lcom/android/server/am/ActivityManagerService$Injector;->getAppOpsService(Ljava/io/File;Landroid/os/Handler;)Lcom/android/server/appop/AppOpsService; +Lcom/android/server/appop/AppOpsService;-><init>(Ljava/io/File;Landroid/os/Handler;)V +Lcom/android/server/appop/AppOpsService;->readState()V +Lcom/android/server/am/ProcessStatsService;-><init>(Lcom/android/server/am/ActivityManagerService;Ljava/io/File;)V +Lcom/android/server/pm/PackageManagerService;->scanDirTracedLI(Ljava/io/File;IIJ)V +Lcom/android/server/pm/PackageManagerService;->scanDirLI(Ljava/io/File;IIJ)V +Lcom/android/server/pm/PackageManagerService;->addForInitLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/pm/PackageManagerService;->scanPackageChildLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/pm/KeySetManagerService;->readKeySetsLPw(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;)V +Lcom/android/server/pm/ParallelPackageParser;->lambda$submit$0$ParallelPackageParser(Ljava/io/File;I)V +Lcom/android/server/pm/-$$Lambda$ParallelPackageParser$FTtinPrp068lVeI7K6bC1tNE3iM;->run()V +Lcom/android/server/pm/ParallelPackageParser;->parsePackage(Landroid/content/pm/PackageParser;Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/appop/AppOpsService;->readPackage(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/Settings;->addPackageLPw(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IJIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)Lcom/android/server/pm/PackageSetting; +Lcom/android/server/appop/AppOpsService;->readUid(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V +Lcom/android/server/appop/AppOpsService;->readUidOps(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/PackageSetting;-><init>(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/PackageSetting;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;I[Ljava/lang/String;[J)V +Lcom/android/server/pm/SELinuxMMAC;->readInstallPolicy()Z +Lcom/android/server/pm/KeySetManagerService;->readKeysLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/Settings;->writeIntToFile(Ljava/io/File;I)V +Lcom/android/server/pm/PackageSettingBase;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)V +Lcom/android/server/appop/AppOpsService;->readOp(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;Z)V +Lcom/android/server/pm/SELinuxMMAC;->readSignerOrThrow(Lorg/xmlpull/v1/XmlPullParser;)Lcom/android/server/pm/Policy; +Lcom/android/server/pm/Settings;->readComponentsLPr(Lorg/xmlpull/v1/XmlPullParser;)Landroid/util/ArraySet; +Lcom/android/server/pm/KeySetManagerService;->readPublicKeyLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/PackageManagerService;->scanPackageNewLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Lcom/android/server/pm/PackageManagerService$ScanResult; +Lcom/android/server/pm/permission/PermissionsState;->grantRuntimePermission(Lcom/android/server/pm/permission/BasePermission;I)I +Lcom/android/server/pm/Policy$PolicyBuilder;->addSignature(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder; +Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;)V +Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;Lcom/android/server/display/DisplayManagerService$Injector;)V +Lcom/android/server/am/ActivityManagerService;->start()V +Lcom/android/server/am/ActivityManagerService;->startAssociationLocked(ILjava/lang/String;IIJLandroid/content/ComponentName;Ljava/lang/String;)Lcom/android/server/am/ActivityManagerService$Association; +Lcom/android/server/am/ActivityManagerService;->startIsolatedProcess(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Runnable;)Z +Lcom/android/server/am/ActivityManagerService;->startObservingNativeCrashes()V +Lcom/android/server/am/ActivityManagerService;->startPersistentApps(I)V +Lcom/android/server/am/ActivityManagerService;->startProcessLocked(Ljava/lang/String;Landroid/content/pm/ApplicationInfo;ZILjava/lang/String;Landroid/content/ComponentName;ZZZ)Lcom/android/server/am/ProcessRecord; +Lcom/android/server/am/ActivityManagerService;->startService(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;ZLjava/lang/String;I)Landroid/content/ComponentName; +PLcom/android/server/am/ActivityManagerService;->startUserInBackgroundWithListener(ILandroid/os/IProgressListener;)Z +Lcom/android/server/am/ActivityManagerService$Lifecycle;->onStart()V +Lcom/android/server/pm/PackageManagerService;->scanPackageOnlyLI(Lcom/android/server/pm/PackageManagerService$ScanRequest;ZJ)Lcom/android/server/pm/PackageManagerService$ScanResult; +Lcom/android/server/pm/PackageSettingBase;->modifyUserState(I)Landroid/content/pm/PackageUserState; +Lcom/android/server/pm/PackageSettingBase;->modifyUserStateComponents(IZZ)Landroid/content/pm/PackageUserState; +Lcom/android/server/pm/Settings;->readDomainVerificationLPw(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/PackageSettingBase;)V +Lcom/android/server/pm/PackageSettingBase;->setEnabled(IILjava/lang/String;)V +Lcom/android/server/am/BatteryStatsService;-><init>(Landroid/content/Context;Ljava/io/File;Landroid/os/Handler;)V +Lcom/android/server/pm/PackageManagerService;->commitReconciledScanResultLocked(Lcom/android/server/pm/PackageManagerService$ReconciledPackage;)V +Lcom/android/server/pm/KeySetManagerService;->readKeySetListLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/appop/AppOpsService$Op;->accessed(JILjava/lang/String;II)V +Lcom/android/server/wm/ActivityTaskManagerService;->initialize(Lcom/android/server/firewall/IntentFirewall;Lcom/android/server/am/PendingIntentController;Landroid/os/Looper;)V +Lcom/android/server/pm/SettingBase;-><init>(II)V +Lcom/android/server/pm/PackageManagerService;->locationIsPrivileged(Ljava/lang/String;)Z +Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;)V +Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/PowerManagerService$Injector;)V +Lcom/android/server/pm/permission/PermissionsState;->enforceValidUserId(I)V +Lcom/android/server/Watchdog;->getInstance()Lcom/android/server/Watchdog; +Lcom/android/server/Watchdog;-><init>()V +Lcom/android/server/pm/PackageManagerService;->commitPackageSettings(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;IZLcom/android/server/pm/PackageManagerService$ReconciledPackage;)V +Lcom/android/server/pm/PackageSetting;->getPermissionsState()Lcom/android/server/pm/permission/PermissionsState; +Lcom/android/server/pm/Settings;->registerExistingAppIdLPw(ILcom/android/server/pm/SettingBase;Ljava/lang/Object;)Z +Lcom/android/server/pm/permission/PermissionManagerService;->create(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)Lcom/android/server/pm/permission/PermissionManagerServiceInternal; +Lcom/android/server/pm/Settings;->addSharedUserLPw(Ljava/lang/String;III)Lcom/android/server/pm/SharedUserSetting; +Lcom/android/server/pm/PackageSettingBase;->init(Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V +Lcom/android/server/appop/AppOpsService$Op;->updateProxyState(JILjava/lang/String;)V +Lcom/android/server/display/DisplayManagerService$DisplayAdapterListener;->onDisplayDeviceEvent(Lcom/android/server/display/DisplayDevice;I)V +Lcom/android/server/wm/ActivityTaskManagerService;->onActivityManagerInternalAdded()V +Lcom/android/server/SystemService;->publishBinderService(Ljava/lang/String;Landroid/os/IBinder;)V +Lcom/android/server/am/ActivityManagerService;->initPowerManagement()V +Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;-><init>(Landroid/content/Context;)V +Lcom/android/server/display/DisplayManagerService;->onStart()V +Lcom/android/server/pm/Settings;->readPreferredActivitiesLPw(Lorg/xmlpull/v1/XmlPullParser;I)V +Lcom/android/server/pm/PackageKeySetData;-><init>()V +Lcom/android/server/display/DisplayManagerService;->registerDefaultDisplayAdapters()V +Lcom/android/server/display/LocalDisplayAdapter;->registerLocked()V +Lcom/android/server/ServiceThread;->run()V +Lcom/android/server/display/DisplayModeDirector;-><init>(Landroid/content/Context;Landroid/os/Handler;)V +Lcom/android/server/pm/Settings;->addPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;)V +Lcom/android/server/pm/permission/PermissionManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)V +Lcom/android/server/appop/AppOpsService;->getUidStateLocked(IZ)Lcom/android/server/appop/AppOpsService$UidState; +Lcom/android/server/am/BatteryStatsService;->fillRailDataStats(Lcom/android/internal/os/RailStats;)V +Lcom/android/server/pm/SELinuxMMAC;->getSeInfo(Landroid/content/pm/PackageParser$Package;ZII)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService;->collectCertificatesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;ZZ)V +Lcom/android/server/pm/PackageManagerService;->reconcilePackagesLocked(Lcom/android/server/pm/PackageManagerService$ReconcileRequest;Lcom/android/server/pm/KeySetManagerService;)Ljava/util/Map; +Lcom/android/server/pm/permission/BasePermission;->readInt(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;I)I +Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;)V +Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;Ljava/io/File;)V +Lcom/android/server/display/LocalDisplayAdapter;->tryConnectDisplayLocked(J)V +Lcom/android/server/pm/PreferredActivity;-><init>(Landroid/content/IntentFilter;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V +Lcom/android/server/pm/PackageManagerService;->preparePackageParserCache()Ljava/io/File; +Lcom/android/server/pm/Policy$PolicyBuilder;->build()Lcom/android/server/pm/Policy; +Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;I)Ljava/lang/Object; +Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;IZ)Ljava/lang/Object; +Lcom/android/server/SystemServiceManager;->startBootPhase(I)V +Lcom/android/server/display/PersistentDataStore;->load()V +Lcom/android/server/display/PersistentDataStore;->loadDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/display/PersistentDataStore;->loadFromXml(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/display/PersistentDataStore;->loadRememberedWifiDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/wm/AppWarnings;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/content/Context;Landroid/os/Handler;Landroid/os/Handler;Ljava/io/File;)V +Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V +Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAdded(Lcom/android/server/display/DisplayDevice;)V +Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAddedLocked(Lcom/android/server/display/DisplayDevice;)V +Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->getDisplayDeviceInfoLocked()Lcom/android/server/display/DisplayDeviceInfo; +Lcom/android/server/pm/PackageSettingBase;->setUserState(IJIZZZZIZLjava/lang/String;Landroid/content/pm/SuspendDialogInfo;Landroid/os/PersistableBundle;Landroid/os/PersistableBundle;ZZLjava/lang/String;Landroid/util/ArraySet;Landroid/util/ArraySet;IIILjava/lang/String;)V +Lcom/android/server/pm/Installer;->onStart()V +Lcom/android/server/pm/Installer;->connect()V +Lcom/android/server/lights/LightsService$LightImpl;-><init>(Lcom/android/server/lights/LightsService;Landroid/content/Context;I)V +Lcom/android/server/pm/PackageManagerService;->addBuiltInSharedLibraryLocked(Ljava/lang/String;Ljava/lang/String;)Z +Lcom/android/server/LockGuard;->findOrCreateLockInfo(Ljava/lang/Object;)Lcom/android/server/LockGuard$LockInfo; +Lcom/android/server/lights/LightsService;-><init>(Landroid/content/Context;)V +Lcom/android/server/pm/Policy;->getMatchedSeInfo(Landroid/content/pm/PackageParser$Package;)Ljava/lang/String; +Lcom/android/server/ServiceThread;-><init>(Ljava/lang/String;IZ)V +Lcom/android/server/wm/ActivityTaskManagerService;->createStackSupervisor()Lcom/android/server/wm/ActivityStackSupervisor; +Lcom/android/server/Watchdog;->addMonitor(Lcom/android/server/Watchdog$Monitor;)V +Lcom/android/server/wm/ActivityStackSupervisor;->initPowerManagement()V +Lcom/android/server/wm/ActivityTaskManagerService;->onInitPowerManagement()V +Lcom/android/server/pm/KeySetManagerService;->addScannedPackageLPw(Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/am/BatteryStatsService;->initPowerManagement()V +Lcom/android/server/wm/ActivityTaskManagerService;-><init>(Landroid/content/Context;)V +Lcom/android/server/am/ProcessList;-><init>()V +Lcom/android/server/pm/PackageManagerService;->commitSharedLibraryInfoLocked(Landroid/content/pm/SharedLibraryInfo;)V +Lcom/android/server/pm/PackageManagerServiceUtils;->getLastModifiedTime(Landroid/content/pm/PackageParser$Package;)J +Lcom/android/server/am/ProcessStatsService;->updateFile()V +Lcom/android/server/pm/Policy$PolicyBuilder;->setGlobalSeinfoOrThrow(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder; +Lcom/android/server/wm/AppWarnings;->readConfigFromFileAmsThread()V +Lcom/android/server/am/BatteryStatsService;->fillLowPowerStats(Lcom/android/internal/os/RpmStats;)V +Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceChanged(Lcom/android/server/display/DisplayDevice;)V +Lcom/android/server/firewall/IntentFirewall;-><init>(Lcom/android/server/firewall/IntentFirewall$AMSInterface;Landroid/os/Handler;)V +Lcom/android/server/pm/PackageSettingBase;->getNotInstalledUserIds()[I +Lcom/android/server/appop/AppOpsService$UidState;->evalForegroundOps(Landroid/util/SparseArray;)V +Lcom/android/server/SystemServerInitThreadPool;->submit(Ljava/lang/Runnable;Ljava/lang/String;)Ljava/util/concurrent/Future; +Lcom/android/server/pm/KeySetManagerService;->addSigningKeySetToPackageLPw(Lcom/android/server/pm/PackageSetting;Landroid/util/ArraySet;)V +Lcom/android/server/pm/ComponentResolver;->addAllComponents(Landroid/content/pm/PackageParser$Package;Z)V +Lcom/android/server/appop/AppOpsService;->publish(Landroid/content/Context;)V +Lcom/android/server/power/PowerManagerService;->onStart()V +Lcom/android/server/os/DeviceIdentifiersPolicyService;->onStart()V +Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;-><init>(Landroid/content/Context;)V +Lcom/android/server/pm/PackageManagerService;->applyPolicy(Landroid/content/pm/PackageParser$Package;IILandroid/content/pm/PackageParser$Package;)V +Lcom/android/server/pm/KeySetManagerService;->addRefCountsFromSavedPackagesLPw(Landroid/util/ArrayMap;)V +Lcom/android/server/am/OomAdjuster;-><init>(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ProcessList;Lcom/android/server/am/ActiveUids;)V +Lcom/android/server/am/ProcessList;->init(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ActiveUids;)V +Lcom/android/server/pm/PackageManagerService$ScanRequest;-><init>(Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/SharedUserSetting;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Ljava/lang/String;IIZLandroid/os/UserHandle;)V +Lcom/android/server/pm/Settings;->writeUserRestrictionsLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;)V +PLcom/android/server/pm/permission/PermissionsState;-><init>(Lcom/android/server/pm/permission/PermissionsState;)V +Lcom/android/server/pm/UserManagerService;->readUserListLP()V +Lcom/android/server/RescueParty;->isUsbActive()Z +Lcom/android/server/RescueParty;->isDisabled()Z +Lcom/android/server/pm/SharedUserSetting;->addPackage(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;-><init>(Lcom/android/server/display/LocalDisplayAdapter;Landroid/os/IBinder;J[Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[IIZ)V +Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->run()V +Lcom/android/server/pm/PackageSettingBase;->doCopy(Lcom/android/server/pm/PackageSettingBase;)V +Lcom/android/server/SystemServerInitThreadPool;->get()Lcom/android/server/SystemServerInitThreadPool; +Lcom/android/server/pm/PreferredActivity;->onReadTag(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;)Z +Lcom/android/server/FgThread;->getHandler()Landroid/os/Handler; +Lcom/android/server/FgThread;->ensureThreadLocked()V +Lcom/android/server/IntentResolver;->addFilter(Landroid/content/IntentFilter;)V +Lcom/android/server/IntentResolver;->addFilter(Landroid/util/ArrayMap;Ljava/lang/String;Landroid/content/IntentFilter;)V +Lcom/android/server/pm/PackageManagerService;->assertPackageIsValid(Landroid/content/pm/PackageParser$Package;II)V +Lcom/android/server/pm/PackageManagerService;->getSettingsVersionForPackage(Landroid/content/pm/PackageParser$Package;)Lcom/android/server/pm/Settings$VersionInfo; +Lcom/android/server/pm/KeySetManagerService;->getPublicKeysFromKeySetLPr(J)Landroid/util/ArraySet; +Lcom/android/server/pm/ComponentResolver;->addActivitiesLocked(Landroid/content/pm/PackageParser$Package;Ljava/util/List;Z)V +Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->checkProperties()V +Lcom/android/server/pm/Settings;->getSettingLPr(I)Lcom/android/server/pm/SettingBase; +Lcom/android/server/uri/UriGrantsManagerService;-><init>(Landroid/content/Context;)V +Lcom/android/server/pm/Settings;-><init>(Ljava/io/File;Lcom/android/server/pm/permission/PermissionSettings;Ljava/lang/Object;)V +Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;->onStart()V +Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;->onStart()V +Lcom/android/server/pm/PackageSetting;->updateFrom(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/display/DisplayModeDirector$SettingsObserver;-><init>(Lcom/android/server/display/DisplayModeDirector;Landroid/content/Context;Landroid/os/Handler;)V +Lcom/android/server/power/batterysaver/BatterySaverController;-><init>(Ljava/lang/Object;Landroid/content/Context;Landroid/os/Looper;Lcom/android/server/power/batterysaver/BatterySaverPolicy;Lcom/android/server/power/batterysaver/BatterySavingStats;)V +Lcom/android/server/wm/ActivityStackSupervisor;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/os/Looper;)V +Lcom/android/server/PackageWatchdog;-><init>(Landroid/content/Context;)V +Lcom/android/server/PackageWatchdog;->getInstance(Landroid/content/Context;)Lcom/android/server/PackageWatchdog; +Lcom/android/server/pm/Settings;->getAllUsers(Lcom/android/server/pm/UserManagerService;)Ljava/util/List; +Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;)V +Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;J)V +Lcom/android/server/wm/RecentTasks;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Lcom/android/server/wm/ActivityStackSupervisor;)V +Lcom/android/server/pm/PackageSettingBase;->updateFrom(Lcom/android/server/pm/PackageSettingBase;)Lcom/android/server/pm/PackageSettingBase; +Lcom/android/server/pm/UserManagerService;->getUsers(Z)Ljava/util/List; +Lcom/android/server/firewall/IntentFirewall;->readRulesDir(Ljava/io/File;)V +Lcom/android/server/wm/TaskChangeNotificationController;-><init>(Ljava/lang/Object;Lcom/android/server/wm/ActivityStackSupervisor;Landroid/os/Handler;)V +Lcom/android/server/am/BatteryExternalStatsWorker;->awaitControllerInfo(Landroid/os/SynchronousResultReceiver;)Landroid/os/Parcelable; +Lcom/android/server/display/DisplayManagerService;->addLogicalDisplayLocked(Lcom/android/server/display/DisplayDevice;)Lcom/android/server/display/LogicalDisplay; +Lcom/android/server/display/DisplayManagerService;->updateLogicalDisplaysLocked()Z +Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->updatePhysicalDisplayInfoLocked([Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[II)Z +Lcom/android/server/display/DisplayDeviceInfo;->toString()Ljava/lang/String; +Lcom/android/server/UiThread;->run()V +Lcom/android/server/pm/PackageKeySetData;->setProperSigningKeySet(J)V +Lcom/android/server/UiThread;->ensureThreadLocked()V +Lcom/android/server/UiThread;->getHandler()Landroid/os/Handler; +Lcom/android/server/pm/Settings;->getPackageLPr(Ljava/lang/String;)Lcom/android/server/pm/PackageSetting; +Lcom/android/server/IoThread;->ensureThreadLocked()V +Lcom/android/server/IoThread;->getHandler()Landroid/os/Handler; +Lcom/android/server/pm/Settings;->getInternalVersion()Lcom/android/server/pm/Settings$VersionInfo; +Lcom/android/server/appop/AppOpsService$Op;->running(JJII)V +Lcom/android/server/appop/AppOpsService$Op;->updateAccessTimeAndDuration(JJII)V +Lcom/android/server/appop/AppOpsService$Op;->rejected(JILjava/lang/String;II)V +Lcom/android/server/DisplayThread;->ensureThreadLocked()V +Lcom/android/server/DisplayThread;->getHandler()Landroid/os/Handler; +Lcom/android/server/am/UserController;-><init>(Lcom/android/server/am/UserController$Injector;)V +Lcom/android/server/AnimationThread;->ensureThreadLocked()V +Lcom/android/server/AnimationThread;->getHandler()Landroid/os/Handler; +Lcom/android/server/wm/SurfaceAnimationThread;->ensureThreadLocked()V +Lcom/android/server/wm/SurfaceAnimationThread;->getHandler()Landroid/os/Handler; +Lcom/android/server/wm/ActivityStackSupervisor;->initialize()V +Lcom/android/server/pm/PackageSettingBase;->readUserState(I)Landroid/content/pm/PackageUserState; +Lcom/android/server/pm/PackageManagerServiceUtils;->getCompressedFiles(Ljava/lang/String;)[Ljava/io/File; +Lcom/android/server/pm/Settings;->insertPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->addActivity(Landroid/content/pm/PackageParser$Activity;Ljava/lang/String;Ljava/util/List;)V +Lcom/android/server/pm/Installer;->invalidateMounts()V +Lcom/android/server/power/PowerManagerService$NativeWrapper;->nativeInit(Lcom/android/server/power/PowerManagerService;)V +Lcom/android/server/power/ThermalManagerService;->onStart()V +Lcom/android/server/am/OomAdjProfiler;-><init>()V +Lcom/android/server/pm/PackageManagerService;->maybeClearProfilesForUpgradesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/am/ActivityManagerConstants;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;)V +Lcom/android/server/IntentResolver;-><init>()V +Lcom/android/server/pm/Settings;->updatePackageSetting(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/util/List;Lcom/android/server/pm/UserManagerService;[Ljava/lang/String;[J)V +Lcom/android/server/PackageWatchdog;->loadFromFile()V +Lcom/android/server/power/batterysaver/BatterySaverPolicy;-><init>(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)V +Lcom/android/server/power/AttentionDetector;-><init>(Ljava/lang/Runnable;Ljava/lang/Object;)V +Lcom/android/server/pm/dex/DexManager;-><init>(Landroid/content/Context;Landroid/content/pm/IPackageManager;Lcom/android/server/pm/PackageDexOptimizer;Lcom/android/server/pm/Installer;Ljava/lang/Object;)V +Lcom/android/server/appop/AppOpsService$Op;-><init>(Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;I)V +Lcom/android/server/pm/UserManagerService;->readUserLP(I)Lcom/android/server/pm/UserManagerService$UserData; +Lcom/android/server/pm/UserManagerService;->readUserLP(ILjava/io/InputStream;)Lcom/android/server/pm/UserManagerService$UserData; +Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;)Landroid/os/Bundle; +Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;Landroid/os/Bundle;)V +Lcom/android/server/pm/PackageManagerService;->adjustScanFlags(ILcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/os/UserHandle;Landroid/content/pm/PackageParser$Package;)I +Lcom/android/server/pm/SettingBase;->setFlags(I)V +Lcom/android/server/display/LogicalDisplay;->updateLocked(Ljava/util/List;)V +Lcom/android/server/Watchdog$HandlerChecker;->run()V +Lcom/android/server/Watchdog;->run()V +Lcom/android/server/display/DisplayAdapter$1;->run()V +Lcom/android/server/display/DisplayManagerService$DisplayManagerHandler;->handleMessage(Landroid/os/Message;)V +Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getAndCheckValidity(I)Ljava/lang/String; +Lcom/android/server/pm/ParallelPackageParser;->take()Lcom/android/server/pm/ParallelPackageParser$ParseResult; +Lcom/android/server/pm/KeySetManagerService;->assertScannedPackageValid(Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->run()V +Lcom/android/server/pm/PackageManagerServiceUtils;->verifySignatures(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$SigningDetails;ZZ)Z +Lcom/android/server/pm/PackageManagerService;->getSharedLibLatestVersionSetting(Lcom/android/server/pm/PackageManagerService$ScanResult;)Lcom/android/server/pm/PackageSetting; +Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayBrightness(I)V +Lcom/android/server/pm/PackageManagerService;->getLatestSharedLibraVersionLPr(Landroid/content/pm/PackageParser$Package;)Landroid/content/pm/SharedLibraryInfo; +Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getSystemPropertyName(I)Ljava/lang/String; +Lcom/android/server/lights/LightsService$LightImpl;->setLightLocked(IIIII)V +Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(I)V +Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(II)V +Lcom/android/server/Watchdog$HandlerChecker;->scheduleCheckLocked()V +Lcom/android/server/pm/permission/PermissionsState;->copyFrom(Lcom/android/server/pm/permission/PermissionsState;)V +Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissionGroups(Landroid/content/pm/PackageParser$Package;Z)V +Lcom/android/server/RecoverySystemService;->onStart()V +Lcom/android/server/display/DisplayManagerService;->onBootPhase(I)V +Lcom/android/server/am/ProcessList;->updateOomLevels(IIZ)V +Lcom/android/server/am/OomAdjProfiler;->batteryPowerChanged(Z)V +Lcom/android/server/pm/UserManagerService;->hasManageUsersOrPermission(Ljava/lang/String;)Z +Lcom/android/server/am/OomAdjProfiler;->scheduleSystemServerCpuTimeUpdate()V +Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Lcom/android/server/pm/PackageManagerService$1;)V +Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V +Lcom/android/server/wm/ConfigurationContainer;->onConfigurationChanged(Landroid/content/res/Configuration;)V +Lcom/android/server/wm/RootActivityContainer;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;)V +Lcom/android/server/wm/ActivityTaskManagerService;->createRecentTasks()Lcom/android/server/wm/RecentTasks; +Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked()V +Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z +Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked()V +Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z +Lcom/android/server/pm/Settings;->getRenamedPackageLPr(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/server/am/OomAdjProfiler;->updateSystemServerCpuTime(ZZ)V +Lcom/android/server/pm/UserManagerService;->getInstance()Lcom/android/server/pm/UserManagerService; +Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissions(Landroid/content/pm/PackageParser$Package;Z)V +Lcom/android/server/power/PowerManagerService$Injector;->createBatterySaverPolicy(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)Lcom/android/server/power/batterysaver/BatterySaverPolicy; +Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;)V +Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/ThermalManagerService$ThermalHalWrapper;)V +Lcom/android/server/display/PersistentDataStore$Injector;->openRead()Ljava/io/InputStream; +Lcom/android/server/pm/PackageManagerService$ReconciledPackage;-><init>(Lcom/android/server/pm/PackageManagerService$InstallArgs;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;Lcom/android/server/pm/PackageManagerService$PrepareResult;Lcom/android/server/pm/PackageManagerService$ScanResult;Lcom/android/server/pm/PackageManagerService$DeletePackageAction;Ljava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZLcom/android/server/pm/PackageManagerService$1;)V +Lcom/android/server/pm/ComponentResolver;-><init>(Lcom/android/server/pm/UserManagerService;Landroid/content/pm/PackageManagerInternal;Ljava/lang/Object;)V +Lcom/android/server/wm/LaunchParamsController;->registerDefaultModifiers(Lcom/android/server/wm/ActivityStackSupervisor;)V +Lcom/android/server/Watchdog$OpenFdMonitor;->create()Lcom/android/server/Watchdog$OpenFdMonitor; +Lcom/android/server/SystemServiceManager;->warnIfTooLong(JLcom/android/server/SystemService;Ljava/lang/String;)V +Lcom/android/server/am/UserController$Injector;->getLockPatternUtils()Lcom/android/internal/widget/LockPatternUtils; +Lcom/android/server/am/PendingIntentController;-><init>(Landroid/os/Looper;Lcom/android/server/am/UserController;)V +Lcom/android/server/am/BroadcastQueue;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;Ljava/lang/String;Lcom/android/server/am/BroadcastConstants;Z)V +Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayState(I)V +Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->waitWakeup()Ljava/lang/String; diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 46c2a85d0691..b4ee0b1abbd7 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2402,7 +2402,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Update the view states first... mCurrentViewId = viewState.id; - viewState.setCurrentValue(value); + if (value != null) { + viewState.setCurrentValue(value); + } if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) { if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")"); diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index d5a7c818bfb2..814f6daac43c 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -195,16 +195,20 @@ public class BackupManagerService { } boolean isAbleToServeUser(int userId) { - return getServiceUsers().get(UserHandle.USER_SYSTEM) != null - && getServiceUsers().get(userId) != null; + return getUserServices().get(UserHandle.USER_SYSTEM) != null + && getUserServices().get(userId) != null; } /** - * Returns a lst of users currently unlocked that have a - * {@link UserBackupManagerService} registered. + * Returns a list of users currently unlocked that have a {@link UserBackupManagerService} + * registered. + * + * Warning: Do NOT modify returned object as it's used inside. + * + * TODO: Return a copy or only expose read-only information through other means. */ @VisibleForTesting - public SparseArray<UserBackupManagerService> getServiceUsers() { + public SparseArray<UserBackupManagerService> getUserServices() { return mServiceUsers; } @@ -495,7 +499,8 @@ public class BackupManagerService { /** * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the - * serial number of the its ancestral work profile. + * serial number of the its ancestral work profile or null if there is no {@link + * UserBackupManagerService} associated with that user. * * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)} * and it corresponds to the profile that was used to restore to the callers profile. @@ -504,16 +509,18 @@ public class BackupManagerService { public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) { int callingUserId = Binder.getCallingUserHandle().getIdentifier(); long oldId = Binder.clearCallingIdentity(); - int[] userIds; + final int[] userIds; try { - userIds = mContext.getSystemService(UserManager.class).getProfileIds(callingUserId, - false); + userIds = + mContext + .getSystemService(UserManager.class) + .getProfileIds(callingUserId, false); } finally { Binder.restoreCallingIdentity(oldId); } for (int userId : userIds) { - UserBackupManagerService userBackupManagerService = getServiceUsers().get(userId); + UserBackupManagerService userBackupManagerService = getUserServices().get(userId); if (userBackupManagerService != null) { if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) { return UserHandle.of(userId); @@ -880,28 +887,35 @@ public class BackupManagerService { } /** Implementation to receive lifecycle event callbacks for system services. */ - public static final class Lifecycle extends SystemService { + public static class Lifecycle extends SystemService { public Lifecycle(Context context) { + this(context, new Trampoline(context)); + } + + @VisibleForTesting + Lifecycle(Context context, Trampoline trampoline) { super(context); - sInstance = new Trampoline(context); + sInstance = trampoline; } @Override public void onStart() { - publishBinderService(Context.BACKUP_SERVICE, sInstance); + publishService(Context.BACKUP_SERVICE, sInstance); } @Override public void onUnlockUser(int userId) { - if (userId == UserHandle.USER_SYSTEM) { - sInstance.initializeService(); - } - sInstance.unlockUser(userId); + sInstance.onUnlockUser(userId); } @Override public void onStopUser(int userId) { - sInstance.stopUser(userId); + sInstance.onStopUser(userId); + } + + @VisibleForTesting + void publishService(String name, IBinder service) { + publishBinderService(name, service); } } } diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java index f4b66456c27b..210a9ef94e53 100644 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -40,12 +40,12 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; -import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.server.backup.utils.RandomAccessFileUtils; @@ -73,9 +73,6 @@ import java.io.PrintWriter; * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through * privileged callers (currently {@link DevicePolicyManager}). This is called on {@link * UserHandle#USER_SYSTEM} and disables backup for all users. - * - * <p>Creation of the backup service is done when {@link UserHandle#USER_SYSTEM} is unlocked. The - * system user is unlocked before any other users. */ public class Trampoline extends IBackupManager.Stub { /** @@ -109,7 +106,10 @@ public class Trampoline extends IBackupManager.Stub { // TODD(b/121198006): remove this object and synchronized all methods on "this". private final Object mStateLock = new Object(); - private volatile BackupManagerService mService; + // TODO: This is not marked as final because of test code. Since we'll merge BMS and Trampoline, + // it doesn't make sense to refactor for final. It's never null. + @VisibleForTesting + protected volatile BackupManagerService mService; private final Handler mHandler; public Trampoline(Context context) { @@ -120,6 +120,13 @@ public class Trampoline extends IBackupManager.Stub { handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); mUserManager = UserManager.get(context); + mService = new BackupManagerService(mContext, this); + } + + // TODO: Remove this when we implement DI by injecting in the construtor. + @VisibleForTesting + Handler getBackupHandler() { + return mHandler; } protected boolean isBackupDisabled() { @@ -205,7 +212,7 @@ public class Trampoline extends IBackupManager.Stub { // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser), // it's used in multiple places where I/O waits would cause system lock-ups. private boolean isUserReadyForBackup(int userId) { - return mService != null && mService.isAbleToServeUser(userId); + return mService.isAbleToServeUser(userId); } /** @@ -230,68 +237,55 @@ public class Trampoline extends IBackupManager.Stub { return mUserManager; } - protected BackupManagerService createBackupManagerService() { - return new BackupManagerService(mContext, this); - } - protected void postToHandler(Runnable runnable) { mHandler.post(runnable); } /** - * Called from {@link BackupManagerService.Lifecycle} when the system user is unlocked. Attempts - * to initialize {@link BackupManagerService}. Offloads work onto the handler thread {@link - * #mHandlerThread} to keep unlock time low. - */ - void initializeService() { - postToHandler( - () -> { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init"); - if (mGlobalDisable) { - Slog.i(TAG, "Backup service not supported"); - return; - } - synchronized (mStateLock) { - if (mService == null) { - mService = createBackupManagerService(); - } - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - }); - } - - /** * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked. * Starts the backup service for this user if backup is active for this user. Offloads work onto - * the handler thread {@link #mHandlerThread} to keep unlock time low. + * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not + * essential for device functioning. */ - void unlockUser(int userId) { + void onUnlockUser(int userId) { postToHandler(() -> startServiceForUser(userId)); } private void startServiceForUser(int userId) { // We know that the user is unlocked here because it is called from setBackupServiceActive // and unlockUser which have these guarantees. So we can check if the file exists. - if (mService != null && isBackupActivatedForUser(userId)) { - Slog.i(TAG, "Starting service for user: " + userId); - mService.startServiceForUser(userId); + if (mGlobalDisable) { + Slog.i(TAG, "Backup service not supported"); + return; } + if (!isBackupActivatedForUser(userId)) { + Slog.i(TAG, "Backup not activated for user " + userId); + return; + } + Slog.i(TAG, "Starting service for user: " + userId); + mService.startServiceForUser(userId); } /** * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped. * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low. */ - void stopUser(int userId) { + void onStopUser(int userId) { postToHandler( () -> { - if (mService != null) { + if (!mGlobalDisable) { Slog.i(TAG, "Stopping service for user: " + userId); mService.stopServiceForUser(userId); } }); } + /** Returns {@link UserBackupManagerService} for user {@code userId}. */ + @Nullable + public UserBackupManagerService getUserService(int userId) { + return mService.getUserServices().get(userId); + } + /** * The system user and managed profiles can only be acted on by callers in the system or root * processes. Other users can be acted on by callers who have both android.permission.BACKUP and @@ -350,9 +344,6 @@ public class Trampoline extends IBackupManager.Stub { synchronized (mStateLock) { Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active"); if (makeActive) { - if (mService == null) { - mService = createBackupManagerService(); - } try { activateBackupForUserLocked(userId); } catch (IOException e) { @@ -380,7 +371,7 @@ public class Trampoline extends IBackupManager.Stub { } //TODO(b/121198006): loop through active users that have work profile and // stop them as well. - stopUser(userId); + onStopUser(userId); } } } @@ -388,8 +379,7 @@ public class Trampoline extends IBackupManager.Stub { // IBackupManager binder API /** - * Querying activity state of backup service. Calling this method before initialize yields - * undefined result. + * Querying activity state of backup service. * * @param userId The user in which the activity state of backup service is queried. * @return true if the service is active. @@ -397,7 +387,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public boolean isBackupServiceActive(int userId) { synchronized (mStateLock) { - return mService != null && isBackupActivatedForUser(userId); + return !mGlobalDisable && isBackupActivatedForUser(userId); } } @@ -598,8 +588,8 @@ public class Trampoline extends IBackupManager.Stub { @Override @Nullable public ComponentName getCurrentTransportComponentForUser(int userId) { - return (isUserReadyForBackup(userId)) ? mService.getCurrentTransportComponent(userId) - : null; + return (isUserReadyForBackup(userId)) + ? mService.getCurrentTransportComponent(userId) : null; } @Override @@ -614,8 +604,8 @@ public class Trampoline extends IBackupManager.Stub { @Override public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException { - return (isUserReadyForBackup(userId)) ? mService.listAllTransportComponents(userId) - : null; + return (isUserReadyForBackup(userId)) + ? mService.listAllTransportComponents(userId) : null; } @Override @@ -648,8 +638,8 @@ public class Trampoline extends IBackupManager.Stub { @Override public String selectBackupTransportForUser(int userId, String transport) throws RemoteException { - return (isUserReadyForBackup(userId)) ? mService.selectBackupTransport(userId, transport) - : null; + return (isUserReadyForBackup(userId)) + ? mService.selectBackupTransport(userId, transport) : null; } @Override @@ -700,8 +690,8 @@ public class Trampoline extends IBackupManager.Stub { @Override public Intent getDataManagementIntentForUser(int userId, String transport) throws RemoteException { - return isUserReadyForBackup(userId) ? mService.getDataManagementIntent(userId, transport) - : null; + return isUserReadyForBackup(userId) + ? mService.getDataManagementIntent(userId, transport) : null; } @Override @@ -784,15 +774,15 @@ public class Trampoline extends IBackupManager.Stub { @Override @Nullable public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) { - if (mService != null) { - return mService.getUserForAncestralSerialNumber(ancestralSerialNumber); + if (mGlobalDisable) { + return null; } - return null; + return mService.getUserForAncestralSerialNumber(ancestralSerialNumber); } @Override public void setAncestralSerialNumber(long ancestralSerialNumber) { - if (mService != null) { + if (!mGlobalDisable) { mService.setAncestralSerialNumber(ancestralSerialNumber); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 4f7900eefee2..e67ccc42f1e2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -150,7 +150,6 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.Xml; @@ -168,7 +167,6 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; -import com.android.internal.util.WakeupMessage; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.AutodestructReference; @@ -305,7 +303,8 @@ public class ConnectivityService extends IConnectivityManager.Stub /** Flag indicating if background data is restricted. */ private boolean mRestrictBackground; - final private Context mContext; + private final Context mContext; + private final Dependencies mDeps; // 0 is full bad, 100 is full good private int mDefaultInetConditionPublished = 0; @@ -586,11 +585,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private NetworkNotificationManager mNotifier; private LingerMonitor mLingerMonitor; - // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp - private static final int MIN_NET_ID = 100; // some reserved marks - private static final int MAX_NET_ID = 65535 - 0x0400; // Top 1024 bits reserved by IpSecService - private int mNextNetId = MIN_NET_ID; - // sequence number of NetworkRequests private int mNextNetworkRequestId = 1; @@ -834,19 +828,113 @@ public class ConnectivityService extends IConnectivityManager.Stub } }; + /** + * Dependencies of ConnectivityService, for injection in tests. + */ + @VisibleForTesting + public static class Dependencies { + /** + * Get system properties to use in ConnectivityService. + */ + public MockableSystemProperties getSystemProperties() { + return new MockableSystemProperties(); + } + + /** + * Create a HandlerThread to use in ConnectivityService. + */ + public HandlerThread makeHandlerThread() { + return new HandlerThread("ConnectivityServiceThread"); + } + + /** + * Get a reference to the NetworkStackClient. + */ + public NetworkStackClient getNetworkStack() { + return NetworkStackClient.getInstance(); + } + + /** + * @see Tethering + */ + public Tethering makeTethering(@NonNull Context context, + @NonNull INetworkManagementService nms, + @NonNull INetworkStatsService statsService, + @NonNull INetworkPolicyManager policyManager, + @NonNull TetheringDependencies tetheringDeps) { + return new Tethering(context, nms, statsService, policyManager, + IoThread.get().getLooper(), getSystemProperties(), tetheringDeps); + } + + /** + * @see ProxyTracker + */ + public ProxyTracker makeProxyTracker(@NonNull Context context, + @NonNull Handler connServiceHandler) { + return new ProxyTracker(context, connServiceHandler, EVENT_PROXY_HAS_CHANGED); + } + + /** + * @see NetIdManager + */ + public NetIdManager makeNetIdManager() { + return new NetIdManager(); + } + + /** + * @see NetworkUtils#queryUserAccess(int, int) + */ + public boolean queryUserAccess(int uid, int netId) { + return NetworkUtils.queryUserAccess(uid, netId); + } + + /** + * @see MultinetworkPolicyTracker + */ + public MultinetworkPolicyTracker makeMultinetworkPolicyTracker( + @NonNull Context c, @NonNull Handler h, @NonNull Runnable r) { + return new MultinetworkPolicyTracker(c, h, r); + } + + /** + * @see ServiceManager#checkService(String) + */ + public boolean hasService(@NonNull String name) { + return ServiceManager.checkService(name) != null; + } + + /** + * @see IpConnectivityMetrics.Logger + */ + public IpConnectivityMetrics.Logger getMetricsLogger() { + return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class), + "no IpConnectivityMetrics service"); + } + + /** + * @see IpConnectivityMetrics + */ + public IIpConnectivityMetrics getIpConnectivityMetrics() { + return IIpConnectivityMetrics.Stub.asInterface( + ServiceManager.getService(IpConnectivityLog.SERVICE_NAME)); + } + } + public ConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager) { - this(context, netManager, statsService, policyManager, - getDnsResolver(), new IpConnectivityLog(), NetdService.getInstance()); + this(context, netManager, statsService, policyManager, getDnsResolver(), + new IpConnectivityLog(), NetdService.getInstance(), new Dependencies()); } @VisibleForTesting protected ConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, - IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd) { + IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) { if (DBG) log("ConnectivityService starting up"); - mSystemProperties = getSystemProperties(); + mDeps = checkNotNull(deps, "missing Dependencies"); + mSystemProperties = mDeps.getSystemProperties(); + mNetIdManager = mDeps.makeNetIdManager(); mMetricsLog = logger; mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); @@ -863,7 +951,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mDefaultWifiRequest = createDefaultInternetRequestForTransport( NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST); - mHandlerThread = new HandlerThread("ConnectivityServiceThread"); + mHandlerThread = mDeps.makeHandlerThread(); mHandlerThread.start(); mHandler = new InternalHandler(mHandlerThread.getLooper()); mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper()); @@ -881,7 +969,7 @@ public class ConnectivityService extends IConnectivityManager.Stub LocalServices.getService(NetworkPolicyManagerInternal.class), "missing NetworkPolicyManagerInternal"); mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver"); - mProxyTracker = makeProxyTracker(); + mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler); mNetd = netd; mKeyStore = KeyStore.getInstance(); @@ -949,7 +1037,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Do the same for Ethernet, since it's often not specified in the configs, although many // devices can use it via USB host adapters. - if (mNetConfigs[TYPE_ETHERNET] == null && hasService(Context.ETHERNET_SERVICE)) { + if (mNetConfigs[TYPE_ETHERNET] == null && mDeps.hasService(Context.ETHERNET_SERVICE)) { mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET); mNetworksDefined++; } @@ -969,7 +1057,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); - mTethering = makeTethering(); + mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager, + makeTetheringDependencies()); mPermissionMonitor = new PermissionMonitor(mContext, mNetd); @@ -1028,7 +1117,7 @@ public class ConnectivityService extends IConnectivityManager.Stub LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS); mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit); - mMultinetworkPolicyTracker = createMultinetworkPolicyTracker( + mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker( mContext, mHandler, () -> rematchForAvoidBadWifiUpdate()); mMultinetworkPolicyTracker.start(); @@ -1038,10 +1127,8 @@ public class ConnectivityService extends IConnectivityManager.Stub registerPrivateDnsSettingsCallbacks(); } - @VisibleForTesting - protected Tethering makeTethering() { - // TODO: Move other elements into @Overridden getters. - final TetheringDependencies deps = new TetheringDependencies() { + private TetheringDependencies makeTetheringDependencies() { + return new TetheringDependencies() { @Override public boolean isTetheringSupported() { return ConnectivityService.this.isTetheringSupported(); @@ -1051,14 +1138,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return mDefaultRequest; } }; - return new Tethering(mContext, mNMS, mStatsService, mPolicyManager, - IoThread.get().getLooper(), new MockableSystemProperties(), - deps); - } - - @VisibleForTesting - protected ProxyTracker makeProxyTracker() { - return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED); } private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { @@ -1150,22 +1229,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return mNextNetworkRequestId++; } - @VisibleForTesting - protected int reserveNetId() { - synchronized (mNetworkForNetId) { - for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) { - int netId = mNextNetId; - if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID; - // Make sure NetID unused. http://b/16815182 - if (!mNetIdInUse.get(netId)) { - mNetIdInUse.put(netId, true); - return netId; - } - } - } - throw new IllegalStateException("No free netIds"); - } - private NetworkState getFilteredNetworkState(int networkType, int uid) { if (mLegacyTypeTracker.isTypeSupported(networkType)) { final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); @@ -1797,11 +1860,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } }; - @VisibleForTesting - protected void registerNetdEventCallback() { - final IIpConnectivityMetrics ipConnectivityMetrics = - IIpConnectivityMetrics.Stub.asInterface( - ServiceManager.getService(IpConnectivityLog.SERVICE_NAME)); + private void registerNetdEventCallback() { + final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics(); if (ipConnectivityMetrics == null) { Slog.wtf(TAG, "Missing IIpConnectivityMetrics"); return; @@ -2237,12 +2297,6 @@ public class ConnectivityService extends IConnectivityManager.Stub protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208"; private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd"; - // Overridden for testing purposes to avoid writing to SystemProperties. - @VisibleForTesting - protected MockableSystemProperties getSystemProperties() { - return new MockableSystemProperties(); - } - private void updateTcpBufferSizes(String tcpBufferSizes) { String[] values = null; if (tcpBufferSizes != null) { @@ -2632,8 +2686,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (valid != nai.lastValidated) { if (wasDefault) { - metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity( - SystemClock.elapsedRealtime(), valid); + mDeps.getMetricsLogger() + .defaultNetworkMetrics().logDefaultNetworkValidity( + SystemClock.elapsedRealtime(), valid); } final int oldScore = nai.getCurrentScore(); nai.lastValidated = valid; @@ -2968,8 +3023,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean wasDefault = isDefaultNetwork(nai); synchronized (mNetworkForNetId) { mNetworkForNetId.remove(nai.network.netId); - mNetIdInUse.delete(nai.network.netId); } + mNetIdManager.releaseNetId(nai.network.netId); // Just in case. mLegacyTypeTracker.remove(nai, wasDefault); } @@ -3016,7 +3071,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence // whose timestamps tell how long it takes to recover a default network. long now = SystemClock.elapsedRealtime(); - metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai); + mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai); } notifyIfacesChangedForNetworkStats(); // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied @@ -3070,9 +3125,7 @@ public class ConnectivityService extends IConnectivityManager.Stub destroyNativeNetwork(nai); mDnsManager.removeNetwork(nai.network); } - synchronized (mNetworkForNetId) { - mNetIdInUse.delete(nai.network.netId); - } + mNetIdManager.releaseNetId(nai.network.netId); } private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) { @@ -4156,7 +4209,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return null; } return getLinkPropertiesProxyInfo(activeNetwork); - } else if (queryUserAccess(Binder.getCallingUid(), network.netId)) { + } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.netId)) { // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which // caller may not have. return getLinkPropertiesProxyInfo(network); @@ -4165,10 +4218,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return null; } - @VisibleForTesting - protected boolean queryUserAccess(int uid, int netId) { - return NetworkUtils.queryUserAccess(uid, netId); - } private ProxyInfo getLinkPropertiesProxyInfo(Network network) { final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); @@ -4761,7 +4810,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final long ident = Binder.clearCallingIdentity(); try { // Concatenate the range of types onto the range of NetIDs. - int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE); + int id = NetIdManager.MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE); mNotifier.setProvNotificationVisible(visible, id, action); } finally { Binder.restoreCallingIdentity(ident); @@ -5372,10 +5421,9 @@ public class ConnectivityService extends IConnectivityManager.Stub @GuardedBy("mNetworkForNetId") private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>(); // NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId. - // An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so + // An entry is first reserved with NetIdManager, prior to being added to mNetworkForNetId, so // there may not be a strict 1:1 correlation between the two. - @GuardedBy("mNetworkForNetId") - private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray(); + private final NetIdManager mNetIdManager; // NetworkAgentInfo keyed off its connecting messenger // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays @@ -5477,9 +5525,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // satisfies mDefaultRequest. final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), - new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, - mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver, - mNMS, factorySerialNumber); + new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, + currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, + mDnsResolver, mNMS, factorySerialNumber); // Make sure the network capabilities reflect what the agent info says. nai.setNetworkCapabilities(mixInCapabilities(nai, nc)); final String extraInfo = networkInfo.getExtraInfo(); @@ -5488,7 +5536,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("registerNetworkAgent " + nai); final long token = Binder.clearCallingIdentity(); try { - getNetworkStack().makeNetworkMonitor( + mDeps.getNetworkStack().makeNetworkMonitor( nai.network, name, new NetworkMonitorCallbacks(nai)); } finally { Binder.restoreCallingIdentity(token); @@ -5500,11 +5548,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return nai.network.netId; } - @VisibleForTesting - protected NetworkStackClient getNetworkStack() { - return NetworkStackClient.getInstance(); - } - private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { nai.onNetworkMonitorCreated(networkMonitor); if (VDBG) log("Got NetworkAgent Messenger"); @@ -5520,7 +5563,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger); NetworkInfo networkInfo = nai.networkInfo; - nai.networkInfo = null; updateNetworkInfo(nai, networkInfo); updateUids(nai, null, nai.networkCapabilities); } @@ -6314,7 +6356,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Notify system services that this network is up. makeDefault(newNetwork); // Log 0 -> X and Y -> X default network transitions, where X is the new default. - metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent( + mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent( now, newNetwork, oldDefaultNetwork); // Have a new default network, release the transition wakelock in scheduleReleaseNetworkTransitionWakelock(); @@ -6519,8 +6561,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) { log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " + - (oldInfo == null ? "null" : oldInfo.getState()) + - " to " + state); + oldInfo.getState() + " to " + state); } if (!networkAgent.created @@ -6593,8 +6634,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO(b/122649188): send the broadcast only to VPN users. mProxyTracker.sendProxyBroadcast(); } - } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) || - state == NetworkInfo.State.SUSPENDED) { + } else if (networkAgent.created && (oldInfo.getState() == NetworkInfo.State.SUSPENDED || + state == NetworkInfo.State.SUSPENDED)) { // going into or coming out of SUSPEND: re-score and notify if (networkAgent.getCurrentScore() != oldScore) { rematchAllNetworksAndRequests(networkAgent, oldScore); @@ -6992,27 +7033,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return nwm.getWatchlistConfigHash(); } - @VisibleForTesting - MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) { - return new MultinetworkPolicyTracker(c, h, r); - } - - @VisibleForTesting - public WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int cmd, Object obj) { - return new WakeupMessage(c, h, s, cmd, 0, 0, obj); - } - - @VisibleForTesting - public boolean hasService(String name) { - return ServiceManager.checkService(name) != null; - } - - @VisibleForTesting - protected IpConnectivityMetrics.Logger metricsLogger() { - return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class), - "no IpConnectivityMetrics service"); - } - private void logNetworkEvent(NetworkAgentInfo nai, int evtype) { int[] transports = nai.networkCapabilities.getTransportTypes(); mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype)); diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 4d39f9ab8d78..bec08f45188f 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -39,6 +39,12 @@ option java_package com.android.server 27391 user_activity_timeout_override (override|2|3) 27392 battery_saver_setting (threshold|1) + +# --------------------------- +# ThermalManagerService.java +# --------------------------- +2737 thermal_changed (name|3),(type|1|5),(temperature|5),(sensor_status|1|5),(previous_system_status|1|5) + # # Leave IDs through 2740 for more power logs (2730 used by battery_discharge above) # diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index fe22dcda9683..a629b3fbb8fa 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -750,10 +750,10 @@ public class IpSecService extends IIpSecService.Stub { } } - // These values have been reserved in ConnectivityService + // These values have been reserved in NetIdManager @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00; - @VisibleForTesting static final int TUN_INTF_NETID_RANGE = 0x0400; + public static final int TUN_INTF_NETID_RANGE = 0x0400; private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray(); private int mNextTunnelNetIdIndex = 0; diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java new file mode 100644 index 000000000000..11533beade56 --- /dev/null +++ b/services/core/java/com/android/server/NetIdManager.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 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; + +import android.annotation.NonNull; +import android.util.SparseBooleanArray; + +import com.android.internal.annotations.GuardedBy; + +/** + * Class used to reserve and release net IDs. + * + * <p>Instances of this class are thread-safe. + */ +public class NetIdManager { + // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp + public static final int MIN_NET_ID = 100; // some reserved marks + // Top IDs reserved by IpSecService + public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE; + + @GuardedBy("mNetIdInUse") + private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray(); + + @GuardedBy("mNetIdInUse") + private int mLastNetId = MIN_NET_ID - 1; + + /** + * Get the first netId that follows the provided lastId and is available. + */ + private static int getNextAvailableNetIdLocked( + int lastId, @NonNull SparseBooleanArray netIdInUse) { + int netId = lastId; + for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) { + netId = netId < MAX_NET_ID ? netId + 1 : MIN_NET_ID; + if (!netIdInUse.get(netId)) { + return netId; + } + } + throw new IllegalStateException("No free netIds"); + } + + /** + * Reserve a new ID for a network. + */ + public int reserveNetId() { + synchronized (mNetIdInUse) { + mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse); + // Make sure NetID unused. http://b/16815182 + mNetIdInUse.put(mLastNetId, true); + return mLastNetId; + } + } + + /** + * Clear a previously reserved ID for a network. + */ + public void releaseNetId(int id) { + synchronized (mNetIdInUse) { + mNetIdInUse.delete(id); + } + } +} diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index 097a7d614ab6..80facbb3258c 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -21,7 +21,6 @@ import static android.app.ActivityManager.UID_OBSERVER_GONE; import android.annotation.IntDef; import android.annotation.Nullable; - import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.IActivityManager; @@ -59,24 +58,23 @@ import com.android.internal.app.ResolverActivity; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.function.pooled.PooledLambda; - import com.android.server.wm.ActivityTaskManagerInternal; + import dalvik.system.DexFile; import dalvik.system.VMRuntime; -import java.io.FileDescriptor; import java.io.Closeable; -import java.io.InputStream; import java.io.DataInputStream; +import java.io.FileDescriptor; import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.List; import java.util.ArrayList; - -import java.util.zip.ZipFile; +import java.util.List; import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * <p>PinnerService pins important files for key processes in memory.</p> @@ -97,6 +95,16 @@ public final class PinnerService extends SystemService { private static final int KEY_CAMERA = 0; private static final int KEY_HOME = 1; + // Pin the camera application. + private static boolean PROP_PIN_CAMERA = SystemProperties.getBoolean( + "pinner.pin_camera", true); + // Pin using pinlist.meta when pinning apps. + private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean( + "pinner.use_pinlist", true); + // Pin the whole odex/vdex/etc file when pinning apps. + private static boolean PROP_PIN_ODEX = SystemProperties.getBoolean( + "pinner.whole_odex", true); + private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); // 80MB max for camera app. private static final int MAX_HOME_PIN_SIZE = 6 * (1 << 20); // 6MB max for home app. @@ -160,7 +168,11 @@ public final class PinnerService extends SystemService { boolean shouldPinHome = context.getResources().getBoolean( com.android.internal.R.bool.config_pinnerHomeApp); if (shouldPinCamera) { - mPinKeys.add(KEY_CAMERA); + if (PROP_PIN_CAMERA) { + mPinKeys.add(KEY_CAMERA); + } else if (DEBUG) { + Slog.i(TAG, "Pinner - skip pinning camera app"); + } } if (shouldPinHome) { mPinKeys.add(KEY_HOME); @@ -573,17 +585,9 @@ public final class PinnerService extends SystemService { } // determine the ABI from either ApplicationInfo or Build - String arch = "arm"; - if (appInfo.primaryCpuAbi != null) { - if (VMRuntime.is64BitAbi(appInfo.primaryCpuAbi)) { - arch = arch + "64"; - } - } else { - if (VMRuntime.is64BitAbi(Build.SUPPORTED_ABIS[0])) { - arch = arch + "64"; - } - } - + String abi = appInfo.primaryCpuAbi != null ? appInfo.primaryCpuAbi : + Build.SUPPORTED_ABIS[0]; + String arch = VMRuntime.getInstructionSet(abi); // get the path to the odex or oat file String baseCodePath = appInfo.getBaseCodePath(); String[] files = null; @@ -599,10 +603,16 @@ public final class PinnerService extends SystemService { pf = pinFile(file, pinSizeLimit, /*attemptPinIntrospection=*/false); if (pf != null) { synchronized (this) { - pinnedApp.mFiles.add(pf); + if (PROP_PIN_ODEX) { + pinnedApp.mFiles.add(pf); + } } if (DEBUG) { - Slog.i(TAG, "Pinned " + pf.fileName); + if (PROP_PIN_ODEX) { + Slog.i(TAG, "Pinned " + pf.fileName); + } else { + Slog.i(TAG, "Pinned [skip] " + pf.fileName); + } } } } @@ -696,6 +706,13 @@ public final class PinnerService extends SystemService { * @return Open input stream or null on any error */ private static InputStream maybeOpenPinMetaInZip(ZipFile zipFile, String fileName) { + if (!PROP_PIN_PINLIST) { + if (DEBUG) { + Slog.i(TAG, "Pin - skip pinlist.meta in " + fileName); + } + return null; + } + ZipEntry pinMetaEntry = zipFile.getEntry(PIN_META_FILENAME); InputStream pinMetaStream = null; if (pinMetaEntry != null) { diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index deff7ef7d39a..ddde7fef8962 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3208,28 +3208,28 @@ class StorageManagerService extends IStorageManager.Stub // should be kept in sync with getFreeBytes(). final File path = storage.findPathForUuid(volumeUuid); - final long usable = path.getUsableSpace(); - final long lowReserved = storage.getStorageLowBytes(path); - final long fullReserved = storage.getStorageFullBytes(path); + long usable = 0; + long lowReserved = 0; + long fullReserved = 0; + long cacheClearable = 0; - if (stats.isQuotaSupported(volumeUuid)) { + if ((flags & StorageManager.FLAG_ALLOCATE_CACHE_ONLY) == 0) { + usable = path.getUsableSpace(); + lowReserved = storage.getStorageLowBytes(path); + fullReserved = storage.getStorageFullBytes(path); + } + + if ((flags & StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY) == 0 + && stats.isQuotaSupported(volumeUuid)) { final long cacheTotal = stats.getCacheBytes(volumeUuid); final long cacheReserved = storage.getStorageCacheBytes(path, flags); - final long cacheClearable = Math.max(0, cacheTotal - cacheReserved); + cacheClearable = Math.max(0, cacheTotal - cacheReserved); + } - if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { - return Math.max(0, (usable + cacheClearable) - fullReserved); - } else { - return Math.max(0, (usable + cacheClearable) - lowReserved); - } + if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { + return Math.max(0, (usable + cacheClearable) - fullReserved); } else { - // When we don't have fast quota information, we ignore cached - // data and only consider unused bytes. - if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { - return Math.max(0, usable - fullReserved); - } else { - return Math.max(0, usable - lowReserved); - } + return Math.max(0, (usable + cacheClearable) - lowReserved); } } catch (IOException e) { throw new ParcelableException(e); @@ -3242,10 +3242,17 @@ class StorageManagerService extends IStorageManager.Stub public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) { flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage); - final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage); + final long allocatableBytes = getAllocatableBytes(volumeUuid, + flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY, callingPackage); if (bytes > allocatableBytes) { - throw new ParcelableException(new IOException("Failed to allocate " + bytes - + " because only " + allocatableBytes + " allocatable")); + // If we don't have room without taking cache into account, check to see if we'd have + // room if we included freeable cache space. + final long cacheClearable = getAllocatableBytes(volumeUuid, + flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY, callingPackage); + if (bytes > allocatableBytes + cacheClearable) { + throw new ParcelableException(new IOException("Failed to allocate " + bytes + + " because only " + (allocatableBytes + cacheClearable) + " allocatable")); + } } final StorageManager storage = mContext.getSystemService(StorageManager.class); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f3264e2be565..f731a6d6652b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2373,11 +2373,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - @VisibleForTesting - public ActivityManagerService(Injector injector) { - this(injector, null /* handlerThread */); - } - /** * Provides the basic functionality for activity task related tests when a handler thread is * given to initialize the dependency members. @@ -7901,11 +7896,14 @@ public class ActivityManagerService extends IActivityManager.Stub } void reportGlobalUsageEventLocked(int event) { - mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME, - mUserController.getCurrentUserId(), event); + final int currentUserId = mUserController.getCurrentUserId(); + mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME, currentUserId, event); int[] profiles = mUserController.getCurrentProfileIds(); if (profiles != null) { for (int i = profiles.length - 1; i >= 0; i--) { + if (profiles[i] == currentUserId) { + continue; + } mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME, profiles[i], event); } } @@ -8519,32 +8517,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - if (pid == Process.myPid()) { - Slog.wtf(TAG, "system can't run remote animation"); - return; - } - synchronized (ActivityManagerService.this) { - final ProcessRecord pr; - synchronized (mPidsSelfLocked) { - pr = mPidsSelfLocked.get(pid); - if (pr == null) { - Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid); - return; - } - } - if (pr.runningRemoteAnimation == runningRemoteAnimation) { - return; - } - pr.runningRemoteAnimation = runningRemoteAnimation; - if (DEBUG_OOM_ADJ) { - Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation - + " for pid=" + pid); - } - updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); - } - } - public final void enterSafeMode() { synchronized(this) { // It only makes sense to do this before the system is ready @@ -18099,11 +18071,6 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation); - } - - @Override public List<ProcessMemoryState> getMemoryStateForProcesses() { List<ProcessMemoryState> processMemoryStates = new ArrayList<>(); synchronized (mPidsSelfLocked) { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 0dd719994de2..a0900b68111e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -528,12 +528,12 @@ final class ActivityManagerShellCommand extends ShellCommand { options.setLockTaskEnabled(true); } if (mWaitOption) { - result = mInternal.startActivityAndWait(null, null, intent, mimeType, + result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, options != null ? options.toBundle() : null, mUserId); res = result.result; } else { - res = mInternal.startActivityAsUser(null, null, intent, mimeType, + res = mInternal.startActivityAsUser(null, SHELL_PACKAGE_NAME, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, options != null ? options.toBundle() : null, mUserId); } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 563b2f3bfb32..ea3084274ae0 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.MY_PID; @@ -1348,6 +1349,25 @@ class ProcessRecord implements WindowProcessListener { } } + @Override + public void setRunningRemoteAnimation(boolean runningRemoteAnimation) { + if (pid == Process.myPid()) { + Slog.wtf(TAG, "system can't run remote animation"); + return; + } + synchronized (mService) { + if (this.runningRemoteAnimation == runningRemoteAnimation) { + return; + } + this.runningRemoteAnimation = runningRemoteAnimation; + if (DEBUG_OOM_ADJ) { + Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation + + " for pid=" + pid); + } + mService.updateOomAdjLocked(this, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + } + } + public long getInputDispatchingTimeout() { return mWindowProcessController.getInputDispatchingTimeout(); } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index cb6cf74d4f52..6010b1dc88c4 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -15,9 +15,6 @@ */ package com.android.server.audio; -import static com.android.server.audio.AudioService.CONNECTION_STATE_CONNECTED; -import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTED; - import android.annotation.NonNull; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; @@ -95,13 +92,28 @@ import java.io.PrintWriter; /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) { mContext = context; mAudioService = service; - setupMessaging(context); mBtHelper = new BtHelper(this); mDeviceInventory = new AudioDeviceInventory(this); + init(); + } + + /** for test purposes only, inject AudioDeviceInventory */ + AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service, + @NonNull AudioDeviceInventory mockDeviceInventory) { + mContext = context; + mAudioService = service; + mBtHelper = new BtHelper(this); + mDeviceInventory = mockDeviceInventory; + + init(); + } + + private void init() { + setupMessaging(mContext); + mForcedUseForComm = AudioSystem.FORCE_NONE; mForcedUseForCommExt = mForcedUseForComm; - } /*package*/ Context getContext() { @@ -232,17 +244,42 @@ import java.io.PrintWriter; mSupprNoisy = suppressNoisyIntent; mVolume = vol; } + + // redefine equality op so we can match messages intended for this device + @Override + public boolean equals(Object o) { + return mDevice.equals(o); + } } + /*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile, suppressNoisyIntent, a2dpVolume); - // TODO add a check to try to remove unprocessed messages for the same device (the old - // check didn't work), and make sure it doesn't conflict with config change message - sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); + // when receiving a request to change the connection state of a device, this last request + // is the source of truth, so cancel all previous requests + removeAllA2dpConnectionEvents(device); + + sendLMsgNoDelay( + state == BluetoothProfile.STATE_CONNECTED + ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION + : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, + SENDMSG_QUEUE, info); + } + + /** remove all previously scheduled connection and disconnection events for the given device */ + private void removeAllA2dpConnectionEvents(@NonNull BluetoothDevice device) { + mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, + device); + mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION, + device); + mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, + device); + mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, + device); } private static final class HearingAidDeviceConnectionInfo { @@ -430,13 +467,16 @@ import java.io.PrintWriter; sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE); } - /*package*/ void postA2dpSinkConnection(int state, + /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { - sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE, + sendILMsg(state == BluetoothA2dp.STATE_CONNECTED + ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED + : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, + SENDMSG_QUEUE, state, btDeviceInfo, delay); } - /*package*/ void postA2dpSourceConnection(int state, + /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state, btDeviceInfo, delay); @@ -522,25 +562,6 @@ import java.io.PrintWriter; } } - @GuardedBy("mDeviceStateLock") - /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state, - @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { - final int intState = (state == BluetoothA2dp.STATE_CONNECTED) - ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED; - final int delay = mDeviceInventory.checkSendBecomingNoisyIntent( - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState, - AudioSystem.DEVICE_NONE); - final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress(); - - if (AudioService.DEBUG_DEVICES) { - Log.d(TAG, "handleSetA2dpSinkConnectionState btDevice= " + btDeviceInfo - + " state= " + state - + " is dock: " + btDeviceInfo.getBtDevice().isBluetoothDock()); - } - sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE, - state, btDeviceInfo, delay); - } - /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0; @@ -575,8 +596,10 @@ import java.io.PrintWriter; // must be called synchronized on mConnectedDevices /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) { - return mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, - new BtHelper.BluetoothA2dpDeviceInfo(btDevice)); + return (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, + new BtHelper.BluetoothA2dpDeviceInfo(btDevice)) + || mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, + new BtHelper.BluetoothA2dpDeviceInfo(btDevice))); } /*package*/ void setA2dpDockTimeout(String address, int a2dpCodec, int delayMs) { @@ -711,7 +734,8 @@ import java.io.PrintWriter; mDeviceInventory.onReportNewRoutes(); } break; - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: synchronized (mDeviceStateLock) { mDeviceInventory.onSetA2dpSinkConnectionState( (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); @@ -836,7 +860,8 @@ import java.io.PrintWriter; } } break; - case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: { + case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: + case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: { final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj; AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent " @@ -887,7 +912,7 @@ import java.io.PrintWriter; private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3; private static final int MSG_IIL_SET_FORCE_USE = 4; private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5; - private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE = 6; + private static final int MSG_TOGGLE_HDMI = 6; private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7; private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8; private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; @@ -898,7 +923,6 @@ import java.io.PrintWriter; private static final int MSG_II_SET_HEARING_AID_VOLUME = 14; private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15; private static final int MSG_I_DISCONNECT_BT_SCO = 16; - private static final int MSG_TOGGLE_HDMI = 17; private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18; private static final int MSG_DISCONNECT_A2DP = 19; private static final int MSG_DISCONNECT_A2DP_SINK = 20; @@ -908,25 +932,30 @@ import java.io.PrintWriter; private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24; private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25; private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26; + private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27; + private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28; // process external command to (dis)connect an A2DP device - private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 27; + private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29; + private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30; // process external command to (dis)connect a hearing aid device - private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28; + private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31; // a ScoClient died in BtHelper - private static final int MSG_L_SCOCLIENT_DIED = 29; + private static final int MSG_L_SCOCLIENT_DIED = 32; private static boolean isMessageHandledUnderWakelock(int msgId) { switch(msgId) { case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: case MSG_IL_BTA2DP_DOCK_TIMEOUT: case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: case MSG_TOGGLE_HDMI: case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: - case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: + case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: + case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: return true; default: @@ -1007,7 +1036,8 @@ import java.io.PrintWriter; switch (msg) { case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: - case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: + case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: case MSG_IL_BTA2DP_DOCK_TIMEOUT: diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index a9a8ef2f7e12..90973a888a9d 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -41,14 +41,16 @@ import android.util.Log; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; /** * Class to manage the inventory of all connected devices. * This class is thread-safe. + * (non final for mocking/spying) */ -public final class AudioDeviceInventory { +public class AudioDeviceInventory { private static final String TAG = "AS.AudioDeviceInventory"; @@ -56,11 +58,7 @@ public final class AudioDeviceInventory { // Key for map created from DeviceInfo.makeDeviceListKey() private final ArrayMap<String, DeviceInfo> mConnectedDevices = new ArrayMap<>(); - private final @NonNull AudioDeviceBroker mDeviceBroker; - - AudioDeviceInventory(@NonNull AudioDeviceBroker broker) { - mDeviceBroker = broker; - } + private @NonNull AudioDeviceBroker mDeviceBroker; // cache of the address of the last dock the device was connected to private String mDockAddress; @@ -70,6 +68,20 @@ public final class AudioDeviceInventory { final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers = new RemoteCallbackList<IAudioRoutesObserver>(); + /*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) { + mDeviceBroker = broker; + } + + //----------------------------------------------------------- + /** for mocking only */ + /*package*/ AudioDeviceInventory() { + mDeviceBroker = null; + } + + /*package*/ void setDeviceBroker(@NonNull AudioDeviceBroker broker) { + mDeviceBroker = broker; + } + //------------------------------------------------------------ /** * Class to store info about connected devices. @@ -146,8 +158,10 @@ public final class AudioDeviceInventory { } } + // only public for mocking/spying @GuardedBy("AudioDeviceBroker.mDeviceStateLock") - /*package*/ void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, + @VisibleForTesting + public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, @AudioService.BtProfileConnectionState int state) { final BluetoothDevice btDevice = btInfo.getBtDevice(); int a2dpVolume = btInfo.getVolume(); @@ -159,30 +173,40 @@ public final class AudioDeviceInventory { if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } + + final int a2dpCodec = btInfo.getCodec(); + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( "A2DP sink connected: device addr=" + address + " state=" + state + + " codec=" + a2dpCodec + " vol=" + a2dpVolume)); - final int a2dpCodec = btInfo.getCodec(); - synchronized (mConnectedDevices) { final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, btDevice.getAddress()); final DeviceInfo di = mConnectedDevices.get(key); boolean isConnected = di != null; - if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { - if (btDevice.isBluetoothDock()) { - if (state == BluetoothProfile.STATE_DISCONNECTED) { - // introduction of a delay for transient disconnections of docks when - // power is rapidly turned off/on, this message will be canceled if - // we reconnect the dock under a preset delay - makeA2dpDeviceUnavailableLater(address, - AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS); - // the next time isConnected is evaluated, it will be false for the dock + if (isConnected) { + if (state == BluetoothProfile.STATE_CONNECTED) { + // device is already connected, but we are receiving a connection again, + // it could be for a codec change + if (a2dpCodec != di.mDeviceCodecFormat) { + mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice); } } else { - makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); + if (btDevice.isBluetoothDock()) { + if (state == BluetoothProfile.STATE_DISCONNECTED) { + // introduction of a delay for transient disconnections of docks when + // power is rapidly turned off/on, this message will be canceled if + // we reconnect the dock under a preset delay + makeA2dpDeviceUnavailableLater(address, + AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS); + // the next time isConnected is evaluated, it will be false for the dock + } + } else { + makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); + } } } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { if (btDevice.isBluetoothDock()) { @@ -282,11 +306,9 @@ public final class AudioDeviceInventory { + " event=" + BtHelper.a2dpDeviceEventToString(event))); synchronized (mConnectedDevices) { - //TODO original CL is not consistent between BluetoothDevice and BluetoothA2dpDeviceInfo - // for this type of message if (mDeviceBroker.hasScheduledA2dpSinkConnectionState(btDevice)) { AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "A2dp config change ignored")); + "A2dp config change ignored (scheduled connection change)")); return; } final String key = DeviceInfo.makeDeviceListKey( @@ -534,8 +556,10 @@ public final class AudioDeviceInventory { return mCurAudioRoutes; } + // only public for mocking/spying @GuardedBy("AudioDeviceBroker.mDeviceStateLock") - /*package*/ void setBluetoothA2dpDeviceConnectionState( + @VisibleForTesting + public void setBluetoothA2dpDeviceConnectionState( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) { int delay; @@ -544,9 +568,12 @@ public final class AudioDeviceInventory { } synchronized (mConnectedDevices) { if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) { - int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0; + @AudioService.ConnectionState int asState = + (state == BluetoothA2dp.STATE_CONNECTED) + ? AudioService.CONNECTION_STATE_CONNECTED + : AudioService.CONNECTION_STATE_DISCONNECTED; delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - intState, musicDevice); + asState, musicDevice); } else { delay = 0; } @@ -785,7 +812,7 @@ public final class AudioDeviceInventory { return 0; } mDeviceBroker.postBroadcastBecomingNoisy(); - delay = 1000; + delay = AudioService.BECOMING_NOISY_DELAY_MS; } return delay; @@ -943,4 +970,21 @@ public final class AudioDeviceInventory { intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels); } } + + //---------------------------------------------------------- + // For tests only + + /** + * Check if device is in the list of connected devices + * @param device + * @return true if connected + */ + @VisibleForTesting + public boolean isA2dpDeviceConnected(@NonNull BluetoothDevice device) { + final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, + device.getAddress()); + synchronized (mConnectedDevices) { + return (mConnectedDevices.get(key) != null); + } + } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 7458bee793db..5bc2261878b6 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -128,6 +128,7 @@ import android.view.accessibility.AccessibilityManager; import android.widget.Toast; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; @@ -190,6 +191,13 @@ public class AudioService extends IAudioService.Stub private static final int UNMUTE_STREAM_DELAY = 350; /** + * Delay before disconnecting a device that would cause BECOMING_NOISY intent to be sent, + * to give a chance to applications to pause. + */ + @VisibleForTesting + public static final int BECOMING_NOISY_DELAY_MS = 1000; + + /** * Only used in the result from {@link #checkForRingerModeChange(int, int, int)} */ private static final int FLAG_ADJUST_VOLUME = 1; @@ -3950,7 +3958,9 @@ public class AudioService extends IAudioService.Stub || adjust == AudioManager.ADJUST_TOGGLE_MUTE; } - /*package*/ boolean isInCommunication() { + /** only public for mocking/spying, do not call outside of AudioService */ + @VisibleForTesting + public boolean isInCommunication() { boolean IsInCall = false; TelecomManager telecomManager = @@ -4119,7 +4129,9 @@ public class AudioService extends IAudioService.Stub return false; } - /*package*/ int getDeviceForStream(int stream) { + /** only public for mocking/spying, do not call outside of AudioService */ + @VisibleForTesting + public int getDeviceForStream(int stream) { int device = getDevicesForStream(stream); if ((device & (device - 1)) != 0) { // Multiple device selection is either: @@ -4164,7 +4176,9 @@ public class AudioService extends IAudioService.Stub } } - /*package*/ void postObserveDevicesForAllStreams() { + /** only public for mocking/spying, do not call outside of AudioService */ + @VisibleForTesting + public void postObserveDevicesForAllStreams() { sendMsg(mAudioHandler, MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS, SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, null /*obj*/, @@ -4275,7 +4289,9 @@ public class AudioService extends IAudioService.Stub AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_HDMI; - /*package*/ void postAccessoryPlugMediaUnmute(int newDevice) { + /** only public for mocking/spying, do not call outside of AudioService */ + @VisibleForTesting + public void postAccessoryPlugMediaUnmute(int newDevice) { sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE, newDevice, 0, null, 0); } @@ -4825,7 +4841,9 @@ public class AudioService extends IAudioService.Stub } } - /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, + /** only public for mocking/spying, do not call outside of AudioService */ + @VisibleForTesting + public void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, String caller) { sendMsg(mAudioHandler, MSG_SET_DEVICE_STREAM_VOLUME, @@ -5183,7 +5201,9 @@ public class AudioService extends IAudioService.Stub * @return true if there is currently a registered dynamic mixing policy that affects media * and is not a render + loopback policy */ - /*package*/ boolean hasMediaDynamicPolicy() { + // only public for mocking/spying + @VisibleForTesting + public boolean hasMediaDynamicPolicy() { synchronized (mAudioPolicies) { if (mAudioPolicies.isEmpty()) { return false; @@ -5516,7 +5536,9 @@ public class AudioService extends IAudioService.Stub return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr); } - /*package*/ boolean hasAudioFocusUsers() { + /** only public for mocking/spying, do not call outside of AudioService */ + @VisibleForTesting + public boolean hasAudioFocusUsers() { return mMediaFocusControl.hasAudioFocusUsers(); } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 1a63f8f51ee3..9f1a6bd15ac3 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -139,6 +139,12 @@ public class BtHelper { public int getCodec() { return mCodec; } + + // redefine equality op so we can match messages intended for this device + @Override + public boolean equals(Object o) { + return mBtDevice.equals(o); + } } // A2DP device events @@ -441,9 +447,9 @@ public class BtHelper { return; } final BluetoothDevice btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = mA2dp.getConnectionState(btDevice); - mDeviceBroker.handleSetA2dpSinkConnectionState( - state, new BluetoothA2dpDeviceInfo(btDevice)); + // the device is guaranteed CONNECTED + mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(btDevice, + BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK, true, -1); } /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) { diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index db55138e446d..65472c9b409d 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -364,28 +364,8 @@ public class FocusRequester { // check enforcement by the framework boolean handled = false; - if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK - && MediaFocusControl.ENFORCE_DUCKING - && frWinner != null) { - // candidate for enforcement by the framework - if (frWinner.mCallingUid != this.mCallingUid) { - if (!forceDuck && ((mGrantFlags - & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) { - // the focus loser declared it would pause instead of duck, let it - // handle it (the framework doesn't pause for apps) - handled = false; - Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags"); - } else if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW && - this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL)) - { - // legacy behavior, apps used to be notified when they should be ducking - handled = false; - Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK"); - } else { - handled = mFocusController.duckPlayers(frWinner, this, forceDuck); - } - } // else: the focus change is within the same app, so let the dispatching - // happen as if the framework was not involved. + if (frWinner != null) { + handled = frameworkHandleFocusLoss(focusLoss, frWinner, forceDuck); } if (handled) { @@ -415,6 +395,47 @@ public class FocusRequester { } } + /** + * Let the framework handle the focus loss if possible + * @param focusLoss + * @param frWinner + * @param forceDuck + * @return true if the framework handled the focus loss + */ + @GuardedBy("MediaFocusControl.mAudioFocusLock") + private boolean frameworkHandleFocusLoss(int focusLoss, @NonNull final FocusRequester frWinner, + boolean forceDuck) { + if (frWinner.mCallingUid != this.mCallingUid) { + // the focus change is within the same app, so let the dispatching + // happen as if the framework was not involved. + return false; + } + + if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { + if (!MediaFocusControl.ENFORCE_DUCKING) { + return false; + } + + // candidate for enforcement by the framework + if (!forceDuck && ((mGrantFlags + & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) { + // the focus loser declared it would pause instead of duck, let it + // handle it (the framework doesn't pause for apps) + Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags"); + return false; + } + if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW + && this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL)) { + // legacy behavior, apps used to be notified when they should be ducking + Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK"); + return false; + } + + return mFocusController.duckPlayers(frWinner, this, forceDuck); + } + return false; + } + int dispatchFocusChange(int focusChange) { if (mFocusDispatcher == null) { if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); } diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index 5c93071fd551..c845981fea7e 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -105,12 +105,13 @@ public class MediaFocusControl implements PlayerFocusEnforcer { //================================================================= // PlayerFocusEnforcer implementation @Override - public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) { + public boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser, + boolean forceDuck) { return mFocusEnforcer.duckPlayers(winner, loser, forceDuck); } @Override - public void unduckPlayers(FocusRequester winner) { + public void unduckPlayers(@NonNull FocusRequester winner) { mFocusEnforcer.unduckPlayers(winner); } @@ -742,7 +743,20 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } - /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */ + /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) + * @param aa + * @param focusChangeHint + * @param cb + * @param fd + * @param clientId + * @param callingPackageName + * @param flags + * @param sdk + * @param forceDuck only true if + * {@link android.media.AudioFocusRequest.Builder#setFocusGain(int)} was set to true for + * accessibility. + * @return + */ protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb, IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName, int flags, int sdk, boolean forceDuck) { diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index 3a25d980e97a..f8ba55bcd092 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -425,7 +425,8 @@ public final class PlaybackActivityMonitor private final DuckingManager mDuckingManager = new DuckingManager(); @Override - public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) { + public boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser, + boolean forceDuck) { if (DEBUG) { Log.v(TAG, String.format("duckPlayers: uids winner=%d loser=%d", winner.getClientUid(), loser.getClientUid())); @@ -473,7 +474,7 @@ public final class PlaybackActivityMonitor } @Override - public void unduckPlayers(FocusRequester winner) { + public void unduckPlayers(@NonNull FocusRequester winner) { if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); } synchronized (mPlayerLock) { mDuckingManager.unduckUid(winner.getClientUid(), mPlayers); diff --git a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java index 3c834daf3c8a..89e7b7828b15 100644 --- a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java +++ b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java @@ -16,6 +16,8 @@ package com.android.server.audio; +import android.annotation.NonNull; + public interface PlayerFocusEnforcer { /** @@ -25,11 +27,24 @@ public interface PlayerFocusEnforcer { * @param loser * @return */ - public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck); + boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser, + boolean forceDuck); - public void unduckPlayers(FocusRequester winner); + /** + * Unduck the players that had been ducked with + * {@link #duckPlayers(FocusRequester, FocusRequester, boolean)} + * @param winner + */ + void unduckPlayers(@NonNull FocusRequester winner); - public void mutePlayersForCall(int[] usagesToMute); + /** + * Mute players at the beginning of a call + * @param usagesToMute array of {@link android.media.AudioAttributes} usages to mute + */ + void mutePlayersForCall(int[] usagesToMute); - public void unmutePlayersForCall(); + /** + * Unmute players at the end of a call + */ + void unmutePlayersForCall(); }
\ No newline at end of file diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 5b043799f848..96b7cb315f58 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -16,6 +16,7 @@ package com.android.server.connectivity; +import android.annotation.NonNull; import android.content.Context; import android.net.IDnsResolver; import android.net.INetd; @@ -116,7 +117,7 @@ import java.util.TreeSet; // not, ConnectivityService disconnects the NetworkAgent's AsyncChannel. public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { - public NetworkInfo networkInfo; + @NonNull public NetworkInfo networkInfo; // This Network object should always be used if possible, so as to encourage reuse of the // enclosed socket factory and connection pool. Avoid creating other Network objects. // This Network object is always valid. @@ -579,10 +580,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } if (newExpiry > 0) { - mLingerMessage = mConnService.makeWakeupMessage( + mLingerMessage = new WakeupMessage( mContext, mHandler, - "NETWORK_LINGER_COMPLETE." + network.netId, - EVENT_NETWORK_LINGER_COMPLETE, this); + "NETWORK_LINGER_COMPLETE." + network.netId /* cmdName */, + EVENT_NETWORK_LINGER_COMPLETE /* cmd */, + 0 /* arg1 (unused) */, 0 /* arg2 (unused) */, + this /* obj (NetworkAgentInfo) */); mLingerMessage.schedule(newExpiry); } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 4957eed21c70..73d160d8c444 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -772,7 +772,6 @@ public class Tethering extends BaseNetworkObserver { case WifiManager.WIFI_AP_STATE_FAILED: default: disableWifiIpServingLocked(ifname, curState); - mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_WIFI); break; } } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 78a48dac6fb5..764863616db1 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -680,6 +680,7 @@ public class DisplayModeDirector { @Override public void onDisplayChanged(int displayId) { updateDisplayModes(displayId); + mBrightnessObserver.onDisplayChanged(displayId); } private void updateDisplayModes(int displayId) { @@ -728,13 +729,12 @@ public class DisplayModeDirector { private SensorManager mSensorManager; private Sensor mLightSensor; + private LightSensorEventListener mLightSensorListener = new LightSensorEventListener(); // Take it as low brightness before valid sensor data comes private float mAmbientLux = -1.0f; private AmbientFilter mAmbientFilter; private final Context mContext; - private ScreenStateReceiver mScreenStateReceiver; - // Enable light sensor only when screen is on, peak refresh rate enabled and low power mode // off. After initialization, these states will be updated from the same handler thread. private boolean mScreenOn = false; @@ -792,11 +792,7 @@ public class DisplayModeDirector { mSensorManager = sensorManager; mLightSensor = lightSensor; - // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status. - if (mContext.getSystemService(PowerManager.class).isInteractive()) { - onScreenOn(true); - } - mScreenStateReceiver = new ScreenStateReceiver(mContext); + onScreenOn(isDefaultDisplayOn()); } } @@ -821,6 +817,12 @@ public class DisplayModeDirector { } } + public void onDisplayChanged(int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + onScreenOn(isDefaultDisplayOn()); + } + } + public void dumpLocked(PrintWriter pw) { pw.println(" BrightnessObserver"); @@ -890,8 +892,6 @@ public class DisplayModeDirector { } private void onScreenOn(boolean on) { - // Not check mShouldObserveAmbientChange because Screen status receiver is registered - // only when it is true. if (mScreenOn != on) { mScreenOn = on; updateSensorStatus(); @@ -907,19 +907,47 @@ public class DisplayModeDirector { mSensorManager.registerListener(mLightSensorListener, mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler); } else { + mLightSensorListener.removeCallbacks(); mSensorManager.unregisterListener(mLightSensorListener); } } - private final SensorEventListener mLightSensorListener = new SensorEventListener() { + private boolean isDefaultDisplayOn() { + final Display display = mContext.getSystemService(DisplayManager.class) + .getDisplay(Display.DEFAULT_DISPLAY); + return display.getState() != Display.STATE_OFF + && mContext.getSystemService(PowerManager.class).isInteractive(); + } + + private final class LightSensorEventListener implements SensorEventListener { + final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS; + private float mLastSensorData; + @Override public void onSensorChanged(SensorEvent event) { + mLastSensorData = event.values[0]; + if (DEBUG) { + Slog.d(TAG, "On sensor changed: " + mLastSensorData); + } + + boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux); + if (zoneChanged && mLastSensorData < mAmbientLux) { + // Easier to see flicker at lower brightness environment. Forget the history to + // get immediate response. + mAmbientFilter.clear(); + } + long now = SystemClock.uptimeMillis(); - mAmbientFilter.addValue(now, event.values[0]); - mAmbientLux = mAmbientFilter.getEstimate(now); + mAmbientFilter.addValue(now, mLastSensorData); - synchronized (mLock) { - onBrightnessChangedLocked(); + mHandler.removeCallbacks(mInjectSensorEventRunnable); + processSensorData(now); + + if (zoneChanged && mLastSensorData > mAmbientLux) { + // Sensor may not report new event if there is no brightness change. + // Need to keep querying the temporal filter for the latest estimation, + // until enter in higher lux zone or is interrupted by a new sensor event. + mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); } } @@ -927,21 +955,47 @@ public class DisplayModeDirector { public void onAccuracyChanged(Sensor sensor, int accuracy) { // Not used. } - }; - private final class ScreenStateReceiver extends BroadcastReceiver { - public ScreenStateReceiver(Context context) { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - context.registerReceiver(this, filter, null, mHandler); + public void removeCallbacks() { + mHandler.removeCallbacks(mInjectSensorEventRunnable); } - @Override - public void onReceive(Context context, Intent intent) { - onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction())); + private void processSensorData(long now) { + mAmbientLux = mAmbientFilter.getEstimate(now); + + synchronized (mLock) { + onBrightnessChangedLocked(); + } } - } + + private boolean isDifferentZone(float lux1, float lux2) { + for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) { + final float boundary = mAmbientBrightnessThresholds[z]; + + // Test each boundary. See if the current value and the new value are at + // different sides. + if ((lux1 <= boundary && lux2 > boundary) + || (lux1 > boundary && lux2 <= boundary)) { + return true; + } + } + + return false; + } + + private Runnable mInjectSensorEventRunnable = new Runnable() { + @Override + public void run() { + long now = SystemClock.uptimeMillis(); + // No need to really inject the last event into a temporal filter. + processSensorData(now); + + // Inject next event if there is a possible zone change. + if (isDifferentZone(mLastSensorData, mAmbientLux)) { + mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); + } + } + }; + }; } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 09e93759196f..f20003a2ee04 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2551,7 +2551,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis); if (mStatusBar != null) { mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition, - needsToShowImeSwitcher); + needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/); } final InputMethodInfo imi = mMethodMap.get(mCurMethodId); if (imi != null && needsToShowImeSwitcher) { diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/services/core/java/com/android/server/inputmethod/InputMethodSystemProperty.java index e20c2fdc8074..a6a68934accd 100644 --- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodSystemProperty.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.view.inputmethod; +package com.android.server.inputmethod; import android.annotation.Nullable; import android.content.ComponentName; @@ -23,8 +23,6 @@ import android.os.SystemProperties; /** * Various (pseudo) constants about IME behaviors. - * - * @hide */ public class InputMethodSystemProperty { /** @@ -58,23 +56,12 @@ public class InputMethodSystemProperty { /** * {@link ComponentName} of multi-client IME to be used. - * - * <p>TODO: Move this back to MultiClientInputMethodManagerService once - * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p> - * - * @hide */ @Nullable - public static final ComponentName sMultiClientImeComponentName = - getMultiClientImeComponentName(); + static final ComponentName sMultiClientImeComponentName = getMultiClientImeComponentName(); /** * {@code true} when multi-client IME is enabled. - * - * <p>TODO: Move this back to MultiClientInputMethodManagerService once - * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p> - * - * @hide */ public static final boolean MULTI_CLIENT_IME_ENABLED = (sMultiClientImeComponentName != null); } diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 3dd730471dca..02e29e0b2ab5 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -67,7 +67,6 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; -import android.view.inputmethod.InputMethodSystemProperty; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 9510db09aa25..f1f6d502d575 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -182,7 +182,7 @@ public class LockSettingsService extends ILockSettings.Stub { @IntDef({CHALLENGE_NONE, CHALLENGE_FROM_CALLER, CHALLENGE_INTERNAL}) - @interface ChallengeType {}; + @interface ChallengeType {} // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Do not call into ActivityManager while holding mSpManager lock. @@ -1853,26 +1853,11 @@ public class LockSettingsService extends ILockSettings.Stub { return VerifyCredentialResponse.ERROR; } - boolean shouldReEnrollBaseZero = storedHash.type == CREDENTIAL_TYPE_PATTERN - && storedHash.isBaseZeroPattern; - - byte[] credentialToVerify; - if (shouldReEnrollBaseZero) { - credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential); - } else { - credentialToVerify = credential; - } - - response = verifyCredential(userId, storedHash, credentialToVerify, + response = verifyCredential(userId, storedHash, credential, challengeType, challenge, progressCallback); if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); - if (shouldReEnrollBaseZero) { - setLockCredentialInternal(credential, storedHash.type, credentialToVerify, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId, false, - /* isLockTiedToParent= */ false); - } } return response; @@ -1937,46 +1922,6 @@ public class LockSettingsService extends ILockSettings.Stub { // of unlocking the user, so yell if calling from the main thread. StrictMode.noteDiskRead(); - if (storedHash.version == CredentialHash.VERSION_LEGACY) { - final byte[] hash; - if (storedHash.type == CREDENTIAL_TYPE_PATTERN) { - hash = LockPatternUtils.patternToHash( - LockPatternUtils.byteArrayToPattern(credential)); - } else { - hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes(); - } - if (Arrays.equals(hash, storedHash.hash)) { - if (storedHash.type == CREDENTIAL_TYPE_PATTERN) { - unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId); - } else { - unlockKeystore(credential, userId); - } - // Users with legacy credentials don't have credential-backed - // FBE keys, so just pass through a fake token/secret - Slog.i(TAG, "Unlocking user with fake token: " + userId); - final byte[] fakeToken = String.valueOf(userId).getBytes(); - unlockUser(userId, fakeToken, fakeToken); - - // migrate credential to GateKeeper - setLockCredentialInternal(credential, storedHash.type, null, - storedHash.type == CREDENTIAL_TYPE_PATTERN - ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING - : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC - /* TODO(roosa): keep the same password quality */, - userId, false, /* isLockTiedToParent= */ false); - if (challengeType == CHALLENGE_NONE) { - notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); - // Use credentials to create recoverable keystore snapshot. - sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId); - return VerifyCredentialResponse.OK; - } - // Fall through to get the auth token. Technically this should never happen, - // as a user that had a legacy credential would have to unlock their device - // before getting to a flow with a challenge, but supporting for consistency. - } else { - return VerifyCredentialResponse.ERROR; - } - } GateKeeperResponse gateKeeperResponse = getGateKeeperService() .verifyChallenge(userId, challenge, storedHash.hash, credential); VerifyCredentialResponse response = convertResponse(gateKeeperResponse); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index 84ae7c790a74..29b8aa2e12f4 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -77,10 +77,7 @@ class LockSettingsStorage { private static final String SYSTEM_DIRECTORY = "/system/"; private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key"; - private static final String BASE_ZERO_LOCK_PATTERN_FILE = "gatekeeper.gesture.key"; - private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key"; private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key"; - private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key"; private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key"; private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/"; @@ -96,59 +93,43 @@ class LockSettingsStorage { @VisibleForTesting public static class CredentialHash { - static final int VERSION_LEGACY = 0; - static final int VERSION_GATEKEEPER = 1; + /** Deprecated private static final int VERSION_LEGACY = 0; */ + private static final int VERSION_GATEKEEPER = 1; - private CredentialHash(byte[] hash, @CredentialType int type, int version) { - this(hash, type, version, false /* isBaseZeroPattern */); - } - - private CredentialHash( - byte[] hash, @CredentialType int type, int version, boolean isBaseZeroPattern) { + private CredentialHash(byte[] hash, @CredentialType int type) { if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) { if (hash == null) { - throw new RuntimeException("Empty hash for CredentialHash"); + throw new IllegalArgumentException("Empty hash for CredentialHash"); } } else /* type == LockPatternUtils.CREDENTIAL_TYPE_NONE */ { if (hash != null) { - throw new RuntimeException("None type CredentialHash should not have hash"); + throw new IllegalArgumentException( + "None type CredentialHash should not have hash"); } } this.hash = hash; this.type = type; - this.version = version; - this.isBaseZeroPattern = isBaseZeroPattern; - } - - private static CredentialHash createBaseZeroPattern(byte[] hash) { - return new CredentialHash(hash, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - VERSION_GATEKEEPER, true /* isBaseZeroPattern */); } static CredentialHash create(byte[] hash, int type) { if (type == LockPatternUtils.CREDENTIAL_TYPE_NONE) { - throw new RuntimeException("Bad type for CredentialHash"); + throw new IllegalArgumentException("Bad type for CredentialHash"); } - return new CredentialHash(hash, type, VERSION_GATEKEEPER); + return new CredentialHash(hash, type); } static CredentialHash createEmptyHash() { - return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, - VERSION_GATEKEEPER); + return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE); } byte[] hash; @CredentialType int type; - int version; - boolean isBaseZeroPattern; public byte[] toBytes() { - Preconditions.checkState(!isBaseZeroPattern, "base zero patterns are not serializable"); - try { ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(os); - dos.write(version); + dos.write(VERSION_GATEKEEPER); dos.write(type); if (hash != null && hash.length > 0) { dos.writeInt(hash.length); @@ -166,7 +147,7 @@ class LockSettingsStorage { public static CredentialHash fromBytes(byte[] bytes) { try { DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes)); - int version = is.read(); + /* int version = */ is.read(); int type = is.read(); int hashSize = is.readInt(); byte[] hash = null; @@ -174,7 +155,7 @@ class LockSettingsStorage { hash = new byte[hashSize]; is.readFully(hash); } - return new CredentialHash(hash, type, version); + return new CredentialHash(hash, type); } catch (IOException e) { throw new RuntimeException(e); } @@ -269,14 +250,7 @@ class LockSettingsStorage { private CredentialHash readPasswordHashIfExists(int userId) { byte[] stored = readFile(getLockPasswordFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { - return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - CredentialHash.VERSION_GATEKEEPER); - } - - stored = readFile(getLegacyLockPasswordFilename(userId)); - if (!ArrayUtils.isEmpty(stored)) { - return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - CredentialHash.VERSION_LEGACY); + return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD); } return null; } @@ -284,39 +258,22 @@ class LockSettingsStorage { private CredentialHash readPatternHashIfExists(int userId) { byte[] stored = readFile(getLockPatternFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { - return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - CredentialHash.VERSION_GATEKEEPER); - } - - stored = readFile(getBaseZeroLockPatternFilename(userId)); - if (!ArrayUtils.isEmpty(stored)) { - return CredentialHash.createBaseZeroPattern(stored); - } - - stored = readFile(getLegacyLockPatternFilename(userId)); - if (!ArrayUtils.isEmpty(stored)) { - return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - CredentialHash.VERSION_LEGACY); + return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN); } return null; } public CredentialHash readCredentialHash(int userId) { CredentialHash passwordHash = readPasswordHashIfExists(userId); - CredentialHash patternHash = readPatternHashIfExists(userId); - if (passwordHash != null && patternHash != null) { - if (passwordHash.version == CredentialHash.VERSION_GATEKEEPER) { - return passwordHash; - } else { - return patternHash; - } - } else if (passwordHash != null) { + if (passwordHash != null) { return passwordHash; - } else if (patternHash != null) { + } + + CredentialHash patternHash = readPatternHashIfExists(userId); + if (patternHash != null) { return patternHash; - } else { - return CredentialHash.createEmptyHash(); } + return CredentialHash.createEmptyHash(); } public void removeChildProfileLock(int userId) { @@ -342,14 +299,11 @@ class LockSettingsStorage { } public boolean hasPassword(int userId) { - return hasFile(getLockPasswordFilename(userId)) || - hasFile(getLegacyLockPasswordFilename(userId)); + return hasFile(getLockPasswordFilename(userId)); } public boolean hasPattern(int userId) { - return hasFile(getLockPatternFilename(userId)) || - hasFile(getBaseZeroLockPatternFilename(userId)) || - hasFile(getLegacyLockPatternFilename(userId)); + return hasFile(getLockPatternFilename(userId)); } public boolean hasCredential(int userId) { @@ -470,20 +424,6 @@ class LockSettingsStorage { } @VisibleForTesting - String getLegacyLockPatternFilename(int userId) { - return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE); - } - - @VisibleForTesting - String getLegacyLockPasswordFilename(int userId) { - return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE); - } - - private String getBaseZeroLockPatternFilename(int userId) { - return getLockCredentialFilePathForUser(userId, BASE_ZERO_LOCK_PATTERN_FILE); - } - - @VisibleForTesting String getChildProfileLockFile(int userId) { return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 217c0bdceede..6fe924e7432d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -5229,7 +5229,7 @@ public class NotificationManagerService extends SystemService { @Override public void run() { synchronized (mNotificationLock) { - final NotificationRecord r = findNotificationByKeyLocked(mKey); + final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(mKey); if (r != null) { snoozeLocked(r); } @@ -5239,33 +5239,34 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") void snoozeLocked(NotificationRecord r) { if (r.sbn.isGroup()) { - final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked( + final List<NotificationRecord> groupNotifications = + findCurrentAndSnoozedGroupNotificationsLocked( r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId()); if (r.getNotification().isGroupSummary()) { - // snooze summary and all children + // snooze all children for (int i = 0; i < groupNotifications.size(); i++) { - snoozeNotificationLocked(groupNotifications.get(i)); + if (mKey != groupNotifications.get(i).getKey()) { + snoozeNotificationLocked(groupNotifications.get(i)); + } } } else { // if there is a valid summary for this group, and we are snoozing the only // child, also snooze the summary if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) { - if (groupNotifications.size() != 2) { - snoozeNotificationLocked(r); - } else { + if (groupNotifications.size() == 2) { // snooze summary and the one child for (int i = 0; i < groupNotifications.size(); i++) { - snoozeNotificationLocked(groupNotifications.get(i)); + if (mKey != groupNotifications.get(i).getKey()) { + snoozeNotificationLocked(groupNotifications.get(i)); + } } } - } else { - snoozeNotificationLocked(r); } } - } else { - // just snooze the one notification - snoozeNotificationLocked(r); } + // snooze the notification + snoozeNotificationLocked(r); + } @GuardedBy("mNotificationLock") @@ -7050,6 +7051,15 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") + @NonNull + List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg, + String groupKey, int userId) { + List<NotificationRecord> records = mSnoozeHelper.getNotifications(pkg, groupKey, userId); + records.addAll(findGroupNotificationsLocked(pkg, groupKey, userId)); + return records; + } + + @GuardedBy("mNotificationLock") @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg, String groupKey, int userId) { List<NotificationRecord> records = new ArrayList<>(); @@ -7059,6 +7069,15 @@ public class NotificationManagerService extends SystemService { return records; } + @GuardedBy("mNotificationLock") + private NotificationRecord findInCurrentAndSnoozedNotificationByKeyLocked(String key) { + NotificationRecord r = findNotificationByKeyLocked(key); + if (r == null) { + r = mSnoozeHelper.getNotification(key); + } + return r; + + } @GuardedBy("mNotificationLock") private @NonNull List<NotificationRecord> findGroupNotificationByListLocked( diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index abc98412e126..91f497cf9607 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -17,7 +17,6 @@ package com.android.server.notification; import android.annotation.NonNull; import android.app.AlarmManager; -import android.app.Notification; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -104,6 +103,46 @@ public class SnoozeHelper { return Collections.EMPTY_LIST; } + @NonNull + ArrayList<NotificationRecord> getNotifications(String pkg, + String groupKey, Integer userId) { + ArrayList<NotificationRecord> records = new ArrayList<>(); + if (mSnoozedNotifications.containsKey(userId) + && mSnoozedNotifications.get(userId).containsKey(pkg)) { + ArrayMap<String, NotificationRecord> packages = + mSnoozedNotifications.get(userId).get(pkg); + for (int i = 0; i < packages.size(); i++) { + String currentGroupKey = packages.valueAt(i).sbn.getGroup(); + if (currentGroupKey.equals(groupKey)) { + records.add(packages.valueAt(i)); + } + } + } + return records; + } + + protected NotificationRecord getNotification(String key) { + List<NotificationRecord> snoozedForUser = new ArrayList<>(); + IntArray userIds = mUserProfiles.getCurrentProfileIds(); + if (userIds != null) { + final int userIdsSize = userIds.size(); + for (int i = 0; i < userIdsSize; i++) { + final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs = + mSnoozedNotifications.get(userIds.get(i)); + if (snoozedPkgs != null) { + final int snoozedPkgsSize = snoozedPkgs.size(); + for (int j = 0; j < snoozedPkgsSize; j++) { + final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j); + if (records != null) { + return records.get(key); + } + } + } + } + } + return null; + } + protected @NonNull List<NotificationRecord> getSnoozed() { List<NotificationRecord> snoozedForUser = new ArrayList<>(); IntArray userIds = mUserProfiles.getCurrentProfileIds(); diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java index c98a79ad4ed9..714bbb97c90d 100644 --- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java +++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java @@ -297,19 +297,5 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } mDs.asBinder().unlinkToDeath(this, 0); } - - // Old methods; unused in the API flow. - @Override - public void onProgressUpdated(int progress) throws RemoteException { - } - - @Override - public void onMaxProgressUpdated(int maxProgress) throws RemoteException { - } - - @Override - public void onSectionComplete(String title, int status, int size, int durationMs) - throws RemoteException { - } } } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index ab8cc5374ec9..c87ab9794563 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -321,14 +321,21 @@ class AppsFilter { private boolean shouldFilterApplicationInternal( PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, int userId) { final String callingName = callingPkgSetting.pkg.packageName; - final String targetName = targetPkgSetting.pkg.packageName; + final PackageParser.Package targetPkg = targetPkgSetting.pkg; + + // This package isn't technically installed and won't be written to settings, so we can + // treat it as filtered until it's available again. + if (targetPkg == null) { + return true; + } + final String targetName = targetPkg.packageName; if (callingPkgSetting.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) { return false; } if (isImplicitlyQueryableSystemApp(targetPkgSetting)) { return false; } - if (targetPkgSetting.pkg.mForceQueryable) { + if (targetPkg.mForceQueryable) { return false; } if (mForceQueryable.contains(targetName)) { diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 984f22f01465..c7124314cae0 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -281,20 +281,7 @@ public class BackgroundDexOptService extends JobService { mAbortIdleOptimization.set(false); long lowStorageThreshold = getLowStorageThreshold(context); - // Optimize primary apks. - int result = optimizePackages(pm, pkgs, lowStorageThreshold, - /*isForPrimaryDex=*/ true); - if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { - return result; - } - if (supportSecondaryDex()) { - result = reconcileSecondaryDexFiles(pm.getDexManager()); - if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { - return result; - } - result = optimizePackages(pm, pkgs, lowStorageThreshold, - /*isForPrimaryDex=*/ false); - } + int result = idleOptimizePackages(pm, pkgs, lowStorageThreshold); return result; } @@ -342,11 +329,20 @@ public class BackgroundDexOptService extends JobService { return 0; } - private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs, - long lowStorageThreshold, boolean isForPrimaryDex) { + private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs, + long lowStorageThreshold) { ArraySet<String> updatedPackages = new ArraySet<>(); try { + final boolean supportSecondaryDex = supportSecondaryDex(); + + if (supportSecondaryDex) { + int result = reconcileSecondaryDexFiles(pm.getDexManager()); + if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) { + return result; + } + } + // Only downgrade apps when space is low on device. // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean // up disk before user hits the actual lowStorageThreshold. @@ -359,43 +355,61 @@ public class BackgroundDexOptService extends JobService { pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis); Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages)); - for (String pkg : unusedPackages) { - int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1); - if (abortCode != OPTIMIZE_CONTINUE) { - // Should be aborted by the scheduler. - return abortCode; - } - if (downgradePackage(pm, pkg, isForPrimaryDex)) { - updatedPackages.add(pkg); + if (!unusedPackages.isEmpty()) { + for (String pkg : unusedPackages) { + int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1); + if (abortCode != OPTIMIZE_CONTINUE) { + // Should be aborted by the scheduler. + return abortCode; + } + if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) { + updatedPackages.add(pkg); + } + if (supportSecondaryDex) { + downgradePackage(pm, pkg, /*isForPrimaryDex*/ false); + } } - } - if (!unusedPackages.isEmpty()) { pkgs = new ArraySet<>(pkgs); pkgs.removeAll(unusedPackages); } } - for (String pkg : pkgs) { - int abortCode = abortIdleOptimizations(lowStorageThreshold); - if (abortCode != OPTIMIZE_CONTINUE) { - // Either aborted by the scheduler or no space left. - return abortCode; - } + int primaryResult = optimizePackages(pm, pkgs, lowStorageThreshold, + /*isForPrimaryDex*/ true, updatedPackages); + if (primaryResult != OPTIMIZE_PROCESSED) { + return primaryResult; + } - boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex); - if (dexOptPerformed) { - updatedPackages.add(pkg); - } + if (!supportSecondaryDex) { + return OPTIMIZE_PROCESSED; } - return OPTIMIZE_PROCESSED; + int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold, + /*isForPrimaryDex*/ false, updatedPackages); + return secondaryResult; } finally { // Always let the pinner service know about changes. notifyPinService(updatedPackages); } } + private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs, + long lowStorageThreshold, boolean isForPrimaryDex, ArraySet<String> updatedPackages) { + for (String pkg : pkgs) { + int abortCode = abortIdleOptimizations(lowStorageThreshold); + if (abortCode != OPTIMIZE_CONTINUE) { + // Either aborted by the scheduler or no space left. + return abortCode; + } + + boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex); + if (dexOptPerformed) { + updatedPackages.add(pkg); + } + } + return OPTIMIZE_PROCESSED; + } /** * Try to downgrade the package to a smaller compilation filter. diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index 8f38026b365f..5eaddf9ffa05 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -686,7 +686,7 @@ class InstantAppRegistry { // Prune first installed instant apps synchronized (mService.mLock) { - allUsers = PackageManagerService.sUserManager.getUserIds(); + allUsers = mService.mUserManager.getUserIds(); final int packageCount = mService.mPackages.size(); for (int i = 0; i < packageCount; i++) { diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java index 6f46564068d9..c21d0cf54d91 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelper.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java @@ -26,7 +26,7 @@ import java.io.File; import java.util.Set; @VisibleForTesting -interface PackageAbiHelper { +public interface PackageAbiHelper { /** * Derive and get the location of native libraries for the given package, * which varies depending on where and how the package was installed. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 8960dfb7106c..89ddc151719e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -92,6 +92,7 @@ import static android.os.storage.StorageManager.FLAG_STORAGE_DE; import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL; import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED; +import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE; import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; @@ -117,7 +118,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; -import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.IActivityManager; @@ -314,7 +314,6 @@ import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.permission.PermissionsState; import com.android.server.policy.PermissionPolicyInternal; -import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; import com.android.server.security.VerityUtils; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.utils.TimingsTraceAndSlog; @@ -663,7 +662,7 @@ public class PackageManagerService extends IPackageManager.Stub // Lock for state used when installing and doing other long running // operations. Methods that must be called with this lock held have // the suffix "LI". - final Object mInstallLock = new Object(); + final Object mInstallLock; // ---------------------------------------------------------------- @@ -697,6 +696,9 @@ public class PackageManagerService extends IPackageManager.Stub */ boolean mPromoteSystemApps; + private final PackageManagerInternal mPmInternal; + + @GuardedBy("mLock") final Settings mSettings; @@ -752,25 +754,195 @@ public class PackageManagerService extends IPackageManager.Stub private final Injector mInjector; /** - * Unit tests will instantiate and / or extend to mock dependencies / behaviors. + * Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors. + * + * NOTE: All getters should return the same instance for every call. */ - @VisibleForTesting - static class Injector { - private final UserManagerInternal mUserManager; - private final PackageAbiHelper mAbiHelper; + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Injector { + + @VisibleForTesting(visibility = Visibility.PRIVATE) + interface Producer<T> { + /** Produce an instance of type {@link T} */ + T produce(Injector injector, PackageManagerService packageManager); + } + + static class LocalServicesProducer<T> implements Producer<T> { + private final Class<T> mProducingClass; + LocalServicesProducer(Class<T> clazz) { + this.mProducingClass = clazz; + } + public T produce(Injector injector, PackageManagerService packageManager) { + return LocalServices.getService(mProducingClass); + } + } - Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) { - mUserManager = userManager; + static class SystemServiceProducer<T> implements Producer<T> { + private final Class<T> mProducingClass; + SystemServiceProducer(Class<T> clazz) { + this.mProducingClass = clazz; + } + public T produce(Injector injector, PackageManagerService packageManager) { + return packageManager.mContext.getSystemService(mProducingClass); + } + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static class Singleton<T> { + private final Producer<T> mProducer; + private volatile T mInstance = null; + Singleton(Producer<T> producer) { + this.mProducer = producer; + } + T get(Injector injector, PackageManagerService packageManagerService) { + if (mInstance == null) { + mInstance = mProducer.produce(injector, packageManagerService); + } + return mInstance; + } + } + + private PackageManagerService mPackageManager; + + private final PackageAbiHelper mAbiHelper; + private final Context mContext; + private final Object mLock; + private final Installer mInstaller; + private final Object mInstallLock; + + // ----- producers ----- + private final Singleton<ComponentResolver> mComponentResolverProducer; + private final Singleton<PermissionManagerServiceInternal> mPermissionManagerProducer; + private final Singleton<UserManagerService> mUserManagerProducer; + private final Singleton<Settings> mSettingsProducer; + private final Singleton<ActivityTaskManagerInternal> mActivityTaskManagerProducer; + private final Singleton<DeviceIdleController.LocalService> mLocalDeviceIdleController; + private final Singleton<StorageManagerInternal> mStorageManagerInternalProducer; + private final Singleton<NetworkPolicyManagerInternal> mNetworkPolicyManagerProducer; + private final Singleton<PermissionPolicyInternal> mPermissionPolicyProducer; + private final Singleton<DeviceStorageMonitorInternal> mDeviceStorageMonitorProducer; + private final Singleton<DisplayManager> mDisplayManagerProducer; + private final Singleton<StorageManager> mStorageManagerProducer; + private final Singleton<AppOpsManager> mAppOpsManagerProducer; + + Injector(Context context, Object lock, Installer installer, + Object installLock, PackageAbiHelper abiHelper, + Producer<ComponentResolver> componentResolverProducer, + Producer<PermissionManagerServiceInternal> permissionManagerProducer, + Producer<UserManagerService> userManagerProducer, + Producer<Settings> settingsProducer, + Producer<ActivityTaskManagerInternal> activityTaskManagerProducer, + Producer<DeviceIdleController.LocalService> deviceIdleControllerProducer, + Producer<StorageManagerInternal> storageManagerInternalProducer, + Producer<NetworkPolicyManagerInternal> networkPolicyManagerProducer, + Producer<PermissionPolicyInternal> permissionPolicyProvider, + Producer<DeviceStorageMonitorInternal> deviceStorageMonitorProducer, + Producer<DisplayManager> displayManagerProducer, + Producer<StorageManager> storageManagerProducer, + Producer<AppOpsManager> appOpsManagerProducer) { + mContext = context; + mLock = lock; + mInstaller = installer; mAbiHelper = abiHelper; + mInstallLock = installLock; + mComponentResolverProducer = new Singleton<>(componentResolverProducer); + mPermissionManagerProducer = new Singleton<>(permissionManagerProducer); + mUserManagerProducer = new Singleton<>(userManagerProducer); + mSettingsProducer = new Singleton<>(settingsProducer); + mActivityTaskManagerProducer = new Singleton<>(activityTaskManagerProducer); + mLocalDeviceIdleController = new Singleton<>(deviceIdleControllerProducer); + mStorageManagerInternalProducer = new Singleton<>(storageManagerInternalProducer); + mNetworkPolicyManagerProducer = new Singleton<>(networkPolicyManagerProducer); + mPermissionPolicyProducer = new Singleton<>(permissionPolicyProvider); + mDeviceStorageMonitorProducer = new Singleton<>(deviceStorageMonitorProducer); + mDisplayManagerProducer = new Singleton<>(displayManagerProducer); + mStorageManagerProducer = new Singleton<>(storageManagerProducer); + mAppOpsManagerProducer = new Singleton<>(appOpsManagerProducer); } - public UserManagerInternal getUserManager() { - return mUserManager; + /** + * Bootstraps this injector with the {@link PackageManagerService instance to which it + * belongs. + */ + public void bootstrap(PackageManagerService pm) { + this.mPackageManager = pm; + } + + public UserManagerInternal getUserManagerInternal() { + return getUserManagerService().getInternalForInjectorOnly(); } public PackageAbiHelper getAbiHelper() { return mAbiHelper; } + + public Object getInstallLock() { + return mInstallLock; + } + + public UserManagerService getUserManagerService() { + return mUserManagerProducer.get(this, mPackageManager); + } + + public Object getLock() { + return mLock; + } + + public Installer getInstaller() { + return mInstaller; + } + + public ComponentResolver getComponentResolver() { + return mComponentResolverProducer.get(this, mPackageManager); + } + + public PermissionManagerServiceInternal getPermissionManagerServiceInternal() { + return mPermissionManagerProducer.get(this, mPackageManager); + } + + public Context getContext() { + return mContext; + } + + public Settings getSettings() { + return mSettingsProducer.get(this, mPackageManager); + } + + public ActivityTaskManagerInternal getActivityTaskManagerInternal() { + return mActivityTaskManagerProducer.get(this, mPackageManager); + } + + public DeviceIdleController.LocalService getLocalDeviceIdleController() { + return mLocalDeviceIdleController.get(this, mPackageManager); + } + + public StorageManagerInternal getStorageManagerInternal() { + return mStorageManagerInternalProducer.get(this, mPackageManager); + } + + public NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() { + return mNetworkPolicyManagerProducer.get(this, mPackageManager); + } + + public PermissionPolicyInternal getPermissionPolicyInternal() { + return mPermissionPolicyProducer.get(this, mPackageManager); + } + + public DeviceStorageMonitorInternal getDeviceStorageMonitorInternal() { + return mDeviceStorageMonitorProducer.get(this, mPackageManager); + } + + public DisplayManager getDisplayManager() { + return mDisplayManagerProducer.get(this, mPackageManager); + } + + public StorageManager getStorageManager() { + return mStorageManagerProducer.get(this, mPackageManager); + } + + public AppOpsManager getAppOpsManager() { + return mAppOpsManagerProducer.get(this, mPackageManager); + } } private final AppsFilter mAppsFilter; @@ -987,13 +1159,6 @@ public class PackageManagerService extends IPackageManager.Stub // List of packages names to keep cached, even if they are uninstalled for all users private List<String> mKeepUninstalledPackages; - private UserManagerInternal mUserManagerInternal; - private ActivityManagerInternal mActivityManagerInternal; - private ActivityTaskManagerInternal mActivityTaskManagerInternal; - private StorageManagerInternal mStorageManagerInternal; - - private DeviceIdleController.LocalService mDeviceIdleController; - private File mCacheDir; private Future<?> mPrepareAppDataFuture; @@ -1084,7 +1249,8 @@ public class PackageManagerService extends IPackageManager.Stub final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setTemporaryAppWhitelistDuration(whitelistTimeout); - DeviceIdleController.LocalService idleController = getDeviceIdleController(); + DeviceIdleController.LocalService idleController = + mInjector.getLocalDeviceIdleController(); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout, UserHandle.USER_SYSTEM, true, "intent filter verifier"); @@ -1351,7 +1517,7 @@ public class PackageManagerService extends IPackageManager.Stub private static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD = 2 * 60 * 60 * 1000L; /* two hours */ - static UserManagerService sUserManager; + UserManagerService mUserManager; // Stores a list of users whose package restrictions file needs to be updated private ArraySet<Integer> mDirtyUsers = new ArraySet<>(); @@ -1948,8 +2114,7 @@ public class PackageManagerService extends IPackageManager.Stub // Send broadcast package appeared if external for all users if (isExternal(res.pkg)) { if (!update) { - final StorageManager storage = - mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); VolumeInfo volume = storage.findVolumeByUuid( res.pkg.applicationInfo.storageUuid.toString()); @@ -2140,7 +2305,7 @@ public class PackageManagerService extends IPackageManager.Stub // Clean up any users or apps that were removed or recreated // while this volume was missing - sUserManager.reconcileUsers(volumeUuid); + mUserManager.reconcileUsers(volumeUuid); reconcileApps(volumeUuid); // Clean up any install sessions that expired or were @@ -2225,9 +2390,9 @@ public class PackageManagerService extends IPackageManager.Stub void scheduleWritePackageRestrictionsLocked(int userId) { final int[] userIds = (userId == UserHandle.USER_ALL) - ? sUserManager.getUserIds() : new int[]{userId}; + ? mUserManager.getUserIds() : new int[]{userId}; for (int nextUserId : userIds) { - if (!sUserManager.exists(nextUserId)) return; + if (!mUserManager.exists(nextUserId)) return; mDirtyUsers.add(nextUserId); if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) { mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY); @@ -2239,10 +2404,39 @@ public class PackageManagerService extends IPackageManager.Stub boolean factoryTest, boolean onlyCore) { // Self-check for initial settings. PackageManagerServiceCompilerMapping.checkProperties(); - final Object packageLock = new Object(); + final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", + Trace.TRACE_TAG_PACKAGE_MANAGER); + t.traceBegin("create package manager"); + final Object lock = new Object(); + final Object installLock = new Object(); + + Injector injector = new Injector( + context, lock, installer, installLock, new PackageAbiHelperImpl(), + (i, pm) -> + new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock), + (i, pm) -> + PermissionManagerService.create(context, lock), + (i, pm) -> + new UserManagerService(context, pm, + new UserDataPreparer(installer, installLock, context, onlyCore), + lock), + (i, pm) -> + new Settings(Environment.getDataDirectory(), + i.getPermissionManagerServiceInternal().getPermissionSettings(), + lock), + new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class), + new Injector.LocalServicesProducer<>(DeviceIdleController.LocalService.class), + new Injector.LocalServicesProducer<>(StorageManagerInternal.class), + new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class), + new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class), + new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class), + new Injector.SystemServiceProducer<>(DisplayManager.class), + new Injector.SystemServiceProducer<>(StorageManager.class), + new Injector.SystemServiceProducer<>(AppOpsManager.class)); + + PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore); + t.traceEnd(); // "create package manager" - PackageManagerService m = new PackageManagerService(context, installer, - factoryTest, onlyCore, packageLock); m.enableSystemUserPackages(); ServiceManager.addService("package", m); final PackageManagerNative pmn = m.new PackageManagerNative(); @@ -2294,9 +2488,8 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) { - DisplayManager displayManager = (DisplayManager) context.getSystemService( - Context.DISPLAY_SERVICE); + private static void getDefaultDisplayMetrics( + DisplayManager displayManager, DisplayMetrics metrics) { displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics); } @@ -2333,12 +2526,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - public PackageManagerService(Context context, Installer installer, boolean factoryTest, - boolean onlyCore, Object packageLock) { + public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", Trace.TRACE_TAG_PACKAGE_MANAGER); - t.traceBegin("create package manager"); - mLock = packageLock; + mInjector = injector; + mInjector.bootstrap(this); + mLock = injector.getLock(); + mInstallLock = injector.getInstallLock(); LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); @@ -2347,38 +2541,24 @@ public class PackageManagerService extends IPackageManager.Stub Slog.w(TAG, "**** ro.build.version.sdk not set!"); } - mContext = context; + mContext = injector.getContext(); mFactoryTest = factoryTest; mOnlyCore = onlyCore; mMetrics = new DisplayMetrics(); - mInstaller = installer; + mInstaller = injector.getInstaller(); // Create sub-components that provide services / data. Order here is important. t.traceBegin("createSubComponents"); - // CHECKSTYLE:OFF IndentationCheck - synchronized (mInstallLock) { - synchronized (mLock) { - // Expose private service for system components to use. - LocalServices.addService( - PackageManagerInternal.class, new PackageManagerInternalImpl()); - sUserManager = new UserManagerService(context, this, - new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), - mLock); - mComponentResolver = new ComponentResolver(sUserManager, - LocalServices.getService(PackageManagerInternal.class), - mLock); - mPermissionManager = PermissionManagerService.create(context, - mLock /*externalLock*/); - mPermissionManagerService = - (IPermissionManager) ServiceManager.getService("permissionmgr"); - mSettings = new Settings(Environment.getDataDirectory(), - mPermissionManager.getPermissionSettings(), mLock); - } - } - - // TODO(b/137961986): We should pass this via constructor, but would first need to create - // a packages lock that could also be passed in. - mInjector = new Injector(getUserManagerInternal(), new PackageAbiHelperImpl()); + + // Expose private service for system components to use. + mPmInternal = new PackageManagerInternalImpl(); + LocalServices.addService(PackageManagerInternal.class, mPmInternal); + mUserManager = injector.getUserManagerService(); + mComponentResolver = injector.getComponentResolver(); + mPermissionManager = injector.getPermissionManagerServiceInternal(); + mSettings = injector.getSettings(); + mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr"); + // CHECKSTYLE:ON IndentationCheck t.traceEnd(); @@ -2418,15 +2598,16 @@ public class PackageManagerService extends IPackageManager.Stub mSeparateProcesses = null; } - mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context, + mPackageDexOptimizer = new PackageDexOptimizer(mInstaller, mInstallLock, mContext, "*dexopt*"); - mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock); - mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock); + mDexManager = + new DexManager(mContext, this, mPackageDexOptimizer, mInstaller, mInstallLock); + mArtManagerService = new ArtManagerService(mContext, this, mInstaller, mInstallLock); mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper()); mViewCompiler = new ViewCompiler(mInstallLock, mInstaller); - getDefaultDisplayMetrics(context, mMetrics); + getDefaultDisplayMetrics(mInjector.getDisplayManager(), mMetrics); t.traceBegin("get system config"); SystemConfig systemConfig = SystemConfig.getInstance(); @@ -2435,8 +2616,8 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); - mApexManager = ApexManager.create(context); - mAppsFilter = AppsFilter.create(context); + mApexManager = ApexManager.create(mContext); + mAppsFilter = AppsFilter.create(mContext); // CHECKSTYLE:OFF IndentationCheck synchronized (mInstallLock) { @@ -2482,7 +2663,7 @@ public class PackageManagerService extends IPackageManager.Stub t.traceEnd(); t.traceBegin("read user settings"); - mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false)); + mFirstBoot = !mSettings.readLPw(mUserManager.getUsers(false)); t.traceEnd(); // Clean up orphaned packages for which the code path doesn't exist @@ -3136,8 +3317,8 @@ public class PackageManagerService extends IPackageManager.Stub // If this is the first boot or an update from pre-M, and it is a normal // boot, then we need to initialize the default preferred apps across // all defined users. - if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) { - for (UserInfo user : sUserManager.getUsers(true)) { + if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) { + for (UserInfo user : mUserManager.getUsers(true)) { mSettings.applyDefaultPreferredAppsLPw(user.id); primeDomainVerificationsLPw(user.id); } @@ -3197,7 +3378,7 @@ public class PackageManagerService extends IPackageManager.Stub // Note that we do *not* clear the application profiles. These remain valid // across OTAs and are used to drive profile verification (post OTA) and // profile compilation (without waiting to collect a fresh set of profiles). - if (mIsUpgrade && !onlyCore) { + if (mIsUpgrade && !mOnlyCore) { Slog.i(TAG, "Build fingerprint changed; clearing code caches"); for (int i = 0; i < mSettings.mPackages.size(); i++) { final PackageSetting ps = mSettings.mPackages.valueAt(i); @@ -3214,7 +3395,7 @@ public class PackageManagerService extends IPackageManager.Stub // Grandfather existing (installed before Q) non-system apps to hide // their icons in launcher. - if (!onlyCore && mIsPreQUpgrade) { + if (!mOnlyCore && mIsPreQUpgrade) { Slog.i(TAG, "Whitelisting all existing apps to hide their icons"); int size = mSettings.mPackages.size(); for (int i = 0; i < size; i++) { @@ -3286,7 +3467,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - mInstallerService = new PackageInstallerService(context, this, mApexManager); + mInstallerService = new PackageInstallerService(mContext, this, mApexManager); final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { @@ -3342,8 +3523,6 @@ public class PackageManagerService extends IPackageManager.Stub PackageParser.readConfigUseRoundIcon(mContext.getResources()); mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L); - - t.traceEnd(); // "create package manager" } /** @@ -4025,7 +4204,7 @@ public class PackageManagerService extends IPackageManager.Stub } private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; if (ps == null) { return null; } @@ -4128,7 +4307,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPackageAvailable(String packageName, int userId) { - if (!sUserManager.exists(userId)) return false; + if (!mUserManager.exists(userId)) return false; final int callingUid = Binder.getCallingUid(); mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "is package available"); @@ -4171,7 +4350,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; flags = updateFlagsForPackage(flags, userId, packageName); mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission */, false /* checkShell */, "get package info"); @@ -4472,7 +4651,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int getPackageUid(String packageName, int flags, int userId) { - if (!sUserManager.exists(userId)) return -1; + if (!mUserManager.exists(userId)) return -1; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForPackage(flags, userId, packageName); mPermissionManager.enforceCrossUserPermission(callingUid, userId, @@ -4502,7 +4681,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int[] getPackageGids(String packageName, int flags, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForPackage(flags, userId, packageName); mPermissionManager.enforceCrossUserPermission(callingUid, userId, @@ -4546,7 +4725,7 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int filterCallingUid, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { @@ -4585,7 +4764,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private ApplicationInfo getApplicationInfoInternal(String packageName, int flags, int filterCallingUid, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; flags = updateFlagsForApplication(flags, userId, packageName); if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) { @@ -4699,7 +4878,7 @@ public class PackageManagerService extends IPackageManager.Stub * until the requested bytes are available. */ public void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException { - final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); final File file = storage.findPathForUuid(volumeUuid); if (file.getUsableSpace() >= bytes) return; @@ -4782,14 +4961,14 @@ public class PackageManagerService extends IPackageManager.Stub private boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod) throws IOException { - final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL); List<VersionedPackage> packagesToDelete = null; final long now = System.currentTimeMillis(); synchronized (mLock) { - final int[] allUsers = sUserManager.getUserIds(); + final int[] allUsers = mUserManager.getUserIds(); final int libCount = mSharedLibraries.size(); for (int i = 0; i < libCount; i++) { final LongSparseArray<SharedLibraryInfo> versionedLib @@ -4861,7 +5040,7 @@ public class PackageManagerService extends IPackageManager.Stub // give them what they want } else { // Caller expressed no opinion, so match based on user state - if (getUserManagerInternal().isUserUnlockingOrUnlocked(userId)) { + if (mUserManager.isUserUnlockingOrUnlocked(userId)) { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; } else { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE; @@ -4870,43 +5049,6 @@ public class PackageManagerService extends IPackageManager.Stub return flags; } - private UserManagerInternal getUserManagerInternal() { - if (mUserManagerInternal == null) { - mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); - } - return mUserManagerInternal; - } - - private ActivityManagerInternal getActivityManagerInternal() { - if (mActivityManagerInternal == null) { - mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); - } - return mActivityManagerInternal; - } - - private ActivityTaskManagerInternal getActivityTaskManagerInternal() { - if (mActivityTaskManagerInternal == null) { - mActivityTaskManagerInternal = - LocalServices.getService(ActivityTaskManagerInternal.class); - } - return mActivityTaskManagerInternal; - } - - private DeviceIdleController.LocalService getDeviceIdleController() { - if (mDeviceIdleController == null) { - mDeviceIdleController = - LocalServices.getService(DeviceIdleController.LocalService.class); - } - return mDeviceIdleController; - } - - private StorageManagerInternal getStorageManagerInternal() { - if (mStorageManagerInternal == null) { - mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class); - } - return mStorageManagerInternal; - } - /** * Update given flags when being used to request {@link PackageInfo}. */ @@ -4921,7 +5063,7 @@ public class PackageManagerService extends IPackageManager.Stub "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at " + Debug.getCallers(5)); } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser - && sUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) { + && mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) { // If the caller wants all packages and has a restricted profile associated with it, // then match all users. This is to make sure that launchers that need to access work // profile apps don't start breaking. TODO: Remove this hack when launchers stop using @@ -5018,7 +5160,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId, component); if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) { @@ -5049,7 +5191,7 @@ public class PackageManagerService extends IPackageManager.Stub } private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) { - if (!getActivityTaskManagerInternal().isCallerRecents(callingUid)) { + if (!mInjector.getActivityTaskManagerInternal().isCallerRecents(callingUid)) { return false; } final long token = Binder.clearCallingIdentity(); @@ -5058,7 +5200,7 @@ public class PackageManagerService extends IPackageManager.Stub if (ActivityManager.getCurrentUser() != callingUserId) { return false; } - return sUserManager.isSameProfileGroup(callingUserId, targetUserId); + return mUserManager.isSameProfileGroup(callingUserId, targetUserId); } finally { Binder.restoreCallingIdentity(token); } @@ -5098,7 +5240,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId, component); mPermissionManager.enforceCrossUserPermission(callingUid, userId, @@ -5124,7 +5266,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName, int flags, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0"); if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return null; @@ -5206,7 +5348,7 @@ public class PackageManagerService extends IPackageManager.Stub Preconditions.checkNotNull(packageName, "packageName cannot be null"); Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0"); - if (!sUserManager.exists(userId)) { + if (!mUserManager.exists(userId)) { return null; } @@ -5313,7 +5455,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId, component); mPermissionManager.enforceCrossUserPermission(callingUid, userId, @@ -5338,7 +5480,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId, component); mPermissionManager.enforceCrossUserPermission(callingUid, userId, @@ -6038,7 +6180,7 @@ public class PackageManagerService extends IPackageManager.Stub try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent"); - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart); mPermissionManager.enforceCrossUserPermission(callingUid, userId, @@ -6063,7 +6205,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException( "findPersistentPreferredActivity can only be run by the system"); } - if (!sUserManager.exists(userId)) { + if (!mUserManager.exists(userId)) { return null; } final int callingUid = Binder.getCallingUid(); @@ -6376,7 +6518,7 @@ public class PackageManagerService extends IPackageManager.Stub Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding mPackages", new Throwable()); } - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); // Do NOT hold the packages lock; this calls up into the settings provider which // could cause a deadlock. @@ -6605,7 +6747,7 @@ public class PackageManagerService extends IPackageManager.Stub private UserInfo getProfileParent(int userId) { final long identity = Binder.clearCallingIdentity(); try { - return sUserManager.getProfileParent(userId); + return mUserManager.getProfileParent(userId); } finally { Binder.restoreCallingIdentity(identity); } @@ -6664,7 +6806,7 @@ public class PackageManagerService extends IPackageManager.Stub private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { - if (!sUserManager.exists(userId)) return Collections.emptyList(); + if (!mUserManager.exists(userId)) return Collections.emptyList(); final String instantAppPkgName = getInstantAppPackageName(filterCallingUid); mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission */, false /* checkShell */, @@ -6938,7 +7080,7 @@ public class PackageManagerService extends IPackageManager.Stub private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId) { - if (!sUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, + if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, sourceUserId)) { return null; } @@ -6999,7 +7141,7 @@ public class PackageManagerService extends IPackageManager.Stub private boolean isUserEnabled(int userId) { long callingId = Binder.clearCallingIdentity(); try { - UserInfo userInfo = sUserManager.getUserInfo(userId); + UserInfo userInfo = mUserManager.getUserInfo(userId); return userInfo != null && userInfo.isEnabled(); } finally { Binder.restoreCallingIdentity(callingId); @@ -7404,7 +7546,7 @@ public class PackageManagerService extends IPackageManager.Stub long ident = Binder.clearCallingIdentity(); boolean targetIsProfile; try { - targetIsProfile = sUserManager.getUserInfo(targetUserId).isManagedProfile(); + targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile(); } finally { Binder.restoreCallingIdentity(ident); } @@ -7443,7 +7585,7 @@ public class PackageManagerService extends IPackageManager.Stub private @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) { - if (!sUserManager.exists(userId)) return Collections.emptyList(); + if (!mUserManager.exists(userId)) return Collections.emptyList(); final int callingUid = Binder.getCallingUid(); flags = updateFlagsForResolve(flags, userId, intent, callingUid, false /*includeInstantApps*/); @@ -7626,7 +7768,7 @@ public class PackageManagerService extends IPackageManager.Stub private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent, String resolvedType, int flags, int userId, boolean allowDynamicSplits) { - if (!sUserManager.exists(userId)) return Collections.emptyList(); + if (!mUserManager.exists(userId)) return Collections.emptyList(); final int callingUid = Binder.getCallingUid(); mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, @@ -7716,7 +7858,7 @@ public class PackageManagerService extends IPackageManager.Stub private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; flags = updateFlagsForResolve( flags, userId, intent, callingUid, false /*includeInstantApps*/); List<ResolveInfo> query = queryIntentServicesInternal( @@ -7742,7 +7884,7 @@ public class PackageManagerService extends IPackageManager.Stub private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid, boolean includeInstantApps) { - if (!sUserManager.exists(userId)) return Collections.emptyList(); + if (!mUserManager.exists(userId)) return Collections.emptyList(); mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "query intent receivers"); @@ -7861,7 +8003,7 @@ public class PackageManagerService extends IPackageManager.Stub private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal( Intent intent, String resolvedType, int flags, int userId) { - if (!sUserManager.exists(userId)) return Collections.emptyList(); + if (!mUserManager.exists(userId)) return Collections.emptyList(); final int callingUid = Binder.getCallingUid(); final String instantAppPkgName = getInstantAppPackageName(callingUid); flags = updateFlagsForResolve(flags, userId, intent, callingUid, @@ -7976,7 +8118,7 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return ParceledListSlice.emptyList(); } - if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); + if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForPackage(flags, userId, null); final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0; final boolean listApex = (flags & MATCH_APEX) != 0; @@ -8076,7 +8218,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions( String[] permissions, int flags, int userId) { - if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); + if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForPackage(flags, userId, permissions); mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, @@ -8118,7 +8260,7 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return Collections.emptyList(); } - if (!sUserManager.exists(userId)) return Collections.emptyList(); + if (!mUserManager.exists(userId)) return Collections.emptyList(); flags = updateFlagsForApplication(flags, userId, null); final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0; @@ -8348,7 +8490,7 @@ public class PackageManagerService extends IPackageManager.Stub } private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) { - if (!sUserManager.exists(userId)) return null; + if (!mUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId, name); final int callingUid = Binder.getCallingUid(); final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId); @@ -8387,7 +8529,7 @@ public class PackageManagerService extends IPackageManager.Stub final int callingUid = Binder.getCallingUid(); final int userId = processName != null ? UserHandle.getUserId(uid) : UserHandle.getCallingUserId(); - if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); + if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForComponent(flags, userId, processName); ArrayList<ProviderInfo> finalList = null; final List<ProviderInfo> matchList = @@ -9763,7 +9905,7 @@ public class PackageManagerService extends IPackageManager.Stub } private int[] resolveUserIds(int userId) { - return (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds() : new int[] { userId }; + return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId }; } private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) { @@ -10159,7 +10301,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) { final int flags = pkg.isUpdatedSystemApp() ? PackageManager.DELETE_KEEP_DATA : 0; - deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(), + deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(), flags , null, true, null); } Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); @@ -10728,7 +10870,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean isUnderFactoryTest, long currentTime) throws PackageManagerException { final PackageAbiHelper packageAbiHelper = injector.getAbiHelper(); - final UserManagerInternal userManager = injector.getUserManager(); + final UserManagerInternal userManager = injector.getUserManagerInternal(); final PackageParser.Package pkg = request.pkg; PackageSetting pkgSetting = request.pkgSetting; final PackageSetting disabledPkgSetting = request.disabledPkgSetting; @@ -10834,7 +10976,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!createNewPackage) { final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0; - setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp); + setInstantAppForUser(injector, pkgSetting, userId, instantApp, fullApp); } // TODO(patb): see if we can do away with disabled check here. if (disabledPkgSetting != null @@ -12296,10 +12438,10 @@ public class PackageManagerService extends IPackageManager.Stub * automatically without needing an explicit launch. * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones. */ - private void sendBootCompletedBroadcastToSystemApp(String packageName, boolean includeStopped, - int userId) { + private void sendBootCompletedBroadcastToSystemApp( + String packageName, boolean includeStopped, int userId) { // If user is not running, the app didn't miss any broadcast - if (!mUserManagerInternal.isUserRunning(userId)) { + if (!mUserManager.isUserRunning(userId)) { return; } final IActivityManager am = ActivityManager.getService(); @@ -12315,7 +12457,7 @@ public class PackageManagerService extends IPackageManager.Stub android.app.AppOpsManager.OP_NONE, null, false, false, userId); // Deliver BOOT_COMPLETED only if user is unlocked - if (mUserManagerInternal.isUserUnlockingOrUnlocked(userId)) { + if (mUserManager.isUserUnlockingOrUnlocked(userId)) { Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName); if (includeStopped) { bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); @@ -12593,7 +12735,7 @@ public class PackageManagerService extends IPackageManager.Stub // only allow the existing package to be used if it's installed as a full // application for at least one user boolean installAllowed = false; - for (int checkUserId : sUserManager.getUserIds()) { + for (int checkUserId : mUserManager.getUserIds()) { installAllowed = !pkgSetting.getInstantApp(checkUserId); if (installAllowed) { break; @@ -12614,8 +12756,7 @@ public class PackageManagerService extends IPackageManager.Stub // upgrade app from instant to full; we don't allow app downgrade installed = true; } - setInstantAppForUser( - getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp); + setInstantAppForUser(mInjector, pkgSetting, userId, instantApp, fullApp); } if (installed) { @@ -12663,7 +12804,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting, + static void setInstantAppForUser(Injector injector, PackageSetting pkgSetting, int userId, boolean instantApp, boolean fullApp) { // no state specified; do nothing if (!instantApp && !fullApp) { @@ -12676,7 +12817,7 @@ public class PackageManagerService extends IPackageManager.Stub pkgSetting.setInstantApp(false /*instantApp*/, userId); } } else { - for (int currentUserId : userManager.getUserIds()) { + for (int currentUserId : injector.getUserManagerInternal().getUserIds()) { if (instantApp && !pkgSetting.getInstantApp(currentUserId)) { pkgSetting.setInstantApp(true /*instantApp*/, currentUserId); } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) { @@ -12687,7 +12828,7 @@ public class PackageManagerService extends IPackageManager.Stub } boolean isUserRestricted(int userId, String restrictionKey) { - Bundle restrictions = sUserManager.getUserRestrictions(userId); + Bundle restrictions = mUserManager.getUserRestrictions(userId); if (restrictions.getBoolean(restrictionKey, false)) { Log.w(TAG, "User is restricted: " + restrictionKey); return true; @@ -12925,7 +13066,7 @@ public class PackageManagerService extends IPackageManager.Stub * @param affectedUser The user for which the changes are taking place. */ void unsuspendForSuspendingPackage(final String packageName, int affectedUser) { - final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds() + final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] {affectedUser}; for (int userId : userIds) { unsuspendForSuspendingPackages(packageName::equals, userId); @@ -13281,7 +13422,7 @@ public class PackageManagerService extends IPackageManager.Stub * @return default verification response code */ private int getDefaultVerificationResponse(UserHandle user) { - if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) { + if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) { return PackageManager.VERIFICATION_REJECT; } return android.provider.Settings.Global.getInt(mContext.getContentResolver(), @@ -13327,7 +13468,7 @@ public class PackageManagerService extends IPackageManager.Stub && mInstantAppInstallerActivity.packageName.equals( mRequiredVerifierPackage)) { try { - mContext.getSystemService(AppOpsManager.class) + mInjector.getAppOpsManager() .checkPackage(installerUid, mRequiredVerifierPackage); if (DEBUG_VERIFY) { Slog.i(TAG, "disable verification for instant app"); @@ -13548,7 +13689,7 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(Binder.getCallingUid()) != null) { throw new SecurityException("Instant applications don't have access to this method"); } - mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), + mInjector.getAppOpsManager().checkPackage(Binder.getCallingUid(), callerPackageName); synchronized (mLock) { PackageSetting ps = mSettings.mPackages.get(packageName); @@ -13693,7 +13834,7 @@ public class PackageManagerService extends IPackageManager.Stub final String packageName = res.pkg.applicationInfo.packageName; final String seInfo = res.pkg.applicationInfo.seInfo; - final int[] allUsers = sUserManager.getUserIds(); + final int[] allUsers = mUserManager.getUserIds(); final int[] installedUsers; final PackageSetting ps; @@ -14366,7 +14507,8 @@ public class PackageManagerService extends IPackageManager.Stub final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, receivers, verificationState); - DeviceIdleController.LocalService idleController = getDeviceIdleController(); + DeviceIdleController.LocalService idleController = + mInjector.getLocalDeviceIdleController(); final long idleDuration = getVerificationTimeout(); /* @@ -14438,7 +14580,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName); if (ps != null) { - installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), + installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } else { installedUsers = new int[0]; @@ -14958,7 +15100,7 @@ public class PackageManagerService extends IPackageManager.Stub final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid), move.dataAppName); Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid); - final int[] userIds = sUserManager.getUserIds(); + final int[] userIds = mUserManager.getUserIds(); synchronized (mInstallLock) { // Clean up both app data and code // All package moves are frozen until finished @@ -15239,7 +15381,7 @@ public class PackageManagerService extends IPackageManager.Stub // Set install reason for users that are having the package newly installed. if (userId == UserHandle.USER_ALL) { - for (int currentUserId : sUserManager.getUserIds()) { + for (int currentUserId : mUserManager.getUserIds()) { if (!previousUserIds.contains(currentUserId)) { ps.setInstallReason(installReason, currentUserId); } @@ -15872,7 +16014,7 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { - res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); + res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); ps.setUpdateAvailable(false /*updateAvailable*/); } final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; @@ -15883,7 +16025,7 @@ public class PackageManagerService extends IPackageManager.Stub PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName); if (childPs != null) { childRes.newUsers = childPs.queryInstalledUsers( - sUserManager.getUserIds(), true); + mUserManager.getUserIds(), true); } } if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { @@ -16003,7 +16145,7 @@ public class PackageManagerService extends IPackageManager.Stub try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages"); commitRequest = new CommitRequest(reconciledPackages, - sUserManager.getUserIds()); + mUserManager.getUserIds()); commitPackagesLocked(commitRequest); success = true; } finally { @@ -16299,7 +16441,7 @@ public class PackageManagerService extends IPackageManager.Stub PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName); if (childPs != null) { childRes.origUsers = childPs.queryInstalledUsers( - sUserManager.getUserIds(), true); + mUserManager.getUserIds(), true); } if ((mPackages.containsKey(childPkg.packageName))) { childRes.removedInfo = new PackageRemovedInfo(this); @@ -16464,7 +16606,7 @@ public class PackageManagerService extends IPackageManager.Stub systemApp = (ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } - res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); + res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } @@ -16723,7 +16865,7 @@ public class PackageManagerService extends IPackageManager.Stub } // In case of rollback, remember per-user/profile install state - allUsers = sUserManager.getUserIds(); + allUsers = mUserManager.getUserIds(); installedUsers = ps.queryInstalledUsers(allUsers, true); @@ -17234,7 +17376,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0; - final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{userId}; + final int[] users = deleteAllUsers ? mUserManager.getUserIds() : new int[]{userId}; if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, @@ -17484,7 +17626,7 @@ public class PackageManagerService extends IPackageManager.Stub // Does it contain a device admin for any user? int[] users; if (userId == UserHandle.USER_ALL) { - users = sUserManager.getUserIds(); + users = mUserManager.getUserIds(); } else { users = new int[]{userId}; } @@ -17561,7 +17703,7 @@ public class PackageManagerService extends IPackageManager.Stub // allow removing a package if it provides a lib others depend on. pkg = mPackages.get(packageName); - allUsers = sUserManager.getUserIds(); + allUsers = mUserManager.getUserIds(); if (pkg != null && pkg.staticSharedLibName != null) { SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName, @@ -17811,7 +17953,7 @@ public class PackageManagerService extends IPackageManager.Stub outInfo.isStaticSharedLib = deletedPkg != null && deletedPkg.staticSharedLibName != null; outInfo.populateUsers(deletedPs == null ? null - : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs); + : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs); } removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0); @@ -17910,7 +18052,8 @@ public class PackageManagerService extends IPackageManager.Stub if (removedAppId != -1) { // A user ID was deleted here. Go through all users and remove it // from KeyStore. - removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId); + removeKeystoreDataIfNeeded( + mInjector.getUserManagerInternal(), UserHandle.USER_ALL, removedAppId); } } @@ -18417,7 +18560,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!systemApp) { // Do not uninstall the APK if an app should be cached boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName); - if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) { + if (ps.isAnyInstalled(mUserManager.getUserIds()) || keepUninstalledPackage) { // Other users still have this package installed, so all // we need to do is clear this user's data and save that // it is uninstalled. @@ -18531,7 +18674,7 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) { final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL) - ? sUserManager.getUserIds() : new int[] {user.getIdentifier()}; + ? mUserManager.getUserIds() : new int[] {user.getIdentifier()}; for (int nextUserId : userIds) { if (DEBUG_REMOVE) { Slog.d(TAG, "Marking package:" + ps.name + " uninstalled for user:" + nextUserId); @@ -18568,7 +18711,7 @@ public class PackageManagerService extends IPackageManager.Stub destroyAppProfilesLIF(pkg); - final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds() + final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] {userId}; for (int nextUserId : userIds) { if (DEBUG_REMOVE) { @@ -18579,7 +18722,7 @@ public class PackageManagerService extends IPackageManager.Stub destroyAppDataLIF(pkg, nextUserId, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); clearDefaultBrowserIfNeededForUser(ps.name, nextUserId); - removeKeystoreDataIfNeeded(nextUserId, ps.appId); + removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId); final SparseBooleanArray changedUsers = new SparseBooleanArray(); clearPackagePreferredActivitiesLPw(ps.name, changedUsers, nextUserId); if (changedUsers.size() > 0) { @@ -18712,9 +18855,9 @@ public class PackageManagerService extends IPackageManager.Stub FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); - removeKeystoreDataIfNeeded(userId, appId); + removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId); - UserManagerInternal umInternal = getUserManagerInternal(); + UserManagerInternal umInternal = mInjector.getUserManagerInternal(); final int flags; if (umInternal.isUserUnlockingOrUnlocked(userId)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; @@ -18729,14 +18872,14 @@ public class PackageManagerService extends IPackageManager.Stub } private void resetNetworkPolicies(int userId) { - LocalServices.getService(NetworkPolicyManagerInternal.class).resetUserState(userId); + mInjector.getNetworkPolicyManagerInternal().resetUserState(userId); } /** * Remove entries from the keystore daemon. Will only remove it if the * {@code appId} is valid. */ - private static void removeKeystoreDataIfNeeded(int userId, int appId) { + private static void removeKeystoreDataIfNeeded(UserManagerInternal um, int userId, int appId) { if (appId < 0) { return; } @@ -18744,7 +18887,7 @@ public class PackageManagerService extends IPackageManager.Stub final KeyStore keyStore = KeyStore.getInstance(); if (keyStore != null) { if (userId == UserHandle.USER_ALL) { - for (final int individual : sUserManager.getUserIds()) { + for (final int individual : um.getUserIds()) { keyStore.clearUid(UserHandle.getUid(individual, appId)); } } else { @@ -19145,8 +19288,8 @@ public class PackageManagerService extends IPackageManager.Stub void clearIntentFilterVerificationsLPw(String packageName, int userId) { if (userId == UserHandle.USER_ALL) { if (mSettings.removeIntentFilterVerificationLPw(packageName, - sUserManager.getUserIds())) { - for (int oneUserId : sUserManager.getUserIds()) { + mUserManager.getUserIds())) { + for (int oneUserId : mUserManager.getUserIds()) { scheduleWritePackageRestrictionsLocked(oneUserId); } } @@ -19159,7 +19302,7 @@ public class PackageManagerService extends IPackageManager.Stub /** Clears state for all users, and touches intent filter verification policy */ void clearDefaultBrowserIfNeeded(String packageName) { - for (int oneUserId : sUserManager.getUserIds()) { + for (int oneUserId : mUserManager.getUserIds()) { clearDefaultBrowserIfNeededForUser(packageName, oneUserId); } } @@ -19526,7 +19669,7 @@ public class PackageManagerService extends IPackageManager.Stub android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); int callingUid = Binder.getCallingUid(); enforceOwnerRights(ownerPackage, callingUid); - PackageManagerServiceUtils.enforceShellRestriction( + PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); if (intentFilter.countActions() == 0) { Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions"); @@ -19558,7 +19701,7 @@ public class PackageManagerService extends IPackageManager.Stub android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); final int callingUid = Binder.getCallingUid(); enforceOwnerRights(ownerPackage, callingUid); - PackageManagerServiceUtils.enforceShellRestriction( + PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); synchronized (mLock) { CrossProfileIntentResolver resolver = @@ -19907,7 +20050,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { - if (!sUserManager.exists(userId)) return; + if (!mUserManager.exists(userId)) return; if (callingPackage == null) { callingPackage = Integer.toString(Binder.getCallingUid()); } @@ -19928,7 +20071,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) { - if (!sUserManager.exists(userId)) return; + if (!mUserManager.exists(userId)) return; setEnabledSetting(componentName.getPackageName(), componentName.getClassName(), newState, flags, userId, null); } @@ -20155,7 +20298,7 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } - if (!sUserManager.exists(userId)) { + if (!mUserManager.exists(userId)) { return; } mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/, @@ -20196,7 +20339,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void setPackageStoppedState(String packageName, boolean stopped, int userId) { - if (!sUserManager.exists(userId)) return; + if (!mUserManager.exists(userId)) return; final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return; @@ -20246,7 +20389,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int getApplicationEnabledSetting(String packageName, int userId) { - if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; + if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int callingUid = Binder.getCallingUid(); mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get enabled"); @@ -20263,7 +20406,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) { if (component == null) return COMPONENT_ENABLED_STATE_DEFAULT; - if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; + if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int callingUid = Binder.getCallingUid(); mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled"); @@ -20361,7 +20504,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - sUserManager.systemReady(); + mUserManager.systemReady(); // Now that we've scanned all packages, and granted any default // permissions, ensure permissions are updated. Beware of dragons if you @@ -20370,7 +20513,7 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false); final PermissionPolicyInternal permissionPolicyInternal = - LocalServices.getService(PermissionPolicyInternal.class); + mInjector.getPermissionPolicyInternal(); permissionPolicyInternal.setOnInitializedCallback(userId -> { // The SDK updated case is already handled when we run during the ctor. synchronized (mPackages) { @@ -20381,14 +20524,14 @@ public class PackageManagerService extends IPackageManager.Stub } // Watch for external volumes that come and go over time - final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); storage.registerListener(mStorageListener); mInstallerService.systemReady(); mApexManager.systemReady(); mPackageDexOptimizer.systemReady(); - getStorageManagerInternal().addExternalStoragePolicy( + mInjector.getStorageManagerInternal().addExternalStoragePolicy( new StorageManagerInternal.ExternalStorageMountPolicy() { @Override public int getMountMode(int uid, String packageName) { @@ -20411,7 +20554,7 @@ public class PackageManagerService extends IPackageManager.Stub }); // Now that we're mostly running, clean up stale users and apps - sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL); + mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL); reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL); mPermissionManager.systemReady(); @@ -20889,7 +21032,7 @@ public class PackageManagerService extends IPackageManager.Stub pw.println(prefix + "No app verification established."); pw.println(); } - for (int userId : sUserManager.getUserIds()) { + for (int userId : mUserManager.getUserIds()) { pw.println("App linkages for user " + userId + ":"); pw.println(); count = 0; @@ -21054,7 +21197,7 @@ public class PackageManagerService extends IPackageManager.Stub } for (String packageName : apkList) { setSystemAppHiddenUntilInstalled(packageName, true); - for (UserInfo user : sUserManager.getUsers(false)) { + for (UserInfo user : mUserManager.getUsers(false)) { setSystemAppInstallState(packageName, false, user.id); } } @@ -21340,10 +21483,9 @@ public class PackageManagerService extends IPackageManager.Stub } // Reconcile app data for all started/unlocked users - final StorageManager sm = mContext.getSystemService(StorageManager.class); - final UserManager um = mContext.getSystemService(UserManager.class); - UserManagerInternal umInternal = getUserManagerInternal(); - for (UserInfo user : um.getUsers()) { + final StorageManager sm = mInjector.getStorageManager(); + UserManagerInternal umInternal = mInjector.getUserManagerInternal(); + for (UserInfo user : mUserManager.getUsers(false /* includeDying */)) { final int flags; if (umInternal.isUserUnlockingOrUnlocked(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; @@ -21533,7 +21675,7 @@ public class PackageManagerService extends IPackageManager.Stub * correct for all installed apps on all mounted volumes. */ void reconcileAppsData(int userId, int flags, boolean migrateAppsData) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { final String volumeUuid = vol.getFsUuid(); synchronized (mInstallLock) { @@ -21662,9 +21804,8 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeKernelMappingLPr(ps); } - final UserManager um = mContext.getSystemService(UserManager.class); - UserManagerInternal umInternal = getUserManagerInternal(); - for (UserInfo user : um.getUsers()) { + UserManagerInternal umInternal = mInjector.getUserManagerInternal(); + for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) { final int flags; if (umInternal.isUserUnlockingOrUnlocked(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; @@ -21995,7 +22136,7 @@ public class PackageManagerService extends IPackageManager.Stub private void movePackageInternal(final String packageName, final String volumeUuid, final int moveId, final int callingUid, UserHandle user) throws PackageManagerException { - final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); final PackageManager pm = mContext.getPackageManager(); final String currentVolumeUuid; @@ -22064,7 +22205,7 @@ public class PackageManagerService extends IPackageManager.Stub label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)); targetSdkVersion = pkg.applicationInfo.targetSdkVersion; freezer = freezePackage(packageName, "movePackageInternal"); - installedUserIds = ps.queryInstalledUsers(sUserManager.getUserIds(), true); + installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } final Bundle extras = new Bundle(); @@ -22231,7 +22372,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } - final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg)); @@ -22269,7 +22410,7 @@ public class PackageManagerService extends IPackageManager.Stub } }; - final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageManager storage = mInjector.getStorageManager(); storage.setPrimaryStorageUuid(volumeUuid, callback); return realMoveId; } @@ -22415,7 +22556,7 @@ public class PackageManagerService extends IPackageManager.Stub final long token = Binder.clearCallingIdentity(); try { final DeviceStorageMonitorInternal - dsm = LocalServices.getService(DeviceStorageMonitorInternal.class); + dsm = mInjector.getDeviceStorageMonitorInternal(); if (dsm != null) { return dsm.isMemoryLow(); } else { @@ -22445,7 +22586,7 @@ public class PackageManagerService extends IPackageManager.Stub final UserInfo userInfo; final long token = Binder.clearCallingIdentity(); try { - userInfo = sUserManager.getUserInfo(userId); + userInfo = mUserManager.getUserInfo(userId); } finally { Binder.restoreCallingIdentity(token); } @@ -22570,7 +22711,7 @@ public class PackageManagerService extends IPackageManager.Stub if (ps == null) { return; } - if (!ps.isAnyInstalled(sUserManager.getUserIds())) { + if (!ps.isAnyInstalled(mUserManager.getUserIds())) { // TODO Implement atomic delete if package is unused // It is currently possible that the package will be deleted even if it is installed // after this method returns. @@ -23853,8 +23994,8 @@ public class PackageManagerService extends IPackageManager.Stub return false; } } - if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId) - || sUserManager.hasUserRestriction( + if (mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId) + || mUserManager.hasUserRestriction( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userId)) { return false; } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 4c7db9afee0a..ef47410ded8c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -47,6 +47,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManagerInternal; import android.service.pm.PackageServiceDumpProto; import android.system.ErrnoException; import android.system.Os; @@ -375,10 +376,12 @@ public class PackageManagerServiceUtils { } } - public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) { + /** Enforces that if the caller is shell, it does not have the provided user restriction. */ + public static void enforceShellRestriction( + UserManagerInternal userManager, String restriction, int callingUid, int userHandle) { if (callingUid == Process.SHELL_UID) { if (userHandle >= 0 - && PackageManagerService.sUserManager.hasUserRestriction( + && userManager.hasUserRestriction( restriction, userHandle)) { throw new SecurityException("Shell does not have permission to access user " + userHandle); diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java index a374e1484b28..231168e9c660 100644 --- a/services/core/java/com/android/server/pm/ProtectedPackages.java +++ b/services/core/java/com/android/server/pm/ProtectedPackages.java @@ -92,6 +92,9 @@ public class ProtectedPackages { if (mDeviceOwnerUserId == userId) { return mDeviceOwnerPackage; } + if (mProfileOwnerPackages == null) { + return null; + } return mProfileOwnerPackages.get(userId); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index f4ba4492dcbb..a707aa884966 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -576,6 +576,14 @@ public class UserManagerService extends IUserManager.Stub { null, mHandler); } + /** + * This method retrieves the {@link UserManagerInternal} only for the purpose of + * PackageManagerService construction. + */ + UserManagerInternal getInternalForInjectorOnly() { + return mLocalService; + } + void cleanupPartialUsers() { // Prune out any partially created, partially removed and ephemeral users. ArrayList<UserInfo> partials = new ArrayList<>(); @@ -1549,11 +1557,7 @@ public class UserManagerService extends IUserManager.Stub { /** @return a specific user restriction that's in effect currently. */ @Override public boolean hasUserRestriction(String restrictionKey, int userId) { - if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) { - return false; - } - Bundle restrictions = getEffectiveUserRestrictions(userId); - return restrictions != null && restrictions.getBoolean(restrictionKey); + return mLocalService.hasUserRestriction(restrictionKey, userId); } /** @return if any user has the given restriction. */ @@ -4120,6 +4124,15 @@ public class UserManagerService extends IUserManager.Stub { return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId, value, callingUid); } + + @Override + public boolean hasUserRestriction(String restrictionKey, int userId) { + if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) { + return false; + } + Bundle restrictions = getEffectiveUserRestrictions(userId); + return restrictions != null && restrictions.getBoolean(restrictionKey); + } } /* Remove all the users except of the system one. */ diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 210a7afb11a2..e2644ffb9301 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1197,7 +1197,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null || pkg.mExtras == null) { - throw new IllegalArgumentException("Unknown package: " + packageName); + Log.e(TAG, "Unknown package: " + packageName); + return; } final BasePermission bp; synchronized (mLock) { @@ -1357,7 +1358,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null || pkg.mExtras == null) { - throw new IllegalArgumentException("Unknown package: " + packageName); + Log.e(TAG, "Unknown package: " + packageName); + return; } if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { throw new IllegalArgumentException("Unknown package: " + packageName); @@ -3928,7 +3930,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Invalid userId " + userId); } if (checkShell) { - PackageManagerServiceUtils.enforceShellRestriction( + PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt, UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId); } if (!requirePermissionWhenSameUser && userId == UserHandle.getUserId(callingUid)) return; diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index 56d839633ab5..4e9b724f528d 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -161,7 +161,7 @@ public class AttentionDetector { context.getContentResolver().registerContentObserver(Settings.System.getUriFor( Settings.System.ADAPTIVE_SLEEP), - false, new ContentObserver(new Handler()) { + false, new ContentObserver(new Handler(context.getMainLooper())) { @Override public void onChange(boolean selfChange) { updateEnabledFromSettings(context); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index d599441b3ba1..e57f43685108 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2723,6 +2723,14 @@ public final class PowerManagerService extends SystemService return true; } } + + if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE + && mDisplayPowerRequest.dozeScreenState == Display.STATE_ON) { + // Although we are in DOZE and would normally allow the device to suspend, + // the doze service has explicitly requested the display to remain in the ON + // state which means we should hold the display suspend blocker. + return true; + } if (mScreenBrightnessBoostInProgress) { return true; } @@ -4854,7 +4862,8 @@ public final class PowerManagerService extends SystemService } } - private final class LocalService extends PowerManagerInternal { + @VisibleForTesting + final class LocalService extends PowerManagerInternal { @Override public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) { if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index 1552fd517d30..491c5ab2ac03 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -38,11 +38,13 @@ import android.os.ShellCallback; import android.os.ShellCommand; import android.os.Temperature; import android.util.ArrayMap; +import android.util.EventLog; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; +import com.android.server.EventLogTags; import com.android.server.FgThread; import com.android.server.SystemService; @@ -250,6 +252,8 @@ public class ThermalManagerService extends SystemService { } finally { mThermalEventListeners.finishBroadcast(); } + EventLog.writeEvent(EventLogTags.THERMAL_CHANGED, temperature.getName(), + temperature.getType(), temperature.getValue(), temperature.getStatus(), mStatus); } private void shutdownIfNeeded(Temperature temperature) { @@ -860,10 +864,10 @@ public class ThermalManagerService extends SystemService { mThermalHal11.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE); mThermalHal11.registerThermalCallback(mThermalCallback11); + Slog.i(TAG, "Thermal HAL 1.1 service connected, limited thermal functions " + + "due to legacy API."); } catch (NoSuchElementException | RemoteException e) { - Slog.e(TAG, - "Thermal HAL 1.1 service not connected, no thermal call back will be " - + "called."); + Slog.e(TAG, "Thermal HAL 1.1 service not connected."); mThermalHal11 = null; } return (mThermalHal11 != null); @@ -978,8 +982,9 @@ public class ThermalManagerService extends SystemService { mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE); mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false, 0 /* not used */); + Slog.i(TAG, "Thermal HAL 2.0 service connected."); } catch (NoSuchElementException | RemoteException e) { - Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1."); + Slog.e(TAG, "Thermal HAL 2.0 service not connected."); mThermalHal20 = null; } return (mThermalHal20 != null); diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index 1948b202fd63..bf8c042835dd 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -264,9 +264,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C //TODO gradually add more role migrations statements here for remaining roles // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders // for a given role before adding a migration statement for it here - maybeMigrateRole(RoleManager.ROLE_SMS, userId); maybeMigrateRole(RoleManager.ROLE_ASSISTANT, userId); + maybeMigrateRole(RoleManager.ROLE_BROWSER, userId); maybeMigrateRole(RoleManager.ROLE_DIALER, userId); + maybeMigrateRole(RoleManager.ROLE_SMS, userId); maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId); // Some package state has changed, so grant default roles again. diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index 6375b4851283..d33c10c99c08 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -121,8 +121,6 @@ public class RoleUserState { */ public int getVersion() { synchronized (mLock) { - throwIfDestroyedLocked(); - return mVersion; } } @@ -134,8 +132,6 @@ public class RoleUserState { */ public void setVersion(int version) { synchronized (mLock) { - throwIfDestroyedLocked(); - if (mVersion == version) { return; } @@ -163,8 +159,6 @@ public class RoleUserState { */ public void setPackagesHash(@Nullable String packagesHash) { synchronized (mLock) { - throwIfDestroyedLocked(); - if (Objects.equals(mPackagesHash, packagesHash)) { return; } @@ -182,8 +176,6 @@ public class RoleUserState { */ public boolean isRoleAvailable(@NonNull String roleName) { synchronized (mLock) { - throwIfDestroyedLocked(); - return mRoles.containsKey(roleName); } } @@ -198,8 +190,6 @@ public class RoleUserState { @Nullable public ArraySet<String> getRoleHolders(@NonNull String roleName) { synchronized (mLock) { - throwIfDestroyedLocked(); - ArraySet<String> packageNames = mRoles.get(roleName); if (packageNames == null) { return null; @@ -217,8 +207,6 @@ public class RoleUserState { */ public boolean addRoleName(@NonNull String roleName) { synchronized (mLock) { - throwIfDestroyedLocked(); - if (!mRoles.containsKey(roleName)) { mRoles.put(roleName, new ArraySet<>()); Slog.i(LOG_TAG, "Added new role: " + roleName); @@ -237,8 +225,6 @@ public class RoleUserState { */ public void setRoleNames(@NonNull List<String> roleNames) { synchronized (mLock) { - throwIfDestroyedLocked(); - boolean changed = false; for (int i = mRoles.size() - 1; i >= 0; i--) { @@ -279,8 +265,6 @@ public class RoleUserState { boolean changed; synchronized (mLock) { - throwIfDestroyedLocked(); - ArraySet<String> roleHolders = mRoles.get(roleName); if (roleHolders == null) { Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName @@ -312,8 +296,6 @@ public class RoleUserState { boolean changed; synchronized (mLock) { - throwIfDestroyedLocked(); - ArraySet<String> roleHolders = mRoles.get(roleName); if (roleHolders == null) { Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName @@ -338,14 +320,16 @@ public class RoleUserState { */ @NonNull public List<String> getHeldRoles(@NonNull String packageName) { - ArrayList<String> result = new ArrayList<>(); - int size = mRoles.size(); - for (int i = 0; i < size; i++) { - if (mRoles.valueAt(i).contains(packageName)) { - result.add(mRoles.keyAt(i)); + synchronized (mLock) { + List<String> roleNames = new ArrayList<>(); + int size = mRoles.size(); + for (int i = 0; i < size; i++) { + if (mRoles.valueAt(i).contains(packageName)) { + roleNames.add(mRoles.keyAt(i)); + } } + return roleNames; } - return result; } /** @@ -353,7 +337,9 @@ public class RoleUserState { */ @GuardedBy("mLock") private void scheduleWriteFileLocked() { - throwIfDestroyedLocked(); + if (mDestroyed) { + return; + } if (!mWriteScheduled) { mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile, @@ -537,8 +523,6 @@ public class RoleUserState { String packagesHash; ArrayMap<String, ArraySet<String>> roles; synchronized (mLock) { - throwIfDestroyedLocked(); - version = mVersion; packagesHash = mPackagesHash; roles = snapshotRolesLocked(); @@ -602,20 +586,15 @@ public class RoleUserState { */ public void destroy() { synchronized (mLock) { - throwIfDestroyedLocked(); + if (mDestroyed) { + throw new IllegalStateException("This RoleUserState has already been destroyed"); + } mWriteHandler.removeCallbacksAndMessages(null); getFile(mUserId).delete(); mDestroyed = true; } } - @GuardedBy("mLock") - private void throwIfDestroyedLocked() { - if (mDestroyed) { - throw new IllegalStateException("This RoleUserState has already been destroyed"); - } - } - @NonNull private static File getFile(@UserIdInt int userId) { return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 828f79007b95..d67048fe548d 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -841,7 +841,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void setImeWindowStatus(int displayId, final IBinder token, final int vis, - final int backDisposition, final boolean showImeSwitcher) { + final int backDisposition, final boolean showImeSwitcher, + boolean isMultiClientImeEnabled) { enforceStatusBar(); if (SPEW) { @@ -858,7 +859,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D if (mBar == null) return; try { mBar.setImeWindowStatus( - displayId, token, vis, backDisposition, showImeSwitcher); + displayId, token, vis, backDisposition, showImeSwitcher, + isMultiClientImeEnabled); } catch (RemoteException ex) { } }); } diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index ab3d7b7f763c..89a530514263 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -457,12 +457,12 @@ public final class TextClassificationManagerService extends ITextClassifierServi Preconditions.checkArgument(userId != UserHandle.USER_NULL, "Null userId"); final int callingUserId = UserHandle.getCallingUserId(); if (callingUserId != userId) { - context.enforceCallingPermission( + context.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Invalid userId. UserId=" + userId + ", CallingUserId=" + callingUserId); } } catch (Exception e) { - throw new RemoteException("Invalid request", e, + throw new RemoteException("Invalid request: " + e.getMessage(), e, /* enableSuppression */ true, /* writableStackTrace */ true); } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index b351faf7e9f1..a3ab27e4f06b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -84,7 +84,6 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PRE import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE; -import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; @@ -226,7 +225,6 @@ import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; import android.view.WindowManager; -import android.view.inputmethod.InputMethodSystemProperty; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -263,6 +261,7 @@ import com.android.server.am.PendingIntentRecord; import com.android.server.am.UserState; import com.android.server.appop.AppOpsService; import com.android.server.firewall.IntentFirewall; +import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.pm.UserManagerService; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.uri.UriGrantsManagerInternal; @@ -1459,16 +1458,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Nullable IRecentsAnimationRunner recentsAnimationRunner) { enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()"); final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { final ComponentName recentsComponent = mRecentTasks.getRecentsComponent(); final int recentsUid = mRecentTasks.getRecentsComponentUid(); + final WindowProcessController caller = getProcessController(callingPid, callingUid); // Start a new recents animation final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor, getActivityStartController(), mWindowManager, intent, recentsComponent, - recentsUid, callingPid); + recentsUid, caller); if (recentsAnimationRunner == null) { anim.preloadRecentsActivity(); } else { @@ -1618,8 +1619,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Explicitly dismissing the activity so reset its relaunch flag. r.mRelaunchReason = RELAUNCH_REASON_NONE; } else { - res = r.finishActivityLocked(resultCode, resultData, "app-request", - true /* oomAdj */) != FINISH_RESULT_CANCELLED; + r.finishActivityLocked(resultCode, resultData, "app-request", + true /* oomAdj */); + res = r.finishing; if (!res) { Slog.i(TAG, "Failed to finish by app-request"); } @@ -4581,7 +4583,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) { mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimations"); - definition.setCallingPid(Binder.getCallingPid()); + definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); synchronized (mGlobalLock) { final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r == null) { @@ -4601,7 +4603,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { RemoteAnimationAdapter adapter) { mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimationForNextActivityStart"); - adapter.setCallingPid(Binder.getCallingPid()); + adapter.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); synchronized (mGlobalLock) { final long origId = Binder.clearCallingIdentity(); try { @@ -4618,7 +4620,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { RemoteAnimationDefinition definition) { mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimations"); - definition.setCallingPid(Binder.getCallingPid()); + definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); synchronized (mGlobalLock) { final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId); if (display == null) { @@ -6487,6 +6489,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } return; } + process.mIsImeProcess = true; process.registerDisplayConfigurationListenerLocked(activityDisplay); } } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index aefc152cb286..7fde6dee63e3 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -207,6 +207,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree boolean removed; // Information about an application starting window if displayed. + // Note: these are de-referenced before the starting window animates away. StartingData mStartingData; WindowState startingWindow; StartingSurface startingSurface; @@ -1249,6 +1250,21 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return true; } + /** + * @return {@code true} if starting window is in app's hierarchy. + */ + boolean hasStartingWindow() { + if (startingDisplayed || mStartingData != null) { + return true; + } + for (int i = mChildren.size() - 1; i >= 0; i--) { + if (getChildAt(i).mAttrs.type == TYPE_APPLICATION_STARTING) { + return true; + } + } + return false; + } + @Override void addWindow(WindowState w) { super.addWindow(w); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index faf75b6630ca..c8e806ed6f0d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -67,6 +67,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; @@ -136,6 +137,8 @@ import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREEN import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION; import static com.android.server.wm.WindowManagerService.dipToPixel; import static com.android.server.wm.WindowManagerService.logSurface; +import static com.android.server.wm.WindowState.EXCLUSION_LEFT; +import static com.android.server.wm.WindowState.EXCLUSION_RIGHT; import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; @@ -328,6 +331,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private final RemoteCallbackList<ISystemGestureExclusionListener> mSystemGestureExclusionListeners = new RemoteCallbackList<>(); private final Region mSystemGestureExclusion = new Region(); + private boolean mSystemGestureExclusionWasRestricted = false; + private final Region mSystemGestureExclusionUnrestricted = new Region(); private int mSystemGestureExclusionLimit; /** @@ -4871,9 +4876,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // // In the case where we have no IME target we assign it where it's base layer would // place it in the AboveAppWindowContainers. - if (imeTarget != null && !(imeTarget.inSplitScreenWindowingMode() - || imeTarget.mToken.isAppAnimating()) - && (imeTarget.getSurfaceControl() != null)) { + // + // Keep IME window in mAboveAppWindowsContainers as long as app's starting window exists + // so it get's layered above the starting window. + if (imeTarget != null + && !(imeTarget.mAppToken != null && imeTarget.mAppToken.hasStartingWindow()) + && (!(imeTarget.inSplitScreenWindowingMode() || imeTarget.mToken.isAppAnimating()) + && (imeTarget.getSurfaceControl() != null))) { mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(), // TODO: We need to use an extra level on the app surface to ensure // this is always above SurfaceView but always below attached window. @@ -5161,16 +5170,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return false; } - final Region systemGestureExclusion = calculateSystemGestureExclusion(); + final Region systemGestureExclusion = Region.obtain(); + mSystemGestureExclusionWasRestricted = calculateSystemGestureExclusion( + systemGestureExclusion, mSystemGestureExclusionUnrestricted); try { if (mSystemGestureExclusion.equals(systemGestureExclusion)) { return false; } mSystemGestureExclusion.set(systemGestureExclusion); + final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted + ? mSystemGestureExclusionUnrestricted : null; for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) { try { mSystemGestureExclusionListeners.getBroadcastItem(i) - .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion); + .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion, + unrestrictedOrNull); } catch (RemoteException e) { Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e); } @@ -5182,8 +5196,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + /** + * Calculates the system gesture exclusion. + * + * @param outExclusion will be set to the gesture exclusion region + * @param outExclusionUnrestricted will be set to the gesture exclusion region without + * any restrictions applied. + * @return whether any restrictions were applied, i.e. outExclusion and outExclusionUnrestricted + * differ. + */ @VisibleForTesting - Region calculateSystemGestureExclusion() { + boolean calculateSystemGestureExclusion(Region outExclusion, @Nullable + Region outExclusionUnrestricted) { + outExclusion.setEmpty(); + if (outExclusionUnrestricted != null) { + outExclusionUnrestricted.setEmpty(); + } final Region unhandled = Region.obtain(); unhandled.set(0, 0, mDisplayFrames.mDisplayWidth, mDisplayFrames.mDisplayHeight); @@ -5192,7 +5220,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final Rect rightEdge = mInsetsStateController.getSourceProvider(TYPE_RIGHT_GESTURES) .getSource().getFrame(); - final Region global = Region.obtain(); final Region touchableRegion = Region.obtain(); final Region local = Region.obtain(); final int[] remainingLeftRight = @@ -5230,28 +5257,39 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) { // Processes the region along the left edge. - remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, global, leftEdge, - remainingLeftRight[0]); + remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, outExclusion, leftEdge, + remainingLeftRight[0], w, EXCLUSION_LEFT); // Processes the region along the right edge. - remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, global, rightEdge, - remainingLeftRight[1]); + remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, outExclusion, rightEdge, + remainingLeftRight[1], w, EXCLUSION_RIGHT); // Adds the middle (unrestricted area) final Region middle = Region.obtain(local); middle.op(leftEdge, Op.DIFFERENCE); middle.op(rightEdge, Op.DIFFERENCE); - global.op(middle, Op.UNION); + outExclusion.op(middle, Op.UNION); middle.recycle(); } else { - global.op(local, Op.UNION); + boolean loggable = needsGestureExclusionRestrictions(w, 0 /* lastSysUiVis */); + if (loggable) { + addToGlobalAndConsumeLimit(local, outExclusion, leftEdge, + Integer.MAX_VALUE, w, EXCLUSION_LEFT); + addToGlobalAndConsumeLimit(local, outExclusion, rightEdge, + Integer.MAX_VALUE, w, EXCLUSION_RIGHT); + } + outExclusion.op(local, Op.UNION); + } + if (outExclusionUnrestricted != null) { + outExclusionUnrestricted.op(local, Op.UNION); } unhandled.op(touchableRegion, Op.DIFFERENCE); }, true /* topToBottom */); local.recycle(); touchableRegion.recycle(); unhandled.recycle(); - return global; + return remainingLeftRight[0] < mSystemGestureExclusionLimit + || remainingLeftRight[1] < mSystemGestureExclusionLimit; } /** @@ -5269,31 +5307,57 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } /** + * @return Whether gesture exclusion area should be logged for the given window + */ + static boolean logsGestureExclusionRestrictions(WindowState win) { + if (win.mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis <= 0) { + return false; + } + final WindowManager.LayoutParams attrs = win.getAttrs(); + final int type = attrs.type; + return type != TYPE_WALLPAPER + && type != TYPE_APPLICATION_STARTING + && type != TYPE_NAVIGATION_BAR + && (attrs.flags & FLAG_NOT_TOUCHABLE) == 0 + && needsGestureExclusionRestrictions(win, 0 /* sysUiVisibility */) + && win.getDisplayContent().mDisplayPolicy.hasSideGestures(); + } + + /** * Adds a local gesture exclusion area to the global area while applying a limit per edge. * * @param local The gesture exclusion area to add. * @param global The destination. * @param edge Only processes the part in that region. * @param limit How much limit in pixels we have. - * @return How much of the limit are remaining. + * @param win The WindowState that is being processed + * @param side The side that is being processed, either {@link WindowState#EXCLUSION_LEFT} or + * {@link WindowState#EXCLUSION_RIGHT} + * @return How much of the limit is remaining. */ private static int addToGlobalAndConsumeLimit(Region local, Region global, Rect edge, - int limit) { + int limit, WindowState win, int side) { final Region r = Region.obtain(local); r.op(edge, Op.INTERSECT); final int[] remaining = {limit}; + final int[] requestedExclusion = {0}; forEachRectReverse(r, rect -> { if (remaining[0] <= 0) { return; } final int height = rect.height(); + requestedExclusion[0] += height; if (height > remaining[0]) { rect.top = rect.bottom - remaining[0]; } remaining[0] -= height; global.op(rect, Op.UNION); }); + + final int grantedExclusion = limit - remaining[0]; + win.setLastExclusionHeights(side, requestedExclusion[0], grantedExclusion); + r.recycle(); return remaining[0]; } @@ -5308,10 +5372,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } if (!changed) { + final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted + ? mSystemGestureExclusionUnrestricted : null; // If updateSystemGestureExclusion changed the exclusion, it will already have // notified the listener. Otherwise, we'll do it here. try { - listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion); + listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion, + unrestrictedOrNull); } catch (RemoteException e) { Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 15768738c85c..a4476f02882a 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -480,9 +480,10 @@ public class DisplayPolicy { @Override public void onSwipeFromRight() { - final Region excludedRegion; + final Region excludedRegion = Region.obtain(); synchronized (mLock) { - excludedRegion = mDisplayContent.calculateSystemGestureExclusion(); + mDisplayContent.calculateSystemGestureExclusion( + excludedRegion, null /* outUnrestricted */); } final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture || mNavigationBarPosition == NAV_BAR_RIGHT; @@ -490,13 +491,15 @@ public class DisplayPolicy { && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) { requestTransientBars(mNavigationBar); } + excludedRegion.recycle(); } @Override public void onSwipeFromLeft() { - final Region excludedRegion; + final Region excludedRegion = Region.obtain(); synchronized (mLock) { - excludedRegion = mDisplayContent.calculateSystemGestureExclusion(); + mDisplayContent.calculateSystemGestureExclusion( + excludedRegion, null /* outUnrestricted */); } final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture || mNavigationBarPosition == NAV_BAR_LEFT; @@ -504,6 +507,7 @@ public class DisplayPolicy { && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) { requestTransientBars(mNavigationBar); } + excludedRegion.recycle(); } @Override @@ -676,6 +680,10 @@ public class DisplayPolicy { return mHasStatusBar; } + boolean hasSideGestures() { + return mHasNavigationBar && mSideGestureInset > 0; + } + public boolean navigationBarCanMove() { return mNavigationBarCanMove; } diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 553b0ffa6999..c8f7af5b10c8 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -147,12 +147,6 @@ class DragState { return mIsClosing; } - private void hideInputSurface() { - if (mInputSurface != null) { - mTransaction.hide(mInputSurface).apply(); - } - } - private void showInputSurface() { if (mInputSurface == null) { mInputSurface = mService.makeSurfaceBuilder( @@ -198,8 +192,6 @@ class DragState { mInputInterceptor = null; } - hideInputSurface(); - // Send drag end broadcast if drag start has been sent. if (mDragInProgress) { final int myPid = Process.myPid(); @@ -239,6 +231,10 @@ class DragState { } // Clear the internal variables. + if (mInputSurface != null) { + mTransaction.remove(mInputSurface).apply(); + mInputSurface = null; + } if (mSurfaceControl != null) { mTransaction.reparent(mSurfaceControl, null).apply(); mSurfaceControl = null; diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 541a8bbc8865..fb6b5da87f2d 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -126,6 +126,7 @@ class RecentTasks { // iterating through the recents list private static final ActivityInfo NO_ACTIVITY_INFO_TOKEN = new ActivityInfo(); private static final ApplicationInfo NO_APPLICATION_INFO_TOKEN = new ApplicationInfo(); + private TaskChangeNotificationController mTaskNotificationController; /** * Callbacks made when manipulating the list. @@ -228,6 +229,7 @@ class RecentTasks { mTaskPersister = taskPersister; mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic(); mHasVisibleRecentTasks = true; + mTaskNotificationController = service.getTaskChangeNotificationController(); } RecentTasks(ActivityTaskManagerService service, ActivityStackSupervisor stackSupervisor) { @@ -238,6 +240,7 @@ class RecentTasks { mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this, stackSupervisor.mPersisterQueue); mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic(); + mTaskNotificationController = service.getTaskChangeNotificationController(); mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents); loadParametersFromResources(res); } @@ -298,7 +301,7 @@ class RecentTasks { // Resume trimming tasks trimInactiveRecentTasks(); - mService.getTaskChangeNotificationController().notifyTaskStackChanged(); + mTaskNotificationController.notifyTaskStackChanged(); } /** @@ -427,12 +430,14 @@ class RecentTasks { for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onRecentTaskAdded(task); } + mTaskNotificationController.notifyTaskListUpdated(); } private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) { for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess); } + mTaskNotificationController.notifyTaskListUpdated(); } /** diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 0a3e7a4860d5..036bef755a87 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -33,6 +33,7 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_O import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; +import android.annotation.Nullable; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Intent; @@ -60,7 +61,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, private final Intent mTargetIntent; private final ComponentName mRecentsComponent; private final int mRecentsUid; - private final int mCallingPid; + private final @Nullable WindowProcessController mCaller; private final int mUserId; private final int mTargetActivityType; @@ -76,7 +77,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor, ActivityStartController activityStartController, WindowManagerService wm, - Intent targetIntent, ComponentName recentsComponent, int recentsUid, int callingPid) { + Intent targetIntent, ComponentName recentsComponent, int recentsUid, + @Nullable WindowProcessController caller) { mService = atm; mStackSupervisor = stackSupervisor; mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay(); @@ -85,7 +87,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mTargetIntent = targetIntent; mRecentsComponent = recentsComponent; mRecentsUid = recentsUid; - mCallingPid = callingPid; + mCaller = caller; mUserId = atm.getCurrentUserId(); mTargetActivityType = targetIntent.getComponent() != null && recentsComponent.equals(targetIntent.getComponent()) @@ -190,7 +192,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent); - mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true)); + if (mCaller != null) { + mCaller.setRunningRecentsAnimation(true); + } mWindowManager.deferSurfaceLayout(); try { @@ -286,8 +290,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mService.stopAppSwitches(); } - mService.mH.post( - () -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false)); + if (mCaller != null) { + mCaller.setRunningRecentsAnimation(false); + } mWindowManager.inSurfaceTransaction(() -> { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, @@ -453,7 +458,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, /** * Called only when the animation should be canceled prior to starting. */ - private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) { + static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) { try { recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index b4bfedda94c7..a1bc406c4550 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -129,7 +129,7 @@ class RemoteAnimationController implements DeathRecipient { writeStartDebugStatement(); } }); - sendRunningRemoteAnimation(true); + setRunningRemoteAnimation(true); } void cancelAnimation(String reason) { @@ -216,7 +216,7 @@ class RemoteAnimationController implements DeathRecipient { mService.closeSurfaceTransaction("RemoteAnimationController#finished"); } } - sendRunningRemoteAnimation(false); + setRunningRemoteAnimation(false); if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation"); } @@ -235,12 +235,18 @@ class RemoteAnimationController implements DeathRecipient { } } - private void sendRunningRemoteAnimation(boolean running) { + private void setRunningRemoteAnimation(boolean running) { final int pid = mRemoteAnimationAdapter.getCallingPid(); + final int uid = mRemoteAnimationAdapter.getCallingUid(); if (pid == 0) { throw new RuntimeException("Calling pid of remote animation was null"); } - mService.sendSetRunningRemoteAnimation(pid, running); + final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid); + if (wpc == null) { + Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid); + return; + } + wpc.setRunningRemoteAnimation(running); } private void linkToDeathOfRunner() throws RemoteException { @@ -417,7 +423,7 @@ class RemoteAnimationController implements DeathRecipient { mHandler.removeCallbacks(mTimeoutRunnable); releaseFinishedCallback(); invokeAnimationCancelled(); - sendRunningRemoteAnimation(false); + setRunningRemoteAnimation(false); } } diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index ac9028329023..a7b53688dbdc 100644 --- a/services/core/java/com/android/server/wm/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -122,17 +122,20 @@ public class SafeActivityOptions { if (mOriginalOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, mOriginalCallingPid, mOriginalCallingUid); - setCallingPidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid); + setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid, + mOriginalCallingUid); } if (mCallerOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, mRealCallingPid, mRealCallingUid); - setCallingPidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid); + setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid, + mRealCallingUid); } return mergeActivityOptions(mOriginalOptions, mCallerOptions); } - private void setCallingPidForRemoteAnimationAdapter(ActivityOptions options, int callingPid) { + private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options, + int callingPid, int callingUid) { final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); if (adapter == null) { return; @@ -141,7 +144,7 @@ public class SafeActivityOptions { Slog.wtf(TAG, "Safe activity options constructed after clearing calling id"); return; } - adapter.setCallingPid(callingPid); + adapter.setCallingPidUid(callingPid, callingUid); } /** diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index b94a7dc781e8..cb15f579908b 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -42,184 +42,54 @@ import android.view.animation.Transformation; import java.io.PrintWriter; class ScreenRotationAnimation { - static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM; - static final boolean DEBUG_STATE = false; - static final boolean DEBUG_TRANSFORMS = false; - static final boolean TWO_PHASE_ANIMATION = false; - static final boolean USE_CUSTOM_BLACK_FRAME = false; + private static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM; /* * Layers for screen rotation animation. We put these layers above * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows. */ - static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER; - static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE; - static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1; - static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2; - static final int SCREEN_FREEZE_LAYER_CUSTOM = SCREEN_FREEZE_LAYER_BASE + 3; - - final Context mContext; - final DisplayContent mDisplayContent; - SurfaceControl mSurfaceControl; - BlackFrame mCustomBlackFrame; - BlackFrame mExitingBlackFrame; - BlackFrame mEnteringBlackFrame; - int mWidth, mHeight; - - int mOriginalRotation; - int mOriginalWidth, mOriginalHeight; - int mCurRotation; - Rect mOriginalDisplayRect = new Rect(); - Rect mCurrentDisplayRect = new Rect(); - - // For all animations, "exit" is for the UI elements that are going - // away (that is the snapshot of the old screen), and "enter" is for - // the new UI elements that are appearing (that is the active windows - // in their final orientation). - - // The starting animation for the exiting and entering elements. This - // animation applies a transformation while the rotation is in progress. - // It is started immediately, before the new entering UI is ready. - Animation mStartExitAnimation; - final Transformation mStartExitTransformation = new Transformation(); - Animation mStartEnterAnimation; - final Transformation mStartEnterTransformation = new Transformation(); - Animation mStartFrameAnimation; - final Transformation mStartFrameTransformation = new Transformation(); - - // The finishing animation for the exiting and entering elements. This - // animation needs to undo the transformation of the starting animation. - // It starts running once the new rotation UI elements are ready to be - // displayed. - Animation mFinishExitAnimation; - final Transformation mFinishExitTransformation = new Transformation(); - Animation mFinishEnterAnimation; - final Transformation mFinishEnterTransformation = new Transformation(); - Animation mFinishFrameAnimation; - final Transformation mFinishFrameTransformation = new Transformation(); + private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER; + private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE; + private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1; + private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2; + + private final Context mContext; + private final DisplayContent mDisplayContent; + private final float[] mTmpFloats = new float[9]; + private final Transformation mRotateExitTransformation = new Transformation(); + private final Transformation mRotateEnterTransformation = new Transformation(); + // Complete transformations being applied. + private final Transformation mExitTransformation = new Transformation(); + private final Transformation mEnterTransformation = new Transformation(); + private final Matrix mFrameInitialMatrix = new Matrix(); + private final Matrix mSnapshotInitialMatrix = new Matrix(); + private final Matrix mSnapshotFinalMatrix = new Matrix(); + private final Matrix mExitFrameFinalMatrix = new Matrix(); + private final WindowManagerService mService; + private SurfaceControl mSurfaceControl; + private BlackFrame mEnteringBlackFrame; + private int mWidth, mHeight; + + private int mOriginalRotation; + private int mOriginalWidth, mOriginalHeight; + private int mCurRotation; + private Rect mOriginalDisplayRect = new Rect(); + private Rect mCurrentDisplayRect = new Rect(); // The current active animation to move from the old to the new rotated // state. Which animation is run here will depend on the old and new // rotations. - Animation mRotateExitAnimation; - final Transformation mRotateExitTransformation = new Transformation(); - Animation mRotateEnterAnimation; - final Transformation mRotateEnterTransformation = new Transformation(); - Animation mRotateFrameAnimation; - final Transformation mRotateFrameTransformation = new Transformation(); - - // A previously running rotate animation. This will be used if we need - // to switch to a new rotation before finishing the previous one. - Animation mLastRotateExitAnimation; - final Transformation mLastRotateExitTransformation = new Transformation(); - Animation mLastRotateEnterAnimation; - final Transformation mLastRotateEnterTransformation = new Transformation(); - Animation mLastRotateFrameAnimation; - final Transformation mLastRotateFrameTransformation = new Transformation(); - - // Complete transformations being applied. - final Transformation mExitTransformation = new Transformation(); - final Transformation mEnterTransformation = new Transformation(); - final Transformation mFrameTransformation = new Transformation(); - - boolean mStarted; - boolean mAnimRunning; - boolean mFinishAnimReady; - long mFinishAnimStartTime; - boolean mForceDefaultOrientation; - - final Matrix mFrameInitialMatrix = new Matrix(); - final Matrix mSnapshotInitialMatrix = new Matrix(); - final Matrix mSnapshotFinalMatrix = new Matrix(); - final Matrix mExitFrameFinalMatrix = new Matrix(); - final Matrix mTmpMatrix = new Matrix(); - final float[] mTmpFloats = new float[9]; + private Animation mRotateExitAnimation; + private Animation mRotateEnterAnimation; + private boolean mStarted; + private boolean mAnimRunning; + private boolean mFinishAnimReady; + private long mFinishAnimStartTime; + private boolean mForceDefaultOrientation; + private BlackFrame mExitingBlackFrame; private boolean mMoreRotateEnter; private boolean mMoreRotateExit; - private boolean mMoreRotateFrame; - private boolean mMoreFinishEnter; - private boolean mMoreFinishExit; - private boolean mMoreFinishFrame; - private boolean mMoreStartEnter; - private boolean mMoreStartExit; - private boolean mMoreStartFrame; - long mHalfwayPoint; - - private final WindowManagerService mService; - - public void printTo(String prefix, PrintWriter pw) { - pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl); - pw.print(" mWidth="); pw.print(mWidth); - pw.print(" mHeight="); pw.println(mHeight); - if (USE_CUSTOM_BLACK_FRAME) { - pw.print(prefix); pw.print("mCustomBlackFrame="); pw.println(mCustomBlackFrame); - if (mCustomBlackFrame != null) { - mCustomBlackFrame.printTo(prefix + " ", pw); - } - } - pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame); - if (mExitingBlackFrame != null) { - mExitingBlackFrame.printTo(prefix + " ", pw); - } - pw.print(prefix); pw.print("mEnteringBlackFrame="); pw.println(mEnteringBlackFrame); - if (mEnteringBlackFrame != null) { - mEnteringBlackFrame.printTo(prefix + " ", pw); - } - pw.print(prefix); pw.print("mCurRotation="); pw.print(mCurRotation); - pw.print(" mOriginalRotation="); pw.println(mOriginalRotation); - pw.print(prefix); pw.print("mOriginalWidth="); pw.print(mOriginalWidth); - pw.print(" mOriginalHeight="); pw.println(mOriginalHeight); - pw.print(prefix); pw.print("mStarted="); pw.print(mStarted); - pw.print(" mAnimRunning="); pw.print(mAnimRunning); - pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady); - pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime); - pw.print(prefix); pw.print("mStartExitAnimation="); pw.print(mStartExitAnimation); - pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation); - pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mStartFrameAnimation="); pw.print(mStartFrameAnimation); - pw.print(" "); mStartFrameTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation); - pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation); - pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mFinishFrameAnimation="); pw.print(mFinishFrameAnimation); - pw.print(" "); mFinishFrameTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation); - pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation); - pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mRotateFrameAnimation="); pw.print(mRotateFrameAnimation); - pw.print(" "); mRotateFrameTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mExitTransformation="); - mExitTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mEnterTransformation="); - mEnterTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mFrameTransformation="); - mFrameTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mFrameInitialMatrix="); - mFrameInitialMatrix.printShortString(pw); - pw.println(); - pw.print(prefix); pw.print("mSnapshotInitialMatrix="); - mSnapshotInitialMatrix.printShortString(pw); - pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw); - pw.println(); - pw.print(prefix); pw.print("mExitFrameFinalMatrix="); - mExitFrameFinalMatrix.printShortString(pw); - pw.println(); - pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation); - if (mForceDefaultOrientation) { - pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString()); - pw.print(" mCurrentDisplayRect="); pw.println(mCurrentDisplayRect.toShortString()); - } - } - - public void writeToProto(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - proto.write(STARTED, mStarted); - proto.write(ANIMATION_RUNNING, mAnimRunning); - proto.end(token); - } + private long mHalfwayPoint; public ScreenRotationAnimation(Context context, DisplayContent displayContent, boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) { @@ -276,7 +146,7 @@ class ScreenRotationAnimation { final Surface surface = mService.mSurfaceFactory.make(); surface.copyFrom(mSurfaceControl); SurfaceControl.ScreenshotGraphicBuffer gb = - mService.mDisplayManagerInternal.screenshot(displayId); + mService.mDisplayManagerInternal.screenshot(displayId); if (gb != null) { try { surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(), @@ -301,12 +171,42 @@ class ScreenRotationAnimation { Slog.w(TAG, "Unable to allocate freeze surface", e); } - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, - " FREEZE " + mSurfaceControl + ": CREATE"); + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { + Slog.i(TAG_WM, + " FREEZE " + mSurfaceControl + ": CREATE"); + } setRotation(t, originalRotation); t.apply(); } + private static void createRotationMatrix(int rotation, int width, int height, + Matrix outMatrix) { + switch (rotation) { + case Surface.ROTATION_0: + outMatrix.reset(); + break; + case Surface.ROTATION_90: + outMatrix.setRotate(90, 0, 0); + outMatrix.postTranslate(height, 0); + break; + case Surface.ROTATION_180: + outMatrix.setRotate(180, 0, 0); + outMatrix.postTranslate(width, height); + break; + case Surface.ROTATION_270: + outMatrix.setRotate(270, 0, 0); + outMatrix.postTranslate(0, width); + break; + } + } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(STARTED, mStarted); + proto.write(ANIMATION_RUNNING, mAnimRunning); + proto.end(token); + } + boolean hasScreenshot() { return mSurfaceControl != null; } @@ -326,40 +226,55 @@ class ScreenRotationAnimation { mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); t.setAlpha(mSurfaceControl, alpha); - if (DEBUG_TRANSFORMS) { - float[] srcPnts = new float[] { 0, 0, mWidth, mHeight }; - float[] dstPnts = new float[4]; - matrix.mapPoints(dstPnts, srcPnts); - Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1] - + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")"); - Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1] - + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")"); - } } } - public static void createRotationMatrix(int rotation, int width, int height, - Matrix outMatrix) { - switch (rotation) { - case Surface.ROTATION_0: - outMatrix.reset(); - break; - case Surface.ROTATION_90: - outMatrix.setRotate(90, 0, 0); - outMatrix.postTranslate(height, 0); - break; - case Surface.ROTATION_180: - outMatrix.setRotate(180, 0, 0); - outMatrix.postTranslate(width, height); - break; - case Surface.ROTATION_270: - outMatrix.setRotate(270, 0, 0); - outMatrix.postTranslate(0, width); - break; + public void printTo(String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl); + pw.print(" mWidth="); pw.print(mWidth); + pw.print(" mHeight="); pw.println(mHeight); + pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame); + if (mExitingBlackFrame != null) { + mExitingBlackFrame.printTo(prefix + " ", pw); + } + pw.print(prefix); pw.print("mEnteringBlackFrame="); pw.println(mEnteringBlackFrame); + if (mEnteringBlackFrame != null) { + mEnteringBlackFrame.printTo(prefix + " ", pw); + } + pw.print(prefix); pw.print("mCurRotation="); pw.print(mCurRotation); + pw.print(" mOriginalRotation="); pw.println(mOriginalRotation); + pw.print(prefix); pw.print("mOriginalWidth="); pw.print(mOriginalWidth); + pw.print(" mOriginalHeight="); pw.println(mOriginalHeight); + pw.print(prefix); pw.print("mStarted="); pw.print(mStarted); + pw.print(" mAnimRunning="); pw.print(mAnimRunning); + pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady); + pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime); + pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation); + pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation); + pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mExitTransformation="); + mExitTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mEnterTransformation="); + mEnterTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mFrameInitialMatrix="); + mFrameInitialMatrix.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mSnapshotInitialMatrix="); + mSnapshotInitialMatrix.printShortString(pw); + pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mExitFrameFinalMatrix="); + mExitFrameFinalMatrix.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation); + if (mForceDefaultOrientation) { + pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString()); + pw.print(" mCurrentDisplayRect="); pw.println(mCurrentDisplayRect.toShortString()); } } - private void setRotation(SurfaceControl.Transaction t, int rotation) { + public void setRotation(SurfaceControl.Transaction t, int rotation) { mCurRotation = rotation; // Compute the transformation matrix that must be applied @@ -368,17 +283,12 @@ class ScreenRotationAnimation { int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0); createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); - if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta); setSnapshotTransform(t, mSnapshotInitialMatrix, 1.0f); } public boolean setRotation(SurfaceControl.Transaction t, int rotation, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) { setRotation(t, rotation); - if (TWO_PHASE_ANIMATION) { - return startAnimation(t, maxAnimationDuration, animationScale, - finalWidth, finalHeight, false, 0, 0); - } // Don't start animation yet. return false; @@ -400,37 +310,9 @@ class ScreenRotationAnimation { mStarted = true; - boolean firstStart = false; - // Figure out how the screen has moved from the original rotation. int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation); - if (TWO_PHASE_ANIMATION && mFinishExitAnimation == null - && (!dismissing || delta != Surface.ROTATION_0)) { - if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations"); - firstStart = true; - mStartExitAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_start_exit); - mStartEnterAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_start_enter); - if (USE_CUSTOM_BLACK_FRAME) { - mStartFrameAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_start_frame); - } - mFinishExitAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_finish_exit); - mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_finish_enter); - if (USE_CUSTOM_BLACK_FRAME) { - mFinishFrameAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_finish_frame); - } - } - - if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth=" - + finalWidth + " finalHeight=" + finalHeight - + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight); - final boolean customAnim; if (exitAnim != 0 && enterAnim != 0) { customAnim = true; @@ -444,40 +326,24 @@ class ScreenRotationAnimation { com.android.internal.R.anim.screen_rotate_0_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_0_enter); - if (USE_CUSTOM_BLACK_FRAME) { - mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_0_frame); - } break; case Surface.ROTATION_90: mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_plus_90_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_plus_90_enter); - if (USE_CUSTOM_BLACK_FRAME) { - mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_plus_90_frame); - } break; case Surface.ROTATION_180: mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_180_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_180_enter); - if (USE_CUSTOM_BLACK_FRAME) { - mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_180_frame); - } break; case Surface.ROTATION_270: mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_minus_90_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_minus_90_enter); - if (USE_CUSTOM_BLACK_FRAME) { - mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.screen_rotate_minus_90_frame); - } break; } } @@ -486,85 +352,16 @@ class ScreenRotationAnimation { // means to allow supplying the last and next size. In this definition // "%p" is the original (let's call it "previous") size, and "%" is the // screen's current/new size. - if (TWO_PHASE_ANIMATION && firstStart) { - // Compute partial steps between original and final sizes. These - // are used for the dimensions of the exiting and entering elements, - // so they are never stretched too significantly. - final int halfWidth = (finalWidth + mOriginalWidth) / 2; - final int halfHeight = (finalHeight + mOriginalHeight) / 2; - - if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations"); - mStartEnterAnimation.initialize(finalWidth, finalHeight, - halfWidth, halfHeight); - mStartExitAnimation.initialize(halfWidth, halfHeight, - mOriginalWidth, mOriginalHeight); - mFinishEnterAnimation.initialize(finalWidth, finalHeight, - halfWidth, halfHeight); - mFinishExitAnimation.initialize(halfWidth, halfHeight, - mOriginalWidth, mOriginalHeight); - if (USE_CUSTOM_BLACK_FRAME) { - mStartFrameAnimation.initialize(finalWidth, finalHeight, - mOriginalWidth, mOriginalHeight); - mFinishFrameAnimation.initialize(finalWidth, finalHeight, - mOriginalWidth, mOriginalHeight); - } - } mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); - if (USE_CUSTOM_BLACK_FRAME) { - mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, - mOriginalHeight); - } mAnimRunning = false; mFinishAnimReady = false; mFinishAnimStartTime = -1; - if (TWO_PHASE_ANIMATION && firstStart) { - mStartExitAnimation.restrictDuration(maxAnimationDuration); - mStartExitAnimation.scaleCurrentDuration(animationScale); - mStartEnterAnimation.restrictDuration(maxAnimationDuration); - mStartEnterAnimation.scaleCurrentDuration(animationScale); - mFinishExitAnimation.restrictDuration(maxAnimationDuration); - mFinishExitAnimation.scaleCurrentDuration(animationScale); - mFinishEnterAnimation.restrictDuration(maxAnimationDuration); - mFinishEnterAnimation.scaleCurrentDuration(animationScale); - if (USE_CUSTOM_BLACK_FRAME) { - mStartFrameAnimation.restrictDuration(maxAnimationDuration); - mStartFrameAnimation.scaleCurrentDuration(animationScale); - mFinishFrameAnimation.restrictDuration(maxAnimationDuration); - mFinishFrameAnimation.scaleCurrentDuration(animationScale); - } - } mRotateExitAnimation.restrictDuration(maxAnimationDuration); mRotateExitAnimation.scaleCurrentDuration(animationScale); mRotateEnterAnimation.restrictDuration(maxAnimationDuration); mRotateEnterAnimation.scaleCurrentDuration(animationScale); - if (USE_CUSTOM_BLACK_FRAME) { - mRotateFrameAnimation.restrictDuration(maxAnimationDuration); - mRotateFrameAnimation.scaleCurrentDuration(animationScale); - } - - final int layerStack = mDisplayContent.getDisplay().getLayerStack(); - if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) { - // Compute the transformation matrix that must be applied - // the the black frame to make it stay in the initial position - // before the new screen rotation. This is different than the - // snapshot transformation because the snapshot is always based - // of the native orientation of the screen, not the orientation - // we were last in. - createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix); - - try { - Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, - mOriginalWidth*2, mOriginalHeight*2); - Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); - mCustomBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner, - SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false); - mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix); - } catch (OutOfResourcesException e) { - Slog.w(TAG, "Unable to allocate black surface", e); - } - } if (!customAnim && mExitingBlackFrame == null) { try { @@ -585,8 +382,8 @@ class ScreenRotationAnimation { outer = mCurrentDisplayRect; inner = mOriginalDisplayRect; } else { - outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, - mOriginalWidth*2, mOriginalHeight*2); + outer = new Rect(-mOriginalWidth * 1, -mOriginalHeight * 1, + mOriginalWidth * 2, mOriginalHeight * 2); inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); } mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner, @@ -599,8 +396,8 @@ class ScreenRotationAnimation { if (customAnim && mEnteringBlackFrame == null) { try { - Rect outer = new Rect(-finalWidth*1, -finalHeight*1, - finalWidth*2, finalHeight*2); + Rect outer = new Rect(-finalWidth * 1, -finalHeight * 1, + finalWidth * 2, finalHeight * 2); Rect inner = new Rect(0, 0, finalWidth, finalHeight); mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner, SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false); @@ -617,7 +414,6 @@ class ScreenRotationAnimation { */ public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) { - if (DEBUG_STATE) Slog.v(TAG, "Dismiss!"); if (mSurfaceControl == null) { // Can't do animation. return false; @@ -629,24 +425,20 @@ class ScreenRotationAnimation { if (!mStarted) { return false; } - if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true"); mFinishAnimReady = true; return true; } public void kill() { - if (DEBUG_STATE) Slog.v(TAG, "Kill!"); if (mSurfaceControl != null) { if (SHOW_TRANSACTIONS || - SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, - " FREEZE " + mSurfaceControl + ": DESTROY"); + SHOW_SURFACE_ALLOC) { + Slog.i(TAG_WM, + " FREEZE " + mSurfaceControl + ": DESTROY"); + } mService.mTransactionFactory.make().remove(mSurfaceControl).apply(); mSurfaceControl = null; } - if (mCustomBlackFrame != null) { - mCustomBlackFrame.kill(); - mCustomBlackFrame = null; - } if (mExitingBlackFrame != null) { mExitingBlackFrame.kill(); mExitingBlackFrame = null; @@ -655,38 +447,6 @@ class ScreenRotationAnimation { mEnteringBlackFrame.kill(); mEnteringBlackFrame = null; } - if (TWO_PHASE_ANIMATION) { - if (mStartExitAnimation != null) { - mStartExitAnimation.cancel(); - mStartExitAnimation = null; - } - if (mStartEnterAnimation != null) { - mStartEnterAnimation.cancel(); - mStartEnterAnimation = null; - } - if (mFinishExitAnimation != null) { - mFinishExitAnimation.cancel(); - mFinishExitAnimation = null; - } - if (mFinishEnterAnimation != null) { - mFinishEnterAnimation.cancel(); - mFinishEnterAnimation = null; - } - } - if (USE_CUSTOM_BLACK_FRAME) { - if (mStartFrameAnimation != null) { - mStartFrameAnimation.cancel(); - mStartFrameAnimation = null; - } - if (mRotateFrameAnimation != null) { - mRotateFrameAnimation.cancel(); - mRotateFrameAnimation = null; - } - if (mFinishFrameAnimation != null) { - mFinishFrameAnimation.cancel(); - mFinishFrameAnimation = null; - } - } if (mRotateExitAnimation != null) { mRotateExitAnimation.cancel(); mRotateExitAnimation = null; @@ -698,7 +458,7 @@ class ScreenRotationAnimation { } public boolean isAnimating() { - return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady); + return hasAnimations(); } public boolean isRotating() { @@ -706,13 +466,7 @@ class ScreenRotationAnimation { } private boolean hasAnimations() { - return (TWO_PHASE_ANIMATION && - (mStartEnterAnimation != null || mStartExitAnimation != null - || mFinishEnterAnimation != null || mFinishExitAnimation != null)) - || (USE_CUSTOM_BLACK_FRAME && - (mStartFrameAnimation != null || mRotateFrameAnimation != null - || mFinishFrameAnimation != null)) - || mRotateEnterAnimation != null || mRotateExitAnimation != null; + return mRotateEnterAnimation != null || mRotateExitAnimation != null; } private boolean stepAnimation(long now) { @@ -720,177 +474,45 @@ class ScreenRotationAnimation { mHalfwayPoint = Long.MAX_VALUE; } if (mFinishAnimReady && mFinishAnimStartTime < 0) { - if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready"); mFinishAnimStartTime = now; } - if (TWO_PHASE_ANIMATION) { - mMoreStartExit = false; - if (mStartExitAnimation != null) { - mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation); - } - - mMoreStartEnter = false; - if (mStartEnterAnimation != null) { - mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation); - } - } - if (USE_CUSTOM_BLACK_FRAME) { - mMoreStartFrame = false; - if (mStartFrameAnimation != null) { - mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation); - } - } - - long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0; - if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow); - - if (TWO_PHASE_ANIMATION) { - mMoreFinishExit = false; - if (mFinishExitAnimation != null) { - mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation); - } - - mMoreFinishEnter = false; - if (mFinishEnterAnimation != null) { - mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation); - } - } - if (USE_CUSTOM_BLACK_FRAME) { - mMoreFinishFrame = false; - if (mFinishFrameAnimation != null) { - mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation); - } - } - mMoreRotateExit = false; if (mRotateExitAnimation != null) { - mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation); + mMoreRotateExit = mRotateExitAnimation.getTransformation(now, + mRotateExitTransformation); } mMoreRotateEnter = false; if (mRotateEnterAnimation != null) { - mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation); - } - - if (USE_CUSTOM_BLACK_FRAME) { - mMoreRotateFrame = false; - if (mRotateFrameAnimation != null) { - mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation); - } + mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, + mRotateEnterTransformation); } - if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) { - if (TWO_PHASE_ANIMATION) { - if (mStartExitAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!"); - mStartExitAnimation.cancel(); - mStartExitAnimation = null; - mStartExitTransformation.clear(); - } - if (mFinishExitAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!"); - mFinishExitAnimation.cancel(); - mFinishExitAnimation = null; - mFinishExitTransformation.clear(); - } - } + if (!mMoreRotateExit) { if (mRotateExitAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!"); mRotateExitAnimation.cancel(); mRotateExitAnimation = null; mRotateExitTransformation.clear(); } } - if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) { - if (TWO_PHASE_ANIMATION) { - if (mStartEnterAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!"); - mStartEnterAnimation.cancel(); - mStartEnterAnimation = null; - mStartEnterTransformation.clear(); - } - if (mFinishEnterAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!"); - mFinishEnterAnimation.cancel(); - mFinishEnterAnimation = null; - mFinishEnterTransformation.clear(); - } - } + if (!mMoreRotateEnter) { if (mRotateEnterAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!"); mRotateEnterAnimation.cancel(); mRotateEnterAnimation = null; mRotateEnterTransformation.clear(); } } - if (USE_CUSTOM_BLACK_FRAME && !mMoreStartFrame && !mMoreRotateFrame && !mMoreFinishFrame) { - if (mStartFrameAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing start frame anim!"); - mStartFrameAnimation.cancel(); - mStartFrameAnimation = null; - mStartFrameTransformation.clear(); - } - if (mFinishFrameAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing finish frame anim!"); - mFinishFrameAnimation.cancel(); - mFinishFrameAnimation = null; - mFinishFrameTransformation.clear(); - } - if (mRotateFrameAnimation != null) { - if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing rotate frame anim!"); - mRotateFrameAnimation.cancel(); - mRotateFrameAnimation = null; - mRotateFrameTransformation.clear(); - } - } - mExitTransformation.set(mRotateExitTransformation); mEnterTransformation.set(mRotateEnterTransformation); - if (TWO_PHASE_ANIMATION) { - mExitTransformation.compose(mStartExitTransformation); - mExitTransformation.compose(mFinishExitTransformation); - - mEnterTransformation.compose(mStartEnterTransformation); - mEnterTransformation.compose(mFinishEnterTransformation); - } - - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation); - - if (USE_CUSTOM_BLACK_FRAME) { - //mFrameTransformation.set(mRotateExitTransformation); - //mFrameTransformation.compose(mStartExitTransformation); - //mFrameTransformation.compose(mFinishExitTransformation); - mFrameTransformation.set(mRotateFrameTransformation); - mFrameTransformation.compose(mStartFrameTransformation); - mFrameTransformation.compose(mFinishFrameTransformation); - mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation); - } - final boolean more = (TWO_PHASE_ANIMATION - && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit)) - || (USE_CUSTOM_BLACK_FRAME - && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame)) - || mMoreRotateEnter || mMoreRotateExit + final boolean more = mMoreRotateEnter || mMoreRotateExit || !mFinishAnimReady; mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); - if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more); - return more; } @@ -900,27 +522,17 @@ class ScreenRotationAnimation { } if (mSurfaceControl != null) { - if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { - if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); + if (!mMoreRotateExit) { t.hide(mSurfaceControl); } } - if (mCustomBlackFrame != null) { - if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) { - if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame"); - mCustomBlackFrame.hide(t); - } else { - mCustomBlackFrame.setMatrix(t, mFrameTransformation.getMatrix()); - } - } - if (mExitingBlackFrame != null) { - if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { - if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame"); + if (!mMoreRotateExit) { mExitingBlackFrame.hide(t); } else { - mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix); + mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), + mFrameInitialMatrix); mExitingBlackFrame.setMatrix(t, mExitFrameFinalMatrix); if (mForceDefaultOrientation) { mExitingBlackFrame.setAlpha(t, mExitTransformation.getAlpha()); @@ -929,8 +541,7 @@ class ScreenRotationAnimation { } if (mEnteringBlackFrame != null) { - if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) { - if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame"); + if (!mMoreRotateEnter) { mEnteringBlackFrame.hide(t); } else { mEnteringBlackFrame.setMatrix(t, mEnterTransformation.getMatrix()); @@ -943,38 +554,11 @@ class ScreenRotationAnimation { public boolean stepAnimationLocked(long now) { if (!hasAnimations()) { - if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running"); mFinishAnimReady = false; return false; } if (!mAnimRunning) { - if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate"); - if (TWO_PHASE_ANIMATION) { - if (mStartEnterAnimation != null) { - mStartEnterAnimation.setStartTime(now); - } - if (mStartExitAnimation != null) { - mStartExitAnimation.setStartTime(now); - } - if (mFinishEnterAnimation != null) { - mFinishEnterAnimation.setStartTime(0); - } - if (mFinishExitAnimation != null) { - mFinishExitAnimation.setStartTime(0); - } - } - if (USE_CUSTOM_BLACK_FRAME) { - if (mStartFrameAnimation != null) { - mStartFrameAnimation.setStartTime(now); - } - if (mFinishFrameAnimation != null) { - mFinishFrameAnimation.setStartTime(0); - } - if (mRotateFrameAnimation != null) { - mRotateFrameAnimation.setStartTime(now); - } - } if (mRotateEnterAnimation != null) { mRotateEnterAnimation.setStartTime(now); } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java index cb504607420c..85176bee67df 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java @@ -193,7 +193,9 @@ class SurfaceAnimationRunner { public void onAnimationStart(Animator animation) { synchronized (mCancelLock) { if (!a.mCancelled) { - mFrameTransaction.show(a.mLeash); + // TODO: change this back to use show instead of alpha when b/138459974 is + // fixed. + mFrameTransaction.setAlpha(a.mLeash, 1); } } } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 3d9dfeb4ecec..cd211a28a908 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -324,9 +324,9 @@ class SurfaceAnimator { .setName(surface + " - animation-leash"); final SurfaceControl leash = builder.build(); t.setWindowCrop(leash, width, height); - if (!hidden) { - t.show(leash); - } + t.show(leash); + // TODO: change this back to use show instead of alpha when b/138459974 is fixed. + t.setAlpha(leash, hidden ? 0 : 1); t.reparent(surface, leash); return leash; } diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java index f776062b31a1..c2c476741963 100644 --- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java @@ -56,6 +56,7 @@ class TaskChangeNotificationController { private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21; private static final int NOTIFY_SINGLE_TASK_DISPLAY_DRAWN = 22; private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 23; + private static final int NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG = 24; // Delay in notifying task stack change listeners (in millis) private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100; @@ -164,6 +165,10 @@ class TaskChangeNotificationController { l.onTaskDisplayChanged(m.arg1, m.arg2); }; + private final TaskStackConsumer mNotifyTaskListUpdated = (l, m) -> { + l.onRecentTaskListUpdated(); + }; + @FunctionalInterface public interface TaskStackConsumer { void accept(ITaskStackListener t, Message m) throws RemoteException; @@ -249,6 +254,9 @@ class TaskChangeNotificationController { case NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG: forAllRemoteListeners(mNotifyTaskDisplayChanged, msg); break; + case NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG: + forAllRemoteListeners(mNotifyTaskListUpdated, msg); + break; } } } @@ -513,4 +521,13 @@ class TaskChangeNotificationController { forAllLocalListeners(mNotifyTaskStackChanged, msg); msg.sendToTarget(); } + + /** + * Called when any additions or deletions to the recent tasks list have been made. + */ + void notifyTaskListUpdated() { + final Message msg = mHandler.obtainMessage(NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG); + forAllLocalListeners(mNotifyTaskListUpdated, msg); + msg.sendToTarget(); + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fbdc54a2435b..3221aef73add 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -34,6 +34,7 @@ import static android.os.Process.myPid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE; import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP; +import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -848,6 +849,16 @@ public class WindowManagerService extends IWindowManager.Stub int mSystemGestureExclusionLimitDp; boolean mSystemGestureExcludedByPreQStickyImmersive; + /** + * The minimum duration between gesture exclusion logging for a given window in + * milliseconds. + * + * Events that happen in-between will be silently dropped. + * + * A non-positive value disables logging. + */ + public long mSystemGestureExclusionLogDebounceTimeoutMillis; + public interface WindowChangeListener { public void windowsChanged(); public void focusChanged(); @@ -1147,6 +1158,9 @@ public class WindowManagerService extends IWindowManager.Stub mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); + mSystemGestureExclusionLogDebounceTimeoutMillis = + DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0); mSystemGestureExcludedByPreQStickyImmersive = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); @@ -1164,6 +1178,10 @@ public class WindowManagerService extends IWindowManager.Stub mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky; mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit); } + + mSystemGestureExclusionLogDebounceTimeoutMillis = + DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0); } }); @@ -2006,6 +2024,7 @@ public class WindowManagerService extends IWindowManager.Stub int attrChanges = 0; int flagChanges = 0; + int privateFlagChanges = 0; if (attrs != null) { displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid); // if they don't have the permission, mask out the status bar bits @@ -2033,7 +2052,8 @@ public class WindowManagerService extends IWindowManager.Stub attrs.height = win.mAttrs.height; } - flagChanges = win.mAttrs.flags ^= attrs.flags; + flagChanges = win.mAttrs.flags ^ attrs.flags; + privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags; attrChanges = win.mAttrs.copyFrom(attrs); if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) { @@ -2050,7 +2070,7 @@ public class WindowManagerService extends IWindowManager.Stub win.getDisplayContent().getDisplayId()); } - if ((flagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) { + if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) { updateNonSystemOverlayWindowsVisibilityIfNeeded( win, win.mWinAnimator.getShown()); } @@ -4529,7 +4549,6 @@ public class WindowManagerService extends IWindowManager.Stub public static final int SEAMLESS_ROTATION_TIMEOUT = 54; public static final int RESTORE_POINTER_ICON = 55; public static final int SET_HAS_OVERLAY_UI = 58; - public static final int SET_RUNNING_REMOTE_ANIMATION = 59; public static final int ANIMATION_FAILSAFE = 60; public static final int RECOMPUTE_FOCUS = 61; public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62; @@ -4886,10 +4905,6 @@ public class WindowManagerService extends IWindowManager.Stub mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1); break; } - case SET_RUNNING_REMOTE_ANIMATION: { - mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1); - break; - } case ANIMATION_FAILSAFE: { synchronized (mGlobalLock) { if (mRecentsAnimationController != null) { @@ -7543,7 +7558,7 @@ public class WindowManagerService extends IWindowManager.Stub return; } final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty(); - if (surfaceShown) { + if (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible()) { if (!mHidingNonSystemOverlayWindows.contains(win)) { mHidingNonSystemOverlayWindows.add(win); } @@ -7574,11 +7589,6 @@ public class WindowManagerService extends IWindowManager.Stub return mSurfaceBuilderFactory.make(s); } - void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0) - .sendToTarget(); - } - void startSeamlessRotation() { // We are careful to reset this in case a window was removed before it finished // seamless rotation. @@ -7639,10 +7649,12 @@ public class WindowManagerService extends IWindowManager.Stub isDown = motionEvent.getAction() == MotionEvent.ACTION_DOWN; isUp = motionEvent.getAction() == MotionEvent.ACTION_UP; } + final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE; // For ACTION_DOWN, syncInputTransactions before injecting input. + // For all mouse events, also sync before injecting. // For ACTION_UP, sync after injecting. - if (isDown) { + if (isDown || isMouseEvent) { syncInputTransactions(); } final boolean result = diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 4a91dac27d7e..cf8e1e80ccc3 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -50,6 +50,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; +import android.os.Build; import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; @@ -57,6 +58,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import android.view.IRemoteAnimationRunner; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.HeavyWeightSwitcherActivity; @@ -160,6 +162,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // Thread currently set for VR scheduling int mVrThreadTid; + boolean mIsImeProcess; + // all activities running in the process private final ArrayList<ActivityRecord> mActivities = new ArrayList<>(); // any tasks this process had run root activities in @@ -177,6 +181,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // Registered display id as a listener to override config change private int mDisplayId; + /** Whether our process is currently running a {@link RecentsAnimation} */ + private boolean mRunningRecentsAnimation; + + /** Whether our process is currently running a {@link IRemoteAnimationRunner} */ + private boolean mRunningRemoteAnimation; + public WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name, int uid, int userId, Object owner, WindowProcessListener listener) { mInfo = info; @@ -954,17 +964,32 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio final Configuration config = getConfiguration(); if (mLastReportedConfiguration.diff(config) == 0) { // Nothing changed. + if (Build.IS_DEBUGGABLE && mIsImeProcess) { + // TODO (b/135719017): Temporary log for debugging IME service. + Slog.w(TAG_CONFIGURATION, "Current config: " + config + + " unchanged for IME proc " + mName); + } return; } try { if (mThread == null) { + if (Build.IS_DEBUGGABLE && mIsImeProcess) { + // TODO (b/135719017): Temporary log for debugging IME service. + Slog.w(TAG_CONFIGURATION, "Unable to send config for IME proc " + mName + + ": no app thread"); + } return; } if (DEBUG_CONFIGURATION) { Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName + " new config " + config); } + if (Build.IS_DEBUGGABLE && mIsImeProcess) { + // TODO (b/135719017): Temporary log for debugging IME service. + Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + + " new config " + config); + } config.seq = mAtm.increaseConfigurationSeqLocked(); mAtm.getLifecycleManager().scheduleTransaction(mThread, ConfigurationChangeItem.obtain(config)); @@ -1080,6 +1105,30 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } + void setRunningRecentsAnimation(boolean running) { + if (mRunningRecentsAnimation == running) { + return; + } + mRunningRecentsAnimation = running; + updateRunningRemoteOrRecentsAnimation(); + } + + void setRunningRemoteAnimation(boolean running) { + if (mRunningRemoteAnimation == running) { + return; + } + mRunningRemoteAnimation = running; + updateRunningRemoteOrRecentsAnimation(); + } + + private void updateRunningRemoteOrRecentsAnimation() { + + // Posting on handler so WM lock isn't held when we call into AM. + mAtm.mH.sendMessage(PooledLambda.obtainMessage( + WindowProcessListener::setRunningRemoteAnimation, mListener, + mRunningRecentsAnimation || mRunningRemoteAnimation)); + } + @Override public String toString() { return mOwner != null ? mOwner.toString() : null; diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java index 527d54a40d03..23d7a6a9d293 100644 --- a/services/core/java/com/android/server/wm/WindowProcessListener.java +++ b/services/core/java/com/android/server/wm/WindowProcessListener.java @@ -17,6 +17,8 @@ package com.android.server.wm; import android.util.proto.ProtoOutputStream; +import android.view.IRemoteAnimationRunner; +import android.view.RemoteAnimationAdapter; /** * Interface used by the owner/creator of a process that owns windows to listen to changes from the @@ -60,4 +62,14 @@ public interface WindowProcessListener { /** App died :(...oh well */ void appDied(); void writeToProto(ProtoOutputStream proto, long fieldId); + + /** + * Sets if the process is currently running a remote animation, which is taken a signal for + * determining oom adjustment and scheduling behavior. + * + * @param runningRemoteAnimation True if the process is running a remote animation, false + * otherwise. + * @see RemoteAnimationAdapter + */ + void setRunningRemoteAnimation(boolean runningRemoteAnimation); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 9f9ef24f72e1..e14514be2207 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -20,6 +20,8 @@ import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OP_NONE; +import static android.app.WindowConfiguration.isSplitScreenWindowingMode; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.SurfaceControl.Transaction; @@ -79,6 +81,7 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; import static com.android.server.wm.AnimationSpecProto.MOVE; +import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.IdentifierProto.HASH_CODE; @@ -173,6 +176,7 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.util.Slog; +import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.view.Display; @@ -226,6 +230,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // to capture touch events in that area. static final int RESIZE_HANDLE_WIDTH_IN_DP = 30; + static final int EXCLUSION_LEFT = 0; + static final int EXCLUSION_RIGHT = 1; + final WindowManagerPolicy mPolicy; final Context mContext; final Session mSession; @@ -396,6 +403,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private final List<Rect> mExclusionRects = new ArrayList<>(); + // 0 = left, 1 = right + private final int[] mLastRequestedExclusionHeight = {0, 0}; + private final int[] mLastGrantedExclusionHeight = {0, 0}; + private final long[] mLastExclusionLogUptimeMillis = {0, 0}; + + private boolean mLastShownChangedReported; + // If a window showing a wallpaper: the requested offset for the // wallpaper; if a wallpaper window: the currently applied offset. float mWallpaperX = -1; @@ -678,6 +692,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && mAppToken != null && mAppToken.mTargetSdk < Build.VERSION_CODES.Q; } + void setLastExclusionHeights(int side, int requested, int granted) { + boolean changed = mLastGrantedExclusionHeight[side] != granted + || mLastRequestedExclusionHeight[side] != requested; + + if (changed) { + if (mLastShownChangedReported) { + logExclusionRestrictions(side); + } + + mLastGrantedExclusionHeight[side] = granted; + mLastRequestedExclusionHeight[side] = requested; + } + } + interface PowerManagerWrapper { void wakeUp(long time, @WakeReason int reason, String details); @@ -2961,6 +2989,49 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mAnimatingExit = false; } + void onSurfaceShownChanged(boolean shown) { + if (mLastShownChangedReported == shown) { + return; + } + mLastShownChangedReported = shown; + + if (shown) { + initExclusionRestrictions(); + } else { + logExclusionRestrictions(EXCLUSION_LEFT); + logExclusionRestrictions(EXCLUSION_RIGHT); + } + } + + private void logExclusionRestrictions(int side) { + if (!logsGestureExclusionRestrictions(this) + || SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side] + + mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis) { + // Drop the log if we have just logged; this is okay, because what we would have logged + // was true only for a short duration. + return; + } + + final long now = SystemClock.uptimeMillis(); + final long duration = now - mLastExclusionLogUptimeMillis[side]; + mLastExclusionLogUptimeMillis[side] = now; + + final int requested = mLastRequestedExclusionHeight[side]; + final int granted = mLastGrantedExclusionHeight[side]; + + StatsLog.write(StatsLog.EXCLUSION_RECT_STATE_CHANGED, + mAttrs.packageName, requested, requested - granted /* rejected */, + side + 1 /* Sides are 1-indexed in atoms.proto */, + (getConfiguration().orientation == ORIENTATION_LANDSCAPE), + isSplitScreenWindowingMode(getWindowingMode()), (int) duration); + } + + private void initExclusionRestrictions() { + final long now = SystemClock.uptimeMillis(); + mLastExclusionLogUptimeMillis[EXCLUSION_LEFT] = now; + mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now; + } + @Override public boolean isDefaultDisplay() { final DisplayContent displayContent = getDisplayContent(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index d90e66e10e73..ae3a10a1ee0f 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -329,9 +329,14 @@ class WindowStateAnimator { } mDrawState = COMMIT_DRAW_PENDING; layoutNeeded = true; - } - if (postDrawTransaction != null) { - mPostDrawTransaction.merge(postDrawTransaction); + + if (postDrawTransaction != null) { + mPostDrawTransaction.merge(postDrawTransaction); + } + } else if (postDrawTransaction != null) { + // If draw state is not pending we may delay applying this transaction from the client, + // so apply it now. + postDrawTransaction.apply(); } return layoutNeeded; @@ -1296,7 +1301,7 @@ class WindowStateAnimator { // if we are transparent. if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) { final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl; - mPostDrawTransaction.hide(pendingSurfaceControl); + mPostDrawTransaction.reparent(pendingSurfaceControl, null); mPostDrawTransaction.reparentChildren(pendingSurfaceControl, mSurfaceController.mSurfaceControl); } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index a616e06e0635..bcefa8fed64e 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -499,6 +499,8 @@ class WindowSurfaceController { mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mAnimator.mWin, surfaceShown); + mAnimator.mWin.onSurfaceShownChanged(surfaceShown); + if (mWindowSession != null) { mWindowSession.onWindowSurfaceVisibilityChanged(this, mSurfaceShown, mWindowType); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index cfa99445f45f..59996ccd5530 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -16,6 +16,7 @@ package com.android.server.devicepolicy; import android.app.admin.IDevicePolicyManager; +import android.content.ComponentName; import com.android.server.SystemService; @@ -56,4 +57,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public void clearSystemUpdatePolicyFreezePeriodRecord() { } + + public boolean setKeyGrantForApp(ComponentName admin, String callerPackage, String alias, + String packageName, boolean hasGrant) { + return false; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ba0636963fa2..f800cca3ab3d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5727,6 +5727,59 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } + @Override + public boolean setKeyGrantForApp( + ComponentName who, String callerPackage, String alias, String packageName, + boolean hasGrant) { + enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, + DELEGATION_CERT_SELECTION); + + if (TextUtils.isEmpty(alias)) { + throw new IllegalArgumentException("Alias to grant cannot be empty."); + } + + if (TextUtils.isEmpty(packageName)) { + throw new IllegalArgumentException("Package to grant to cannot be empty."); + } + + final int userId = mInjector.userHandleGetCallingUserId(); + final int granteeUid; + try { + ApplicationInfo ai = mInjector.getIPackageManager().getApplicationInfo( + packageName, 0, userId); + if (ai == null) { + throw new IllegalArgumentException( + String.format("Provided package %s is not installed", packageName)); + } + granteeUid = ai.uid; + } catch (RemoteException e) { + throw new IllegalStateException("Failure getting grantee uid", e); + } + + final int callingUid = mInjector.binderGetCallingUid(); + final long id = mInjector.binderClearCallingIdentity(); + try { + final KeyChainConnection keyChainConnection = + KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid)); + try { + IKeyChainService keyChain = keyChainConnection.getService(); + keyChain.setGrant(granteeUid, alias, hasGrant); + return true; + } catch (RemoteException e) { + Log.e(LOG_TAG, "Setting grant for package.", e); + return false; + } finally { + keyChainConnection.close(); + } + } catch (InterruptedException e) { + Log.w(LOG_TAG, "Interrupted while setting key grant", e); + Thread.currentThread().interrupt(); + } finally { + mInjector.binderRestoreCallingIdentity(id); + } + return false; + } + /** * Enforce one the following conditions are met: * (1) The device has a Device Owner, and one of the following holds: diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 16007d775283..6e0d83433559 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -67,7 +67,6 @@ import android.util.EventLog; import android.util.Slog; import android.view.WindowManager; import android.view.contentcapture.ContentCaptureManager; -import android.view.inputmethod.InputMethodSystemProperty; import com.android.internal.R; import com.android.internal.logging.MetricsLogger; @@ -101,6 +100,7 @@ import com.android.server.hdmi.HdmiControlService; import com.android.server.incident.IncidentCompanionService; import com.android.server.input.InputManagerService; import com.android.server.inputmethod.InputMethodManagerService; +import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.inputmethod.MultiClientInputMethodManagerService; import com.android.server.lights.LightsService; import com.android.server.media.MediaResourceMonitorService; diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java index be93d6ba5352..e55c4a677dbc 100644 --- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java @@ -26,8 +26,12 @@ import static com.android.server.backup.testing.TransportData.backupTransport; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; import static org.testng.Assert.expectThrows; @@ -121,7 +125,7 @@ public class BackupManagerServiceTest { public void testConstructor_doesNotRegisterUsers() throws Exception { BackupManagerService backupManagerService = createService(); - assertThat(backupManagerService.getServiceUsers().size()).isEqualTo(0); + assertThat(backupManagerService.getUserServices().size()).isEqualTo(0); } /** Test that the constructor handles {@code null} parameters. */ @@ -152,7 +156,7 @@ public class BackupManagerServiceTest { backupManagerService.startServiceForUser(mUserOneId); - SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers(); + SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); assertThat(serviceUsers.get(mUserOneId)).isNotNull(); } @@ -164,7 +168,7 @@ public class BackupManagerServiceTest { backupManagerService.startServiceForUser(mUserOneId, mUserOneService); - SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers(); + SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService); } @@ -178,7 +182,7 @@ public class BackupManagerServiceTest { backupManagerService.stopServiceForUser(mUserOneId); - SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers(); + SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); assertThat(serviceUsers.get(mUserOneId)).isNull(); assertThat(serviceUsers.get(mUserTwoId)).isEqualTo(mUserTwoService); @@ -204,7 +208,7 @@ public class BackupManagerServiceTest { backupManagerService.stopServiceForUser(mUserOneId); - SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers(); + SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(0); } @@ -1500,6 +1504,48 @@ public class BackupManagerServiceTest { } // --------------------------------------------- + // Lifecycle tests + // --------------------------------------------- + + + /** testOnStart_publishesService */ + @Test + public void testOnStart_publishesService() { + Trampoline trampoline = mock(Trampoline.class); + BackupManagerService.Lifecycle lifecycle = + spy(new BackupManagerService.Lifecycle(mContext, trampoline)); + doNothing().when(lifecycle).publishService(anyString(), any()); + + lifecycle.onStart(); + + verify(lifecycle).publishService(Context.BACKUP_SERVICE, trampoline); + } + + /** testOnUnlockUser_forwards */ + @Test + public void testOnUnlockUser_forwards() { + Trampoline trampoline = mock(Trampoline.class); + BackupManagerService.Lifecycle lifecycle = + new BackupManagerService.Lifecycle(mContext, trampoline); + + lifecycle.onUnlockUser(UserHandle.USER_SYSTEM); + + verify(trampoline).onUnlockUser(UserHandle.USER_SYSTEM); + } + + /** testOnStopUser_forwards */ + @Test + public void testOnStopUser_forwards() { + Trampoline trampoline = mock(Trampoline.class); + BackupManagerService.Lifecycle lifecycle = + new BackupManagerService.Lifecycle(mContext, trampoline); + + lifecycle.onStopUser(UserHandle.USER_SYSTEM); + + verify(trampoline).onStopUser(UserHandle.USER_SYSTEM); + } + + // --------------------------------------------- // Service tests // --------------------------------------------- diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java index 4a33739a8596..101bee28025c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java @@ -21,12 +21,17 @@ import static com.android.server.am.AppCompactor.compactActionIntToString; import static com.google.common.truth.Truth.assertThat; +import android.content.Context; import android.os.Handler; import android.os.HandlerThread; +import android.os.Process; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.text.TextUtils; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.server.ServiceThread; import com.android.server.appop.AppOpsService; import com.android.server.testables.TestableDeviceConfig; @@ -54,6 +59,8 @@ import java.util.concurrent.TimeUnit; @RunWith(MockitoJUnitRunner.class) public final class AppCompactorTest { + private ServiceThread mThread; + @Mock private AppOpsService mAppOpsService; private AppCompactor mCompactorUnderTest; @@ -70,7 +77,12 @@ public final class AppCompactorTest { mHandlerThread = new HandlerThread(""); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); - ActivityManagerService ams = new ActivityManagerService(new TestInjector()); + + mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT, + true /* allowIo */); + mThread.start(); + + ActivityManagerService ams = new ActivityManagerService(new TestInjector(), mThread); mCompactorUnderTest = new AppCompactor(ams, new AppCompactor.PropertyChangedCallbackForTest() { @Override @@ -85,6 +97,7 @@ public final class AppCompactorTest { @After public void tearDown() { mHandlerThread.quit(); + mThread.quit(); mCountDown = null; } @@ -656,5 +669,10 @@ public final class AppCompactorTest { public Handler getUiHandler(ActivityManagerService service) { return mHandler; } + + @Override + public Context getContext() { + return InstrumentationRegistry.getInstrumentation().getContext(); + } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 328e8f41f5e2..1c88c40c3e2b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -400,22 +400,7 @@ public class ConnectivityControllerTest { } @Test - public void testEvaluateStateLocked_HeartbeatsOn() { - mConstants.USE_HEARTBEATS = true; - final ConnectivityController controller = new ConnectivityController(mService); - final JobStatus red = createJobStatus(createJob() - .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED); - - controller.evaluateStateLocked(red); - assertFalse(controller.isStandbyExceptionRequestedLocked(UID_RED)); - verify(mNetPolicyManagerInternal, never()) - .setAppIdleWhitelist(eq(UID_RED), anyBoolean()); - } - - @Test public void testEvaluateStateLocked_JobWithoutConnectivity() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = new ConnectivityController(mService); final JobStatus red = createJobStatus(createJob().setMinimumLatency(1)); @@ -427,7 +412,6 @@ public class ConnectivityControllerTest { @Test public void testEvaluateStateLocked_JobWouldBeReady() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); doReturn(true).when(controller).wouldBeReadyWithConnectivityLocked(any()); final JobStatus red = createJobStatus(createJob() @@ -466,7 +450,6 @@ public class ConnectivityControllerTest { @Test public void testEvaluateStateLocked_JobWouldNotBeReady() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); doReturn(false).when(controller).wouldBeReadyWithConnectivityLocked(any()); final JobStatus red = createJobStatus(createJob() @@ -502,7 +485,6 @@ public class ConnectivityControllerTest { @Test public void testReevaluateStateLocked() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); final JobStatus redOne = createJobStatus(createJob(1) .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) @@ -625,7 +607,7 @@ public class ConnectivityControllerTest { private static JobStatus createJobStatus(JobInfo.Builder job, int uid, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) { - return new JobStatus(job.build(), uid, null, -1, 0, 0, null, + return new JobStatus(job.build(), uid, null, -1, 0, null, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java index 94e02d3b2648..64da6f6b8590 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java @@ -573,7 +573,7 @@ public class JobStatusTest { long latestRunTimeElapsedMillis) { final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar")) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build(); - return new JobStatus(job, 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis, + return new JobStatus(job, 0, null, -1, 0, null, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0); } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index 2d702312a62b..8863d5abeca3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -107,7 +107,6 @@ public class QuotaControllerTest { private static final int SOURCE_USER_ID = 0; private BroadcastReceiver mChargingReceiver; - private Constants mJsConstants; private QuotaController mQuotaController; private QuotaController.QcConstants mQcConstants; private int mSourceUid; @@ -134,14 +133,11 @@ public class QuotaControllerTest { .strictness(Strictness.LENIENT) .mockStatic(LocalServices.class) .startMocking(); - // Make sure constants turn on QuotaController. - mJsConstants = new Constants(); - mJsConstants.USE_HEARTBEATS = false; // Called in StateController constructor. when(mJobSchedulerService.getTestableContext()).thenReturn(mContext); when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService); - when(mJobSchedulerService.getConstants()).thenReturn(mJsConstants); + when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class)); // Called in QuotaController constructor. IActivityManager activityManager = ActivityManager.getService(); spyOn(activityManager); @@ -1809,30 +1805,6 @@ public class QuotaControllerTest { .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } - /** Tests that QuotaController doesn't throttle if throttling is turned off. */ - @Test - public void testThrottleToggling() throws Exception { - setDischarging(); - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession( - JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS, - 10 * MINUTE_IN_MILLIS, 4)); - JobStatus jobStatus = createJobStatus("testThrottleToggling", 1); - setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - - mJsConstants.USE_HEARTBEATS = true; - mQuotaController.onConstantsUpdatedLocked(); - Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. - assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - - mJsConstants.USE_HEARTBEATS = false; - mQuotaController.onConstantsUpdatedLocked(); - Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. - assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - } - @Test public void testConstantsUpdating_ValidValues() { mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS; diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index b37e4602ed97..83e20fb011b0 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -83,6 +83,8 @@ android_test { optimize: { enabled: false, }, + + data: [":JobTestApp"], } java_library { diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 01f2f6b26415..c1bbb307c9f5 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -69,6 +69,7 @@ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.HARDWARE_TEST"/> + <uses-permission android:name="android.permission.BLUETOOTH"/> <!-- Uses API introduced in O (26) --> <uses-sdk android:minSdkVersion="1" diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java index a4267b86b359..1084d625f8a3 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -179,9 +179,9 @@ public class AbstractAccessibilityServiceConnectionTest { addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false); addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true); when(mMockA11yWindowManager.getWindowListLocked()).thenReturn(mA11yWindowInfos); - when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) .thenReturn(mA11yWindowInfos.get(0)); - when(mMockA11yWindowManager.findA11yWindowInfoById(PIP_WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(PIP_WINDOWID)) .thenReturn(mA11yWindowInfos.get(1)); final RemoteAccessibilityConnection conn = getRemoteA11yConnection( WINDOWID, mMockIA11yInteractionConnection, PACKAGE_NAME1); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java index 782dc3e2ad45..193f540246e6 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java @@ -47,6 +47,8 @@ import android.view.MotionEvent; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.server.accessibility.gestures.TouchExplorer; + import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java index bb35776ffcd6..04ac7fe91008 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java @@ -166,7 +166,7 @@ public class AccessibilitySecurityPolicyTest { public void canDispatchAccessibilityEvent_otherEvents_windowIdExist_returnTrue() { when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM)) .thenReturn(WINDOWID2); - when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) .thenReturn(AccessibilityWindowInfo.obtain()); for (int i = 0; i < OTHER_EVENTS.length; i++) { final AccessibilityEvent event = AccessibilityEvent.obtain(OTHER_EVENTS[i]); @@ -287,7 +287,7 @@ public class AccessibilitySecurityPolicyTest { .thenReturn(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT); when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM)) .thenReturn(WINDOWID2); - when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID)) + when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) .thenReturn(AccessibilityWindowInfo.obtain()); assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(UserHandle.USER_SYSTEM, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java index 2f9f9bbecbdf..6be5a3785865 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java @@ -192,7 +192,8 @@ public class AccessibilityServiceConnectionTest { when(parceledListSlice.getList()).thenReturn(gestureSteps); mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY); - verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0); + verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0, + Display.DEFAULT_DISPLAY); } @Test @@ -209,7 +210,8 @@ public class AccessibilityServiceConnectionTest { when(parceledListSlice.getList()).thenReturn(gestureSteps); mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY); - verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0); + verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0, + Display.DEFAULT_DISPLAY); verify(mMockServiceClient).onPerformGestureResult(0, false); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java index 7e64cafaf7a2..7887d5b76bca 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java @@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,6 +54,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection; import com.android.server.wm.WindowManagerInternal; +import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; @@ -75,9 +77,12 @@ public class AccessibilityWindowManagerTest { private static final boolean FORCE_SEND = true; private static final boolean SEND_ON_WINDOW_CHANGES = false; private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM; + // TO-DO [Multi-Display] : change the display count to 2 + private static final int DISPLAY_COUNT = 1; private static final int NUM_GLOBAL_WINDOWS = 4; private static final int NUM_APP_WINDOWS = 4; - private static final int NUM_OF_WINDOWS = NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS; + private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS) + * DISPLAY_COUNT; private static final int DEFAULT_FOCUSED_INDEX = 1; private static final int SCREEN_WIDTH = 1080; private static final int SCREEN_HEIGHT = 1920; @@ -86,7 +91,13 @@ public class AccessibilityWindowManagerTest { // List of window token, mapping from windowId -> window token. private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>(); - private final ArrayList<WindowInfo> mWindowInfos = new ArrayList<>(); + // List of window info lists, mapping from displayId -> window info lists. + private final SparseArray<ArrayList<WindowInfo>> mWindowInfos = + new SparseArray<>(); + // List of callback, mapping from displayId -> callback. + private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows = + new SparseArray<>(); + private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null); @Mock private WindowManagerInternal mMockWindowManagerInternal; @@ -109,29 +120,14 @@ public class AccessibilityWindowManagerTest { mMockA11ySecurityPolicy, mMockA11yUserManager); - // Add RemoteAccessibilityConnection into AccessibilityWindowManager, and copy - // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos - // for the test. - int layer = 0; - for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) { - final IWindow token = addAccessibilityInteractionConnection(true); - addWindowInfo(token, layer++); - - } - for (int i = 0; i < NUM_APP_WINDOWS; i++) { - final IWindow token = addAccessibilityInteractionConnection(false); - addWindowInfo(token, layer++); + for (int i = 0; i < DISPLAY_COUNT; i++) { + when(mMockWindowManagerInternal.setWindowsForAccessibilityCallback(eq(i), any())) + .thenReturn(true); + startTrackingPerDisplay(i); } - // setup default focus - mWindowInfos.get(DEFAULT_FOCUSED_INDEX).focused = true; - // Turn on windows tracking, and update window info - mA11yWindowManager.startTrackingWindows(); - mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos); - assertEquals(mA11yWindowManager.getWindowListLocked().size(), - mWindowInfos.size()); // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged. - // Reset it for mockito verify of further test case. + // Resets it for mockito verify of further test case. Mockito.reset(mMockA11yEventSender); } @@ -142,11 +138,12 @@ public class AccessibilityWindowManagerTest { @Test public void startTrackingWindows_shouldEnableWindowManagerCallback() { - // AccessibilityWindowManager#startTrackingWindows already invoked in setup + // AccessibilityWindowManager#startTrackingWindows already invoked in setup. assertTrue(mA11yWindowManager.isTrackingWindowsLocked()); - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY + final WindowsForAccessibilityCallback callbacks = + mCallbackOfWindows.get(Display.DEFAULT_DISPLAY); verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( - eq(Display.DEFAULT_DISPLAY), any()); + eq(Display.DEFAULT_DISPLAY), eq(callbacks)); } @Test @@ -156,9 +153,9 @@ public class AccessibilityWindowManagerTest { mA11yWindowManager.stopTrackingWindows(); assertFalse(mA11yWindowManager.isTrackingWindowsLocked()); - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( - eq(Display.DEFAULT_DISPLAY), any()); + eq(Display.DEFAULT_DISPLAY), isNull()); + } @Test @@ -177,87 +174,102 @@ public class AccessibilityWindowManagerTest { @Test public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() { final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); - WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX); + WindowInfo focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX); assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, focusedWindowInfo.token)); focusedWindowInfo.focused = false; - focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1); + focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1); focusedWindowInfo.focused = true; mA11yWindowManager.onTouchInteractionStart(); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID)); } @Test public void onWindowsChanged_shouldReportCorrectLayer() { - // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup - List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. + List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < a11yWindows.size(); i++) { final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); - final WindowInfo windowInfo = mWindowInfos.get(i); - assertThat(mWindowInfos.size() - windowInfo.layer - 1, + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i); + assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1, is(a11yWindow.getLayer())); } } @Test public void onWindowsChanged_shouldReportCorrectOrder() { - // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup - List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. + List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < a11yWindows.size(); i++) { final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); final IBinder windowToken = mA11yWindowManager .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId()); - final WindowInfo windowInfo = mWindowInfos.get(i); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i); assertThat(windowToken, is(windowInfo.token)); } } @Test public void onWindowsChangedAndForceSend_shouldUpdateWindows() { - final WindowInfo windowInfo = mWindowInfos.get(0); - final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer(); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + final int correctLayer = + mA11yWindowManager.getWindowListLocked().get(0).getLayer(); windowInfo.layer += 1; - mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos); - assertNotEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer()); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND); + assertNotEquals(correctLayer, + mA11yWindowManager.getWindowListLocked().get(0).getLayer()); } @Test public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() { - final WindowInfo windowInfo = mWindowInfos.get(0); - final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer(); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + final int correctLayer = + mA11yWindowManager.getWindowListLocked().get(0).getLayer(); windowInfo.layer += 1; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); - assertEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer()); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertEquals(correctLayer, + mA11yWindowManager.getWindowListLocked().get(0).getLayer()); } @Test public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows() throws RemoteException { - final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0); - final IWindow token = addAccessibilityInteractionConnection(true); + final AccessibilityWindowInfo oldWindow = + mA11yWindowManager.getWindowListLocked().get(0); + final IWindow token = + addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, true); final WindowInfo windowInfo = WindowInfo.obtain(); windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION; windowInfo.token = token.asBinder(); windowInfo.layer = 0; windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - mWindowInfos.set(0, windowInfo); + mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); - assertNotEquals(oldWindow, mA11yWindowManager.getWindowListLocked().get(0)); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertNotEquals(oldWindow, + mA11yWindowManager.getWindowListLocked().get(0)); } @Test public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() { - final WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX); - final WindowInfo windowInfo = mWindowInfos.get(0); + final WindowInfo focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); focusedWindowInfo.focused = false; windowInfo.focused = true; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused()); } @@ -288,7 +300,8 @@ public class AccessibilityWindowManagerTest { @Test public void getWindowTokenForUserAndWindowId_shouldNotNull() { - final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> windows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < windows.size(); i++) { final int windowId = windows.get(i).getId(); @@ -299,7 +312,8 @@ public class AccessibilityWindowManagerTest { @Test public void findWindowId() { - final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> windows = + mA11yWindowManager.getWindowListLocked(); for (int i = 0; i < windows.size(); i++) { final int windowId = windows.get(i).getId(); final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked( @@ -313,13 +327,15 @@ public class AccessibilityWindowManagerTest { @Test public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() { // Updates top 2 z-order WindowInfo are whole visible. - WindowInfo windowInfo = mWindowInfos.get(0); + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2); - windowInfo = mWindowInfos.get(1); - windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1); + windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, + SCREEN_WIDTH, SCREEN_HEIGHT); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(0).getId(); @@ -336,12 +352,13 @@ public class AccessibilityWindowManagerTest { @Test public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() { - // Updates z-order #1 WindowInfo is half visible - WindowInfo windowInfo = mWindowInfos.get(0); + // Updates z-order #1 WindowInfo is half visible. + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -353,7 +370,8 @@ public class AccessibilityWindowManagerTest { @Test public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() { // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible. - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -366,11 +384,12 @@ public class AccessibilityWindowManagerTest { // Updates z-order #0 WindowInfo to have two interact-able areas. Region region = new Region(0, 0, SCREEN_WIDTH, 200); region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION); - WindowInfo windowInfo = mWindowInfos.get(0); + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); windowInfo.regionInScreen.set(region); - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); - final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked(); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -382,7 +401,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() { - final IBinder eventWindowToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1).token; + final IBinder eventWindowToken = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token; final int eventWindowId = mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, eventWindowToken); when(mMockWindowManagerInternal.getFocusedWindowToken()) @@ -402,7 +422,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); assertThat(currentActiveWindowId, is(not(eventWindowId))); @@ -428,7 +449,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX); final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId( AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); assertThat(currentA11yFocusedWindowId, is(not(eventWindowId))); @@ -457,7 +479,8 @@ public class AccessibilityWindowManagerTest { @Test public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX); final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId( AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); assertThat(currentA11yFocusedWindowId, is(not(eventWindowId))); @@ -482,7 +505,8 @@ public class AccessibilityWindowManagerTest { @Test public void onTouchInteractionEnd_shouldRollbackActiveWindow() { - final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1); + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); assertThat(currentActiveWindowId, is(not(eventWindowId))); @@ -513,12 +537,14 @@ public class AccessibilityWindowManagerTest { @Test public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus() throws RemoteException { - final IBinder defaultFocusWinToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX).token; + final IBinder defaultFocusWinToken = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token; final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, defaultFocusWinToken); when(mMockWindowManagerInternal.getFocusedWindowToken()) .thenReturn(defaultFocusWinToken); - final int newFocusWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1); + final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); final IAccessibilityInteractionConnection mockNewFocusConnection = mA11yWindowManager.getConnectionLocked( USER_SYSTEM_ID, newFocusWindowId).getRemote(); @@ -556,28 +582,72 @@ public class AccessibilityWindowManagerTest { @Test public void getPictureInPictureWindow_shouldNotNull() { - assertNull(mA11yWindowManager.getPictureInPictureWindow()); - mWindowInfos.get(1).inPictureInPicture = true; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + assertNull(mA11yWindowManager.getPictureInPictureWindowLocked()); + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true; + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); - assertNotNull(mA11yWindowManager.getPictureInPictureWindow()); + assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked()); } @Test public void notifyOutsideTouch() throws RemoteException { - final int targetWindowId = getWindowIdFromWindowInfos(1); - final int outsideWindowId = getWindowIdFromWindowInfos(0); + final int targetWindowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1); + final int outsideWindowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0); final IAccessibilityInteractionConnection mockRemoteConnection = mA11yWindowManager.getConnectionLocked( USER_SYSTEM_ID, outsideWindowId).getRemote(); - mWindowInfos.get(0).hasFlagWatchOutsideTouch = true; - mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos); + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true; + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId); verify(mockRemoteConnection).notifyOutsideTouch(); } - private IWindow addAccessibilityInteractionConnection(boolean bGlobal) + private void startTrackingPerDisplay(int displayId) throws RemoteException { + ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>(); + // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy + // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos + // for the test. + int layer = 0; + for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) { + final IWindow token = addAccessibilityInteractionConnection(displayId, true); + addWindowInfo(windowInfosForDisplay, token, layer++); + + } + for (int i = 0; i < NUM_APP_WINDOWS; i++) { + final IWindow token = addAccessibilityInteractionConnection(displayId, false); + addWindowInfo(windowInfosForDisplay, token, layer++); + } + // Setups default focus. + windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true; + // Turns on windows tracking, and update window info. + mA11yWindowManager.startTrackingWindows(); + // Puts window lists into array. + mWindowInfos.put(displayId, windowInfosForDisplay); + // Sets the default display as the top focused display. + if (displayId == Display.DEFAULT_DISPLAY) { + setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX); + } + // Invokes callback for sending window lists to A11y framework. + onWindowsForAccessibilityChanged(displayId, FORCE_SEND); + + assertEquals(mA11yWindowManager.getWindowListLocked().size(), + windowInfosForDisplay.size()); + } + + private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) { + ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor = + ArgumentCaptor.forClass( + WindowManagerInternal.WindowsForAccessibilityCallback.class); + verify(mMockWindowManagerInternal) + .setWindowsForAccessibilityCallback(eq(displayId), + windowsForAccessibilityCallbacksCaptor.capture()); + return windowsForAccessibilityCallbacksCaptor.getValue(); + } + + private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal) throws RemoteException { final IWindow mockWindowToken = Mockito.mock(IWindow.class); final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock( @@ -588,6 +658,8 @@ public class AccessibilityWindowManagerTest { when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder); when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(USER_SYSTEM_ID)) .thenReturn(bGlobal); + when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowToken.asBinder())) + .thenReturn(displayId); int windowId = mA11yWindowManager.addAccessibilityInteractionConnection( mockWindowToken, mockA11yConnection, PACKAGE_NAME, USER_SYSTEM_ID); @@ -595,21 +667,40 @@ public class AccessibilityWindowManagerTest { return mockWindowToken; } - private void addWindowInfo(IWindow windowToken, int layer) { + private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) { final WindowInfo windowInfo = WindowInfo.obtain(); windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION; windowInfo.token = windowToken.asBinder(); windowInfo.layer = layer; windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - mWindowInfos.add(windowInfo); + windowInfos.add(windowInfo); } - private int getWindowIdFromWindowInfos(int index) { - final IBinder windowToken = mWindowInfos.get(index).token; + private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) { + final IBinder windowToken = mWindowInfos.get(displayId).get(index).token; return mA11yWindowManager.findWindowIdLocked( USER_SYSTEM_ID, windowToken); } + private void setTopFocusedWindowAndDisplay(int displayId, int index) { + // Sets the top focus window. + final IBinder eventWindowToken = mWindowInfos.get(displayId).get(index).token; + when(mMockWindowManagerInternal.getFocusedWindowToken()) + .thenReturn(eventWindowToken); + // Sets the top focused display. + when(mMockWindowManagerInternal.getDisplayIdForWindow(eventWindowToken)) + .thenReturn(displayId); + } + + private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) { + WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId); + if (callbacks == null) { + callbacks = getWindowsForAccessibilityCallbacks(displayId); + mCallbackOfWindows.put(displayId, callbacks); + } + callbacks.onWindowsForAccessibilityChanged(forceSend, mWindowInfos.get(displayId)); + } + static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> { private int mWindowId; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java index 2977414fb302..f1142fd2f8f9 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java @@ -47,6 +47,7 @@ import android.os.Handler; import android.os.Message; import android.os.RemoteException; import android.util.Log; +import android.view.Display; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; @@ -709,7 +710,8 @@ public class MotionEventInjectorTest { private void injectEventsSync(List<GestureStep> gestureSteps, IAccessibilityServiceClient serviceInterface, int sequence) { - mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence); + mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence, + Display.DEFAULT_DISPLAY); // Dispatch the message sent by the injector. Our simple handler doesn't guarantee stuff // happens in order. mMessageCapturingHandler.sendLastMessage(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java index cdcc338b3928..2585a2832094 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.accessibility; +package com.android.server.accessibility.gestures; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 2645461b5912..274ca368baa1 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.accessibility; +package com.android.server.accessibility.gestures; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -31,6 +31,9 @@ import android.view.MotionEvent; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.server.accessibility.AccessibilityManagerService; +import com.android.server.accessibility.EventStreamTransformation; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java index 5dafe077d32e..d57fd4b467db 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java @@ -18,13 +18,17 @@ package com.android.server.am; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; import android.app.ActivityManagerInternal; import android.os.SystemClock; import androidx.test.filters.MediumTest; +import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -43,6 +47,8 @@ public class ActivityManagerInternalTest { private static final long TEST_PROC_STATE_SEQ2 = 1112; private static final long TEST_PROC_STATE_SEQ3 = 1113; + @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule(); + @Mock private ActivityManagerService.Injector mMockInjector; private ActivityManagerService mAms; @@ -52,7 +58,11 @@ public class ActivityManagerInternalTest { public void setUp() { MockitoAnnotations.initMocks(this); - mAms = new ActivityManagerService(mMockInjector); + doReturn(InstrumentationRegistry.getInstrumentation().getContext()).when(mMockInjector) + .getContext(); + doReturn(mServiceThreadRule.getThread().getThreadHandler()).when(mMockInjector) + .getUiHandler(any()); + mAms = new ActivityManagerService(mMockInjector, mServiceThreadRule.getThread()); mAmi = mAms.new LocalService(); } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 3df6976a2cae..8a1f0467b5be 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -70,13 +70,14 @@ import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; -import com.android.server.appop.AppOpsService; import com.android.server.am.ProcessList.IsolatedUidRange; import com.android.server.am.ProcessList.IsolatedUidRangeAllocator; +import com.android.server.appop.AppOpsService; import com.android.server.wm.ActivityTaskManagerService; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; @@ -114,6 +115,8 @@ public class ActivityManagerServiceTest { UidRecord.CHANGE_ACTIVE }; + @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule(); + private Context mContext = getInstrumentation().getTargetContext(); @Mock private AppOpsService mAppOpsService; @Mock private PackageManager mPackageManager; @@ -131,7 +134,7 @@ public class ActivityManagerServiceTest { mHandlerThread.start(); mHandler = new TestHandler(mHandlerThread.getLooper()); mInjector = new TestInjector(); - mAms = new ActivityManagerService(mInjector); + mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread()); mAms.mWaitForNetworkTimeoutMs = 2000; mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext); mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper()); diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java index 1dfce51725f1..87cc0ffd374d 100644 --- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java @@ -29,6 +29,7 @@ import com.android.server.appop.AppOpsService; import com.android.server.wm.ActivityTaskManagerService; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import java.io.File; @@ -41,6 +42,9 @@ import java.io.File; @FlakyTest(bugId = 113616538) public class AppErrorDialogTest { + @Rule + public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule(); + private Context mContext; private ActivityManagerService mService; @@ -55,14 +59,19 @@ public class AppErrorDialogTest { @Override public Handler getUiHandler(ActivityManagerService service) { - return null; + return mServiceThreadRule.getThread().getThreadHandler(); } @Override public boolean isNetworkRestrictedForUid(int uid) { return false; } - }); + + @Override + public Context getContext() { + return mContext; + } + }, mServiceThreadRule.getThread()); mService.mActivityTaskManager = new ActivityTaskManagerService(mContext); mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper()); } diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java index cbdc6c3faadd..1eb02add0122 100644 --- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java +++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java @@ -39,6 +39,7 @@ import com.android.server.appop.AppOpsService; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -61,6 +62,8 @@ public class CoreSettingsObserverTest { private static final float TEST_FLOAT = 3.14f; private static final String TEST_STRING = "testString"; + @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule(); + private ActivityManagerService mAms; @Mock private Context mContext; @@ -90,7 +93,7 @@ public class CoreSettingsObserverTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolver); - mAms = new ActivityManagerService(new TestInjector()); + mAms = new ActivityManagerService(new TestInjector(), mServiceThreadRule.getThread()); mCoreSettingsObserver = new CoreSettingsObserver(mAms); } @@ -157,7 +160,7 @@ public class CoreSettingsObserverTest { private class TestInjector extends Injector { @Override public Context getContext() { - return mContext; + return getInstrumentation().getContext(); } @Override @@ -167,7 +170,7 @@ public class CoreSettingsObserverTest { @Override public Handler getUiHandler(ActivityManagerService service) { - return null; + return mServiceThreadRule.getThread().getThreadHandler(); } } } diff --git a/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java new file mode 100644 index 000000000000..e86ce7e777ab --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 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.am; + +import android.os.Process; + +import com.android.server.ServiceThread; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +class ServiceThreadRule implements TestRule { + + private ServiceThread mThread; + + ServiceThread getThread() { + return mThread; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT, + true /* allowIo */); + mThread.start(); + try { + base.evaluate(); + } finally { + mThread.getThreadHandler().runWithScissors(mThread::quit, 0 /* timeout */); + } + } + }; + } +} diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java new file mode 100644 index 000000000000..5c2ad94720f0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java @@ -0,0 +1,162 @@ +/* + * Copyright 2019 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.audio; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.media.AudioManager; +import android.media.AudioSystem; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Spy; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class AudioDeviceBrokerTest { + + private static final String TAG = "AudioDeviceBrokerTest"; + private static final int MAX_MESSAGE_HANDLING_DELAY_MS = 100; + + private Context mContext; + // the actual class under test + private AudioDeviceBroker mAudioDeviceBroker; + + @Mock private AudioService mMockAudioService; + @Spy private AudioDeviceInventory mSpyDevInventory; + + private BluetoothDevice mFakeBtDevice; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + + mMockAudioService = mock(AudioService.class); + mSpyDevInventory = spy(new AudioDeviceInventory()); + mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory); + mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker); + + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + mFakeBtDevice = adapter.getRemoteDevice("00:01:02:03:04:05"); + Assert.assertNotNull("invalid null BT device", mFakeBtDevice); + } + + @After + public void tearDown() throws Exception { } + + @Test + public void testSetUpAndTearDown() { } + + /** + * Verify call to postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() for connection + * calls into AudioDeviceInventory with the right params + * @throws Exception + */ + @Test + public void testPostA2dpDeviceConnectionChange() throws Exception { + Log.i(TAG, "testPostA2dpDeviceConnectionChange"); + Assert.assertNotNull("invalid null BT device", mFakeBtDevice); + + mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1); + Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); + verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState( + any(BluetoothDevice.class), + ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED) /*state*/, + ArgumentMatchers.eq(BluetoothProfile.A2DP) /*profile*/, + ArgumentMatchers.eq(true) /*suppressNoisyIntent*/, anyInt() /*musicDevice*/, + ArgumentMatchers.eq(1) /*a2dpVolume*/ + ); + } + + /** + * Verify call to postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() for + * connection > pause > disconnection > connection + * keeps the device connected + * @throws Exception + */ + @Test + public void testA2dpDeviceConnectionDisconnectionConnectionChange() throws Exception { + Log.i(TAG, "testA2dpDeviceConnectionDisconnectionConnectionChange"); + + doTestConnectionDisconnectionReconnection(0); + } + + /** + * Verify device disconnection and reconnection within the BECOMING_NOISY window + * @throws Exception + */ + @Test + public void testA2dpDeviceReconnectionWithinBecomingNoisyDelay() throws Exception { + Log.i(TAG, "testA2dpDeviceReconnectionWithinBecomingNoisyDelay"); + + doTestConnectionDisconnectionReconnection(AudioService.BECOMING_NOISY_DELAY_MS / 2); + } + + private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection) + throws Exception { + when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC)) + .thenReturn(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); + when(mMockAudioService.isInCommunication()).thenReturn(false); + when(mMockAudioService.hasMediaDynamicPolicy()).thenReturn(false); + when(mMockAudioService.hasAudioFocusUsers()).thenReturn(false); + + // first connection + mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1); + Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); + + // disconnection + mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice, + BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1); + if (delayAfterDisconnection > 0) { + Thread.sleep(delayAfterDisconnection); + } + + // reconnection + mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2); + Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS); + + // Verify disconnection has been cancelled and we're seeing two connections attempts, + // with the device connected at the end of the test + verify(mSpyDevInventory, times(2)).onSetA2dpSinkConnectionState( + any(BtHelper.BluetoothA2dpDeviceInfo.class), + ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED)); + Assert.assertTrue("Mock device not connected", + mSpyDevInventory.isA2dpDeviceConnected(mFakeBtDevice)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java index 29cbf988fd56..3da2fd3b6a8e 100644 --- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java @@ -18,7 +18,6 @@ package com.android.server.backup; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; @@ -44,6 +43,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.os.ConditionVariable; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.Process; @@ -70,7 +70,7 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @SmallTest @@ -136,7 +136,7 @@ public class TrampolineTest { SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>(); serviceUsers.append(UserHandle.USER_SYSTEM, mUserBackupManagerService); serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService); - when(mBackupManagerServiceMock.getServiceUsers()).thenReturn(serviceUsers); + when(mBackupManagerServiceMock.getUserServices()).thenReturn(serviceUsers); when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock); when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock); @@ -182,37 +182,76 @@ public class TrampolineTest { } @Test - public void initializeService_successfullyInitializesBackupService() { - mTrampoline.initializeService(); - + public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() { assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); } @Test - public void initializeService_globallyDisabled_nonInitialized() { + public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() { + when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); TrampolineTestable.sBackupDisabled = true; TrampolineTestable trampoline = new TrampolineTestable(mContextMock); + ConditionVariable unlocked = new ConditionVariable(false); - trampoline.initializeService(); + trampoline.onUnlockUser(NON_USER_SYSTEM); - assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); + trampoline.getBackupHandler().post(unlocked::open); + unlocked.block(); + assertNull(trampoline.getUserService(NON_USER_SYSTEM)); } @Test - public void initializeService_doesNotStartServiceForUsers() { - mTrampoline.initializeService(); + public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() { + when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); + TrampolineTestable.sBackupDisabled = true; + TrampolineTestable trampoline = new TrampolineTestable(mContextMock); + ConditionVariable unlocked = new ConditionVariable(false); - verify(mBackupManagerServiceMock, never()).startServiceForUser(anyInt()); + trampoline.onUnlockUser(UserHandle.USER_SYSTEM); + + trampoline.getBackupHandler().post(unlocked::open); + unlocked.block(); + assertNull(trampoline.getUserService(UserHandle.USER_SYSTEM)); } @Test - public void isBackupServiceActive_calledBeforeInitialize_returnsFalse() { - assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); + public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() { + when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); + TrampolineTestable.sBackupDisabled = false; + TrampolineTestable trampoline = new TrampolineTestable(mContextMock); + trampoline.setBackupServiceActive(NON_USER_SYSTEM, false); + ConditionVariable unlocked = new ConditionVariable(false); + + trampoline.onUnlockUser(NON_USER_SYSTEM); + + trampoline.getBackupHandler().post(unlocked::open); + unlocked.block(); + assertNull(trampoline.getUserService(NON_USER_SYSTEM)); + verify(mBackupManagerServiceMock, never()).startServiceForUser(NON_USER_SYSTEM); + } + + @Test + public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue() + throws Exception { + TrampolineTestable.sBackupDisabled = true; + Trampoline trampoline = new TrampolineTestable(mContextMock); + trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue() + throws Exception { + TrampolineTestable.sBackupDisabled = true; + Trampoline trampoline = new TrampolineTestable(mContextMock); + trampoline.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertFalse(trampoline.isBackupServiceActive(NON_USER_SYSTEM)); } @Test public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); @@ -220,7 +259,6 @@ public class TrampolineTest { @Test public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); @@ -229,7 +267,6 @@ public class TrampolineTest { @Test public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -239,7 +276,6 @@ public class TrampolineTest { @Test public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); // Don't activate non-system user. @@ -250,7 +286,6 @@ public class TrampolineTest { public void isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -261,7 +296,6 @@ public class TrampolineTest { public void isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true); assertTrue(mTrampoline.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM)); @@ -269,7 +303,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() { - mTrampoline.initializeService(); TrampolineTestable.sCallingUid = Process.SYSTEM_UID; mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); @@ -279,7 +312,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() { - mTrampoline.initializeService(); TrampolineTestable.sCallingUid = Process.ROOT_UID; mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); @@ -289,7 +321,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() { - mTrampoline.initializeService(); TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID; try { @@ -302,7 +333,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() { when(mUserInfoMock.isManagedProfile()).thenReturn(true); - mTrampoline.initializeService(); TrampolineTestable.sCallingUid = Process.SYSTEM_UID; mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -313,7 +343,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() { when(mUserInfoMock.isManagedProfile()).thenReturn(true); - mTrampoline.initializeService(); TrampolineTestable.sCallingUid = Process.ROOT_UID; mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -324,7 +353,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() { when(mUserInfoMock.isManagedProfile()).thenReturn(true); - mTrampoline.initializeService(); TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID; try { @@ -339,7 +367,6 @@ public class TrampolineTest { doThrow(new SecurityException()) .when(mContextMock) .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString()); - mTrampoline.initializeService(); try { mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -354,7 +381,6 @@ public class TrampolineTest { .when(mContextMock) .enforceCallingOrSelfPermission( eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString()); - mTrampoline.initializeService(); try { mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -367,7 +393,6 @@ public class TrampolineTest { public void setBackupServiceActive_backupDisabled_ignored() { TrampolineTestable.sBackupDisabled = true; TrampolineTestable trampoline = new TrampolineTestable(mContextMock); - trampoline.initializeService(); trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); @@ -376,19 +401,15 @@ public class TrampolineTest { @Test public void setBackupServiceActive_alreadyActive_ignored() { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - assertEquals(1, mTrampoline.getCreateServiceCallsCount()); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - assertEquals(1, mTrampoline.getCreateServiceCallsCount()); } @Test public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); @@ -397,7 +418,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); @@ -406,7 +426,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated() throws IOException { - mTrampoline.initializeService(); assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); @@ -416,7 +435,6 @@ public class TrampolineTest { @Test public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -425,7 +443,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() { - mTrampoline.initializeService(); int otherUser = NON_USER_SYSTEM + 1; File activateFile = new File(mTestDir, "activate-" + otherUser); TrampolineTestable.sActivatedFiles.append(otherUser, activateFile); @@ -440,7 +457,6 @@ public class TrampolineTest { @Test public void setBackupServiceActive_forNonSystemUser_remembersActivated() { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); @@ -450,7 +466,6 @@ public class TrampolineTest { @Test public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() { - mTrampoline.initializeService(); mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false); @@ -460,8 +475,6 @@ public class TrampolineTest { @Test public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() { - mTrampoline.initializeService(); - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false); @@ -470,15 +483,7 @@ public class TrampolineTest { } @Test - public void dataChanged_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.dataChanged(PACKAGE_NAME); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void dataChangedForUser_forwarded() throws Exception { - mTrampoline.initializeService(); - mTrampoline.dataChangedForUser(mUserId, PACKAGE_NAME); verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME); @@ -487,7 +492,6 @@ public class TrampolineTest { @Test public void dataChanged_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.dataChanged(PACKAGE_NAME); @@ -495,14 +499,7 @@ public class TrampolineTest { } @Test - public void clearBackupData_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void clearBackupDataForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.clearBackupDataForUser(mUserId, TRANSPORT_NAME, PACKAGE_NAME); @@ -512,7 +509,6 @@ public class TrampolineTest { @Test public void clearBackupData_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME); @@ -520,14 +516,7 @@ public class TrampolineTest { } @Test - public void agentConnected_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void agentConnectedForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.agentConnectedForUser(mUserId, PACKAGE_NAME, mAgentMock); @@ -537,7 +526,6 @@ public class TrampolineTest { @Test public void agentConnected_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock); @@ -545,14 +533,7 @@ public class TrampolineTest { } @Test - public void agentDisconnected_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.agentDisconnected(PACKAGE_NAME); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void agentDisconnectedForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.agentDisconnectedForUser(mUserId, PACKAGE_NAME); @@ -562,7 +543,6 @@ public class TrampolineTest { @Test public void agentDisconnected_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.agentDisconnected(PACKAGE_NAME); @@ -570,14 +550,7 @@ public class TrampolineTest { } @Test - public void restoreAtInstall_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.restoreAtInstall(PACKAGE_NAME, 123); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void restoreAtInstallForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.restoreAtInstallForUser(mUserId, PACKAGE_NAME, 123); @@ -587,7 +560,6 @@ public class TrampolineTest { @Test public void restoreAtInstall_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.restoreAtInstall(PACKAGE_NAME, 123); @@ -595,14 +567,7 @@ public class TrampolineTest { } @Test - public void setBackupEnabled_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.setBackupEnabled(true); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void setBackupEnabledForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupEnabledForUser(mUserId, true); @@ -612,7 +577,6 @@ public class TrampolineTest { @Test public void setBackupEnabled_forwardedToCallingUserId() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.setBackupEnabled(true); @@ -620,14 +584,7 @@ public class TrampolineTest { } @Test - public void setAutoRestore_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.setAutoRestore(true); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void setAutoRestoreForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.setAutoRestoreForUser(mUserId, true); @@ -637,7 +594,6 @@ public class TrampolineTest { @Test public void setAutoRestore_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.setAutoRestore(true); @@ -645,14 +601,7 @@ public class TrampolineTest { } @Test - public void isBackupEnabled_calledBeforeInitialize_ignored() throws Exception { - assertFalse(mTrampoline.isBackupEnabled()); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void isBackupEnabledForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.isBackupEnabledForUser(mUserId); @@ -662,7 +611,6 @@ public class TrampolineTest { @Test public void isBackupEnabled_forwardedToCallingUserId() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.isBackupEnabled(); @@ -670,40 +618,19 @@ public class TrampolineTest { } @Test - public void setBackupPassword_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void setBackupPassword_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD); verify(mBackupManagerServiceMock).setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD); } @Test - public void hasBackupPassword_calledBeforeInitialize_ignored() throws Exception { - assertFalse(mTrampoline.hasBackupPassword()); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void hasBackupPassword_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.hasBackupPassword(); verify(mBackupManagerServiceMock).hasBackupPassword(); } @Test - public void backupNow_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.backupNow(); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void backupNowForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.backupNowForUser(mUserId); @@ -713,7 +640,6 @@ public class TrampolineTest { @Test public void backupNow_forwardedToCallingUserId() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.backupNow(); @@ -721,16 +647,7 @@ public class TrampolineTest { } @Test - public void adbBackup_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true, - true, true, true, true, true, true, - PACKAGE_NAMES); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void adbBackup_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true, true, true, true, true, true, true, PACKAGE_NAMES); @@ -739,14 +656,7 @@ public class TrampolineTest { } @Test - public void fullTransportBackup_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void fullTransportBackupForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES); @@ -754,29 +664,13 @@ public class TrampolineTest { } @Test - public void adbRestore_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void adbRestore_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock); verify(mBackupManagerServiceMock).adbRestore(mUserId, mParcelFileDescriptorMock); } @Test - public void acknowledgeFullBackupOrRestore_calledBeforeInitialize_ignored() - throws Exception { - mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD, - mFullBackupRestoreObserverMock); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void acknowledgeFullBackupOrRestoreForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.acknowledgeFullBackupOrRestoreForUser( mUserId, @@ -799,7 +693,6 @@ public class TrampolineTest { @Test public void acknowledgeFullBackupOrRestore_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD, mFullBackupRestoreObserverMock); @@ -815,15 +708,8 @@ public class TrampolineTest { } @Test - public void getCurrentTransport_calledBeforeInitialize_ignored() throws Exception { - assertNull(mTrampoline.getCurrentTransport()); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void getCurrentTransportForUser_forwarded() throws Exception { when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME); - mTrampoline.initializeService(); assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransportForUser(mUserId)); verify(mBackupManagerServiceMock).getCurrentTransport(mUserId); @@ -833,22 +719,14 @@ public class TrampolineTest { public void getCurrentTransport_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME); - mTrampoline.initializeService(); assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransport()); verify(mBackupManagerServiceMock).getCurrentTransport(mUserId); } @Test - public void listAllTransports_calledBeforeInitialize_ignored() throws Exception { - assertNull(mTrampoline.listAllTransports()); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void listAllTransportsForUser_forwarded() throws Exception { when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS); - mTrampoline.initializeService(); assertEquals(TRANSPORTS, mTrampoline.listAllTransportsForUser(mUserId)); verify(mBackupManagerServiceMock).listAllTransports(mUserId); @@ -859,62 +737,31 @@ public class TrampolineTest { public void listAllTransports_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS); - mTrampoline.initializeService(); assertEquals(TRANSPORTS, mTrampoline.listAllTransports()); verify(mBackupManagerServiceMock).listAllTransports(mUserId); } @Test - public void listAllTransportComponentsForUser_calledBeforeInitialize_ignored() - throws Exception { - assertNull(mTrampoline.listAllTransportComponentsForUser(mUserId)); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void listAllTransportComponentsForUser_forwarded() throws Exception { when(mBackupManagerServiceMock.listAllTransportComponents(mUserId)).thenReturn( TRANSPORT_COMPONENTS); - mTrampoline.initializeService(); assertEquals(TRANSPORT_COMPONENTS, mTrampoline.listAllTransportComponentsForUser(mUserId)); verify(mBackupManagerServiceMock).listAllTransportComponents(mUserId); } @Test - public void getTransportWhitelist_calledBeforeInitialize_ignored() throws Exception { - assertNull(mTrampoline.getTransportWhitelist()); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void getTransportWhitelist_forwarded() { when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS); - mTrampoline.initializeService(); assertEquals(TRANSPORTS, mTrampoline.getTransportWhitelist()); verify(mBackupManagerServiceMock).getTransportWhitelist(); } @Test - public void updateTransportAttributesForUser_calledBeforeInitialize_ignored() { - mTrampoline.updateTransportAttributesForUser( - mUserId, - TRANSPORT_COMPONENT_NAME, - TRANSPORT_NAME, - null, - "Transport Destination", - null, - "Data Management"); - - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void updateTransportAttributesForUser_forwarded() { when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS); - mTrampoline.initializeService(); mTrampoline.updateTransportAttributesForUser( mUserId, @@ -937,14 +784,7 @@ public class TrampolineTest { } @Test - public void selectBackupTransport_calledBeforeInitialize_ignored() throws RemoteException { - mTrampoline.selectBackupTransport(TRANSPORT_NAME); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void selectBackupTransportForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.selectBackupTransportForUser(mUserId, TRANSPORT_NAME); @@ -954,7 +794,6 @@ public class TrampolineTest { @Test public void selectBackupTransport_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.selectBackupTransport(TRANSPORT_NAME); @@ -962,75 +801,56 @@ public class TrampolineTest { } @Test - public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored() + public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed() throws Exception { - LinkedBlockingQueue<Integer> q = new LinkedBlockingQueue(); - - mTrampoline.selectBackupTransportAsyncForUser( - mUserId, - TRANSPORT_COMPONENT_NAME, - new ISelectBackupTransportCallback() { + when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); + CompletableFuture<Integer> future = new CompletableFuture<>(); + ISelectBackupTransportCallback listener = + new ISelectBackupTransportCallback.Stub() { @Override - public void onSuccess(String transportName) throws RemoteException { - + public void onSuccess(String transportName) { + future.completeExceptionally(new AssertionError()); } - @Override - public void onFailure(int reason) throws RemoteException { - q.offer(reason); + public void onFailure(int reason) { + future.complete(reason); } + }; - @Override - public IBinder asBinder() { - return null; - } - }); + mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); - verifyNoMoreInteractions(mBackupManagerServiceMock); - Integer errorCode = q.poll(5, TimeUnit.SECONDS); - assertNotNull(errorCode); - assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) errorCode); + assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS)); } @Test - public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored_nullListener() + public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow() throws Exception { mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null); - verifyNoMoreInteractions(mBackupManagerServiceMock); // No crash. } @Test - public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored_listenerThrows() + public void + selectBackupTransportAsyncForUser_beforeUserUnlockedWithThrowingListener_doesNotThrow() throws Exception { - mTrampoline.selectBackupTransportAsyncForUser( - mUserId, - TRANSPORT_COMPONENT_NAME, - new ISelectBackupTransportCallback() { + ISelectBackupTransportCallback.Stub listener = + new ISelectBackupTransportCallback.Stub() { @Override - public void onSuccess(String transportName) throws RemoteException { - - } - + public void onSuccess(String transportName) {} @Override public void onFailure(int reason) throws RemoteException { - throw new RemoteException("Crash"); + throw new RemoteException(); } + }; - @Override - public IBinder asBinder() { - return null; - } - }); + mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); - verifyNoMoreInteractions(mBackupManagerServiceMock); // No crash. } @Test public void selectBackupTransportAsyncForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null); @@ -1039,17 +859,10 @@ public class TrampolineTest { } @Test - public void getConfigurationIntent_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.getConfigurationIntent(TRANSPORT_NAME); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void getConfigurationIntentForUser_forwarded() throws Exception { Intent configurationIntentStub = new Intent(); when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn( configurationIntentStub); - mTrampoline.initializeService(); assertEquals( configurationIntentStub, @@ -1063,23 +876,15 @@ public class TrampolineTest { Intent configurationIntentStub = new Intent(); when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn( configurationIntentStub); - mTrampoline.initializeService(); assertEquals(configurationIntentStub, mTrampoline.getConfigurationIntent(TRANSPORT_NAME)); verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME); } @Test - public void getDestinationString_calledBeforeInitialize_ignored() throws Exception { - assertNull(mTrampoline.getDestinationString(TRANSPORT_NAME)); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void getDestinationStringForUser_forwarded() throws Exception { when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn( DESTINATION_STRING); - mTrampoline.initializeService(); assertEquals( DESTINATION_STRING, @@ -1093,23 +898,15 @@ public class TrampolineTest { when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn( DESTINATION_STRING); - mTrampoline.initializeService(); assertEquals(DESTINATION_STRING, mTrampoline.getDestinationString(TRANSPORT_NAME)); verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME); } @Test - public void getDataManagementIntent_calledBeforeInitialize_ignored() throws Exception { - assertNull(mTrampoline.getDataManagementIntent(TRANSPORT_NAME)); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void getDataManagementIntentForUser_forwarded() throws Exception { Intent dataManagementIntent = new Intent(); when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn( dataManagementIntent); - mTrampoline.initializeService(); assertEquals( dataManagementIntent, @@ -1123,23 +920,15 @@ public class TrampolineTest { Intent dataManagementIntent = new Intent(); when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn( dataManagementIntent); - mTrampoline.initializeService(); assertEquals(dataManagementIntent, mTrampoline.getDataManagementIntent(TRANSPORT_NAME)); verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME); } @Test - public void getDataManagementLabelForUser_calledBeforeInitialize_ignored() throws Exception { - assertNull(mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME)); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void getDataManagementLabelForUser_forwarded() throws Exception { when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn( DATA_MANAGEMENT_LABEL); - mTrampoline.initializeService(); assertEquals( DATA_MANAGEMENT_LABEL, @@ -1148,14 +937,7 @@ public class TrampolineTest { } @Test - public void beginRestoreSession_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void beginRestoreSessionForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME); @@ -1164,15 +946,8 @@ public class TrampolineTest { } @Test - public void opComplete_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.opComplete(1, 2); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void opComplete_forwarded() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.opComplete(1, 2); @@ -1180,49 +955,27 @@ public class TrampolineTest { } @Test - public void getAvailableRestoreTokenForUser_calledBeforeInitialize_ignored() { - assertEquals(0, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME)); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void getAvailableRestoreTokenForUser_forwarded() { when(mBackupManagerServiceMock.getAvailableRestoreToken(mUserId, PACKAGE_NAME)) .thenReturn(123L); - mTrampoline.initializeService(); assertEquals(123, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME)); verify(mBackupManagerServiceMock).getAvailableRestoreToken(mUserId, PACKAGE_NAME); } @Test - public void isAppEligibleForBackupForUser_calledBeforeInitialize_ignored() { - assertFalse(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME)); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void isAppEligibleForBackupForUser_forwarded() { when(mBackupManagerServiceMock.isAppEligibleForBackup(mUserId, PACKAGE_NAME)) .thenReturn(true); - mTrampoline.initializeService(); assertTrue(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME)); verify(mBackupManagerServiceMock).isAppEligibleForBackup(mUserId, PACKAGE_NAME); } @Test - public void requestBackup_calledBeforeInitialize_ignored() throws RemoteException { - assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, mTrampoline.requestBackup( - PACKAGE_NAMES, mBackupObserverMock, mBackupManagerMonitorMock, 123)); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void requestBackupForUser_forwarded() throws Exception { when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES, mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456); - mTrampoline.initializeService(); assertEquals(456, mTrampoline.requestBackupForUser(mUserId, PACKAGE_NAMES, mBackupObserverMock, mBackupManagerMonitorMock, 123)); @@ -1235,7 +988,6 @@ public class TrampolineTest { TrampolineTestable.sCallingUserId = mUserId; when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES, mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456); - mTrampoline.initializeService(); assertEquals(456, mTrampoline.requestBackup(PACKAGE_NAMES, mBackupObserverMock, mBackupManagerMonitorMock, 123)); @@ -1244,14 +996,7 @@ public class TrampolineTest { } @Test - public void cancelBackups_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.cancelBackups(); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void cancelBackupsForUser_forwarded() throws Exception { - mTrampoline.initializeService(); mTrampoline.cancelBackupsForUser(mUserId); @@ -1261,7 +1006,6 @@ public class TrampolineTest { @Test public void cancelBackups_forwardedToCallingUserId() throws Exception { TrampolineTestable.sCallingUserId = mUserId; - mTrampoline.initializeService(); mTrampoline.cancelBackups(); @@ -1269,30 +1013,16 @@ public class TrampolineTest { } @Test - public void beginFullBackup_calledBeforeInitialize_ignored() throws Exception { - mTrampoline.beginFullBackup(mUserId, new FullBackupJob()); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void beginFullBackup_forwarded() throws Exception { FullBackupJob fullBackupJob = new FullBackupJob(); when(mBackupManagerServiceMock.beginFullBackup(mUserId, fullBackupJob)).thenReturn(true); - mTrampoline.initializeService(); assertTrue(mTrampoline.beginFullBackup(mUserId, fullBackupJob)); verify(mBackupManagerServiceMock).beginFullBackup(mUserId, fullBackupJob); } @Test - public void endFullBackup_calledBeforeInitialize_ignored() { - mTrampoline.endFullBackup(mUserId); - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test public void endFullBackup_forwarded() { - mTrampoline.initializeService(); mTrampoline.endFullBackup(mUserId); verify(mBackupManagerServiceMock).endFullBackup(mUserId); } @@ -1302,7 +1032,6 @@ public class TrampolineTest { when(mContextMock.checkCallingOrSelfPermission( android.Manifest.permission.DUMP)).thenReturn( PackageManager.PERMISSION_DENIED); - mTrampoline.initializeService(); mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]); @@ -1310,26 +1039,30 @@ public class TrampolineTest { } @Test - public void dump_calledBeforeInitialize_ignored() { + public void dump_callerHasPermission_forwarded() { when(mContextMock.checkCallingOrSelfPermission( android.Manifest.permission.DUMP)).thenReturn( PackageManager.PERMISSION_GRANTED); - mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]); + mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, null); - verifyNoMoreInteractions(mBackupManagerServiceMock); + verify(mBackupManagerServiceMock).dump(mFileDescriptorStub, mPrintWriterMock, null); } - @Test - public void dump_callerHasPermission_forwarded() { - when(mContextMock.checkCallingOrSelfPermission( - android.Manifest.permission.DUMP)).thenReturn( - PackageManager.PERMISSION_GRANTED); - mTrampoline.initializeService(); + public void testGetUserForAncestralSerialNumber() { + TrampolineTestable.sBackupDisabled = false; + Trampoline trampoline = new TrampolineTestable(mContextMock); - mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, null); + trampoline.getUserForAncestralSerialNumber(0L); + verify(mBackupManagerServiceMock).getUserForAncestralSerialNumber(anyInt()); + } - verify(mBackupManagerServiceMock).dump(mFileDescriptorStub, mPrintWriterMock, null); + public void testGetUserForAncestralSerialNumber_whenDisabled() { + TrampolineTestable.sBackupDisabled = true; + Trampoline trampoline = new TrampolineTestable(mContextMock); + + trampoline.getUserForAncestralSerialNumber(0L); + verify(mBackupManagerServiceMock, never()).getUserForAncestralSerialNumber(anyInt()); } private static class TrampolineTestable extends Trampoline { @@ -1341,10 +1074,10 @@ public class TrampolineTest { static SparseArray<File> sActivatedFiles = new SparseArray<>(); static SparseArray<File> sRememberActivatedFiles = new SparseArray<>(); static UserManager sUserManagerMock = null; - private int mCreateServiceCallsCount = 0; TrampolineTestable(Context context) { super(context); + mService = sBackupManagerServiceMock; } @Override @@ -1353,7 +1086,7 @@ public class TrampolineTest { } @Override - public boolean isBackupDisabled() { + protected boolean isBackupDisabled() { return sBackupDisabled; } @@ -1382,18 +1115,8 @@ public class TrampolineTest { } @Override - protected BackupManagerService createBackupManagerService() { - mCreateServiceCallsCount++; - return sBackupManagerServiceMock; - } - - @Override protected void postToHandler(Runnable runnable) { runnable.run(); } - - int getCreateServiceCallsCount() { - return mCreateServiceCallsCount; - } } } diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index 0309dbeea2ca..cae7b57580bb 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -273,7 +273,7 @@ public class JobStoreTest { invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period). final Pair<Long, Long> persistedExecutionTimesUTC = new Pair<>(rtcNow, rtcNow + ONE_HOUR); final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", - 0 /* sourceUserId */, 0, 0, "someTag", + 0 /* sourceUserId */, 0, "someTag", invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, persistedExecutionTimesUTC, 0 /* innerFlagg */); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java index f9e4c347422a..8e0d7be5f44f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java @@ -311,8 +311,6 @@ public class LockSettingsStorageTests extends AndroidTestCase { public void testFileLocation_Owner() { LockSettingsStorage storage = new LockSettingsStorage(getContext()); - assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0)); - assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0)); assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0)); assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0)); } @@ -436,10 +434,8 @@ public class LockSettingsStorageTests extends AndroidTestCase { PAYLOAD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD).toBytes(); CredentialHash deserialized = CredentialHash.fromBytes(serialized); - assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version); assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type); assertArrayEquals(PAYLOAD, deserialized.hash); - assertFalse(deserialized.isBaseZeroPattern); } public void testCredentialHash_unserialize_versionGatekeeper() { @@ -453,10 +449,8 @@ public class LockSettingsStorageTests extends AndroidTestCase { }; CredentialHash deserialized = CredentialHash.fromBytes(serialized); - assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version); assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type); assertArrayEquals(PAYLOAD, deserialized.hash); - assertFalse(deserialized.isBaseZeroPattern); // Make sure the constants we use on the wire do not change. assertEquals(-1, LockPatternUtils.CREDENTIAL_TYPE_NONE); diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 65f9e321e084..75e5847abe90 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -323,6 +323,24 @@ public class AppsFilterTest { assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, null, target, 0)); } + @Test + public void testNoTargetPackage_filters() { + final AppsFilter appsFilter = + new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new String[]{}, false); + + PackageSetting target = new PackageSettingBuilder() + .setName("com.some.package") + .setCodePath("/") + .setResourcePath("/") + .setPVersionCode(1L) + .build(); + PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package", new Intent("TEST_ACTION"))).build(); + + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + } + private PackageSettingBuilder simulateAddPackage(AppsFilter filter, PackageBuilder newPkgBuilder) { PackageParser.Package newPkg = newPkgBuilder.build(); diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java index dd3d8b929793..05905d94dda7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java @@ -70,6 +70,14 @@ public class ScanTests { PackageAbiHelper mMockPackageAbiHelper; @Mock UserManagerInternal mMockUserManager; + @Mock + PackageManagerService.Injector mMockInjector; + + @Before + public void setupInjector() { + when(mMockInjector.getAbiHelper()).thenReturn(mMockPackageAbiHelper); + when(mMockInjector.getUserManagerInternal()).thenReturn(mMockUserManager); + } @Before public void setupDefaultUser() { @@ -401,7 +409,7 @@ public class ScanTests { final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI( createBasicScanRequestBuilder(basicPackage).build(), - new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper), + mMockInjector, true /*isUnderFactoryTest*/, System.currentTimeMillis()); @@ -448,7 +456,7 @@ public class ScanTests { PackageManagerService.ScanRequest scanRequest) throws PackageManagerException { return PackageManagerService.scanPackageOnlyLI( scanRequest, - new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper), + mMockInjector, false /*isUnderFactoryTest*/, System.currentTimeMillis()); } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 1bda412f2f89..88de250e4b0d 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -23,7 +23,10 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; @@ -59,6 +62,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; +import android.view.Display; import androidx.test.InstrumentationRegistry; @@ -157,6 +161,10 @@ public class PowerManagerServiceTest { mResourcesSpy = spy(mContextSpy.getResources()); when(mContextSpy.getResources()).thenReturn(mResourcesSpy); + when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true); + } + + private PowerManagerService createService() { mService = new PowerManagerService(mContextSpy, new Injector() { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, @@ -166,7 +174,7 @@ public class PowerManagerServiceTest { @Override SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) { - return mock(SuspendBlocker.class); + return super.createSuspendBlocker(service, name); } @Override @@ -191,6 +199,7 @@ public class PowerManagerServiceTest { return mAmbientDisplayConfigurationMock; } }); + return mService; } @After @@ -262,6 +271,7 @@ public class PowerManagerServiceTest { @Test public void testUpdatePowerScreenPolicy_UpdateDisplayPowerRequest() { + createService(); mService.updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest); assertThat(mDisplayPowerRequest.lowPowerMode).isEqualTo(BATTERY_SAVER_ENABLED); assertThat(mDisplayPowerRequest.screenLowPowerBrightnessFactor) @@ -270,6 +280,7 @@ public class PowerManagerServiceTest { @Test public void testGetLastShutdownReasonInternal() { + createService(); SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "shutdown,thermal"); int reason = mService.getLastShutdownReasonInternal(TEST_LAST_REBOOT_PROPERTY); SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, ""); @@ -278,6 +289,7 @@ public class PowerManagerServiceTest { @Test public void testGetDesiredScreenPolicy_WithVR() throws Exception { + createService(); // Brighten up the screen mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0); assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo( @@ -307,11 +319,13 @@ public class PowerManagerServiceTest { @Test public void testWakefulnessAwake_InitialValue() throws Exception { + createService(); assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); } @Test public void testWakefulnessSleep_NoDozeSleepFlag() throws Exception { + createService(); // Start with AWAKE state startSystem(); assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); @@ -324,6 +338,7 @@ public class PowerManagerServiceTest { @Test public void testWakefulnessAwake_AcquireCausesWakeup() throws Exception { + createService(); startSystem(); forceSleep(); @@ -355,6 +370,7 @@ public class PowerManagerServiceTest { @Test public void testWakefulnessAwake_IPowerManagerWakeUp() throws Exception { + createService(); startSystem(); forceSleep(); mService.getBinderServiceInstance().wakeUp(SystemClock.uptimeMillis(), @@ -369,6 +385,8 @@ public class PowerManagerServiceTest { @Test public void testWakefulnessAwake_ShouldWakeUpWhenPluggedIn() throws Exception { boolean powerState; + + createService(); startSystem(); forceSleep(); @@ -444,6 +462,7 @@ public class PowerManagerServiceTest { @Test public void testWakefulnessDoze_goToSleep() throws Exception { + createService(); // Start with AWAKE state startSystem(); assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); @@ -457,6 +476,7 @@ public class PowerManagerServiceTest { @Test public void testWasDeviceIdleFor_true() { int interval = 1000; + createService(); mService.onUserActivity(); SystemClock.sleep(interval + 1 /* just a little more */); assertThat(mService.wasDeviceIdleForInternal(interval)).isTrue(); @@ -465,12 +485,14 @@ public class PowerManagerServiceTest { @Test public void testWasDeviceIdleFor_false() { int interval = 1000; + createService(); mService.onUserActivity(); assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse(); } @Test public void testForceSuspend_putsDeviceToSleep() { + createService(); mService.systemReady(null); mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); @@ -497,6 +519,8 @@ public class PowerManagerServiceTest { final int flags = PowerManager.PARTIAL_WAKE_LOCK; final String pkg = mContextSpy.getOpPackageName(); + createService(); + // Set up the Notification mock to keep track of the wakelocks that are currently // active or disabled. We'll use this to verify that wakelocks are disabled when // they should be. @@ -541,7 +565,54 @@ public class PowerManagerServiceTest { @Test public void testForceSuspend_forceSuspendFailurePropogated() { + createService(); when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false); assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse(); } + + @Test + public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() throws Exception { + final String suspendBlockerName = "PowerManagerService.Display"; + final String tag = "acq_causes_wakeup"; + final String packageName = "pkg.name"; + final IBinder token = new Binder(); + + final boolean[] isAcquired = new boolean[1]; + doAnswer(inv -> { + if (suspendBlockerName.equals(inv.getArguments()[0])) { + isAcquired[0] = false; + } + return null; + }).when(mNativeWrapperMock).nativeReleaseSuspendBlocker(any()); + + doAnswer(inv -> { + if (suspendBlockerName.equals(inv.getArguments()[0])) { + isAcquired[0] = true; + } + return null; + }).when(mNativeWrapperMock).nativeAcquireSuspendBlocker(any()); + + // Need to create the service after we stub the mocks for this test because some of the + // mocks are used during the constructor. + createService(); + + // Start with AWAKE state + startSystem(); + assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertTrue(isAcquired[0]); + + // Take a nap and verify we no longer hold the blocker + int flags = PowerManager.DOZE_WAKE_LOCK; + mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, + null /* workSource */, null /* historyTag */); + mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0); + assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING); + assertFalse(isAcquired[0]); + + // Override the display state by DreamManager and verify is reacquires the blocker. + mService.getLocalServiceInstance() + .setDozeOverrideFromDreamManager(Display.STATE_ON, PowerManager.BRIGHTNESS_DEFAULT); + assertTrue(isAcquired[0]); + } } diff --git a/services/tests/servicestests/test-apps/JobTestApp/Android.bp b/services/tests/servicestests/test-apps/JobTestApp/Android.bp index ae1eca7ba707..b29e187576c3 100644 --- a/services/tests/servicestests/test-apps/JobTestApp/Android.bp +++ b/services/tests/servicestests/test-apps/JobTestApp/Android.bp @@ -17,8 +17,6 @@ android_test_helper_app { sdk_version: "current", - test_suites: ["device-tests"], - srcs: ["**/*.java"], dex_preopt: { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index f14e8d216cab..c1c0a308e48a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -2005,6 +2005,73 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception { + final NotificationRecord notification = generateNotificationRecord( + mTestNotificationChannel, 1, null, true); + mService.addNotification(notification); + when(mSnoozeHelper.getNotification(any())).thenReturn(notification); + + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = + mService.new SnoozeNotificationRunnable( + notification.getKey(), 100, null); + snoozeNotificationRunnable.run(); + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = + mService.new SnoozeNotificationRunnable( + notification.getKey(), 100, null); + snoozeNotificationRunnable.run(); + + // snooze twice + verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); + } + + @Test + public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() throws Exception { + final NotificationRecord notification = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + mService.addNotification(notification); + when(mSnoozeHelper.getNotification(any())).thenReturn(notification); + + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = + mService.new SnoozeNotificationRunnable( + notification.getKey(), 100, null); + snoozeNotificationRunnable.run(); + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = + mService.new SnoozeNotificationRunnable( + notification.getKey(), 100, null); + snoozeNotificationRunnable.run(); + + // snooze twice + verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); + } + + @Test + public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception { + final NotificationRecord notification = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord notification2 = generateNotificationRecord( + mTestNotificationChannel, 2, "group", true); + mService.addNotification(notification); + mService.addNotification(notification2); + when(mSnoozeHelper.getNotification(any())).thenReturn(notification); + when(mSnoozeHelper.getNotifications( + anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>()); + + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = + mService.new SnoozeNotificationRunnable( + notification.getKey(), 100, null); + snoozeNotificationRunnable.run(); + when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt())) + .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2))); + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = + mService.new SnoozeNotificationRunnable( + notification.getKey(), 100, null); + snoozeNotificationRunnable.run(); + + // snooze twice + verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong()); + } + + @Test public void testSnoozeRunnable_snoozeNonGrouped() throws Exception { final NotificationRecord nonGrouped = generateNotificationRecord( mTestNotificationChannel, 1, null, false); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 1e645436e7ea..2e7277f5af01 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -264,6 +264,63 @@ public class SnoozeHelperTest extends UiServiceTestCase { } @Test + public void testGetSnoozedGroupNotifications() throws Exception { + IntArray profileIds = new IntArray(); + profileIds.add(UserHandle.USER_CURRENT); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); + NotificationRecord r = getNotificationRecord("pkg", 1, "tag", + UserHandle.CURRENT, "group", true); + NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag", + UserHandle.CURRENT, "group", true); + NotificationRecord r3 = getNotificationRecord("pkg2", 3, "tag", + UserHandle.CURRENT, "group", true); + NotificationRecord r4 = getNotificationRecord("pkg2", 4, "tag", + UserHandle.CURRENT, "group", true); + mSnoozeHelper.snooze(r, 1000); + mSnoozeHelper.snooze(r2, 1000); + mSnoozeHelper.snooze(r3, 1000); + mSnoozeHelper.snooze(r4, 1000); + + assertEquals(2, + mSnoozeHelper.getNotifications("pkg", "group", UserHandle.USER_CURRENT).size()); + } + + @Test + public void testGetSnoozedNotificationByKey() throws Exception { + IntArray profileIds = new IntArray(); + profileIds.add(UserHandle.USER_CURRENT); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); + NotificationRecord r = getNotificationRecord("pkg", 1, "tag", + UserHandle.CURRENT, "group", true); + NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag", + UserHandle.CURRENT, "group", true); + NotificationRecord r3 = getNotificationRecord("pkg2", 3, "tag", + UserHandle.CURRENT, "group", true); + NotificationRecord r4 = getNotificationRecord("pkg2", 4, "tag", + UserHandle.CURRENT, "group", true); + mSnoozeHelper.snooze(r, 1000); + mSnoozeHelper.snooze(r2, 1000); + mSnoozeHelper.snooze(r3, 1000); + mSnoozeHelper.snooze(r4, 1000); + + assertEquals(r, mSnoozeHelper.getNotification(r.getKey())); + } + + @Test + public void testGetUnSnoozedNotificationByKey() throws Exception { + IntArray profileIds = new IntArray(); + profileIds.add(UserHandle.USER_CURRENT); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); + NotificationRecord r = getNotificationRecord("pkg", 1, "tag", + UserHandle.CURRENT, "group", true); + NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag", + UserHandle.CURRENT, "group", true); + mSnoozeHelper.snooze(r2, 1000); + + assertEquals(null, mSnoozeHelper.getNotification(r.getKey())); + } + + @Test public void repostGroupSummary_onlyFellowGroupChildren() throws Exception { NotificationRecord r = getNotificationRecord( "pkg", 1, "one", UserHandle.SYSTEM, "group1", false); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java new file mode 100644 index 000000000000..d8a9bb0d6237 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 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.wm; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + +import static org.junit.Assert.assertTrue; + +import android.app.Activity; + +import androidx.test.filters.MediumTest; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the {@link ActivityTaskManagerService} class. + * + * Build/Install/Run: + * atest WmTests:ActivityTaskManagerServiceTests + */ +@MediumTest +public class ActivityTaskManagerServiceTests extends ActivityTestsBase { + + @Before + public void setUp() throws Exception { + doReturn(false).when(mService).isBooting(); + doReturn(true).when(mService).isBooted(); + } + + /** Verify that activity is finished correctly upon request. */ + @Test + public void testActivityFinish() { + final TestActivityStack stack = + (TestActivityStack) new StackBuilder(mRootActivityContainer).build(); + final ActivityRecord activity = stack.getChildAt(0).getTopActivity(); + assertTrue("Activity must be finished", mService.finishActivity(activity.appToken, + 0 /* resultCode */, null /* resultData */, + Activity.DONT_FINISH_TASK_WITH_ACTIVITY)); + assertTrue(activity.finishing); + + assertTrue("Duplicate activity finish request must also return 'true'", + mService.finishActivity(activity.appToken, 0 /* resultCode */, + null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY)); + } +} + diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index ecf3acd32d4f..e673a627dcd6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -467,6 +467,7 @@ class ActivityTestsBase { spyOn(getLifecycleManager()); spyOn(getLockTaskController()); + spyOn(getTaskChangeNotificationController()); doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); // allow background activity starts by default doReturn(true).when(this).isBackgroundActivityStartsEnabled(); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index f60241846044..d1dc38273a28 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -207,7 +207,7 @@ public class AppTransitionTests extends WindowTestsBase { final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( runner, 100, 50, true /* changeNeedsSnapshot */); // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid. - adapter.setCallingPid(123); + adapter.setCallingPidUid(123, 456); // Simulate activity finish flows to prepare app transition & set visibility, // make sure transition is set as expected. diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 7f35dac9611a..d9566a3c871d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -504,6 +504,21 @@ public class AppWindowTokenTests extends WindowTestsBase { assertEquals(stackBounds, mToken.getAnimationBounds(STACK_CLIP_BEFORE_ANIM)); } + @Test + public void testHasStartingWindow() { + final WindowManager.LayoutParams attrs = + new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING); + final WindowTestUtils.TestWindowState startingWindow = createWindowState(attrs, mToken); + mToken.startingDisplayed = true; + mToken.addWindow(startingWindow); + assertTrue("Starting window should be present", mToken.hasStartingWindow()); + mToken.startingDisplayed = false; + assertTrue("Starting window should be present", mToken.hasStartingWindow()); + + mToken.removeChild(startingWindow); + assertFalse("Starting window should not be present", mToken.hasStartingWindow()); + } + private void assertHasStartingWindow(AppWindowToken atoken) { assertNotNull(atoken.startingSurface); assertNotNull(atoken.mStartingData); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index c5e7c47919fc..388658dfac88 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -756,7 +756,8 @@ public class DisplayContentTests extends WindowTestsBase { final ISystemGestureExclusionListener.Stub verifier = new ISystemGestureExclusionListener.Stub() { @Override - public void onSystemGestureExclusionChanged(int displayId, Region actual) { + public void onSystemGestureExclusionChanged(int displayId, Region actual, + Region unrestricted) { Region expected = Region.obtain(); expected.set(10, 20, 30, 40); assertEquals(expected, actual); @@ -790,7 +791,14 @@ public class DisplayContentTests extends WindowTestsBase { final Region expected = Region.obtain(); expected.set(20, 30, 40, 50); - assertEquals(expected, dc.calculateSystemGestureExclusion()); + assertEquals(expected, calculateSystemGestureExclusion(dc)); + } + + private Region calculateSystemGestureExclusion(DisplayContent dc) { + Region out = Region.obtain(); + Region unrestricted = Region.obtain(); + dc.calculateSystemGestureExclusion(out, unrestricted); + return out; } @Test @@ -814,7 +822,7 @@ public class DisplayContentTests extends WindowTestsBase { win2.setHasSurface(true); final Region expected = Region.obtain(); - assertEquals(expected, dc.calculateSystemGestureExclusion()); + assertEquals(expected, calculateSystemGestureExclusion(dc)); } @Test @@ -839,7 +847,7 @@ public class DisplayContentTests extends WindowTestsBase { final Region expected = Region.obtain(); expected.set(dc.getBounds()); - assertEquals(expected, dc.calculateSystemGestureExclusion()); + assertEquals(expected, calculateSystemGestureExclusion(dc)); win.setHasSurface(false); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index a1999c901702..b7a85d7bb5b7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -43,6 +43,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static java.lang.Integer.MAX_VALUE; @@ -900,6 +902,46 @@ public class RecentTasksTest extends ActivityTestsBase { true /* showRecents */)); } + @Test + public void addTask_callsTaskNotificationController() { + final TaskRecord task = createTaskBuilder(".Task").build(); + + mRecentTasks.add(task); + mRecentTasks.remove(task); + + TaskChangeNotificationController controller = + mTestService.getTaskChangeNotificationController(); + verify(controller, times(2)).notifyTaskListUpdated(); + } + + @Test + public void removeTask_callsTaskNotificationController() { + final TaskRecord task = createTaskBuilder(".Task").build(); + + mRecentTasks.add(task); + mRecentTasks.remove(task); + + // 2 calls - Once for add and once for remove + TaskChangeNotificationController controller = + mTestService.getTaskChangeNotificationController(); + verify(controller, times(2)).notifyTaskListUpdated(); + } + + @Test + public void removeALlVisibleTask_callsTaskNotificationController_twice() { + final TaskRecord task1 = createTaskBuilder(".Task").build(); + final TaskRecord task2 = createTaskBuilder(".Task2").build(); + + mRecentTasks.add(task1); + mRecentTasks.add(task2); + mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID); + + // 4 calls - Twice for add and twice for remove + TaskChangeNotificationController controller = + mTestService.getTaskChangeNotificationController(); + verify(controller, times(4)).notifyTaskListUpdated(); + } + /** * Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks * should be ordered from least to most recent. diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index cb74c3e32252..74791e2ea97f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -79,7 +79,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { when(mMockRunner.asBinder()).thenReturn(new Binder()); mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */); - mAdapter.setCallingPid(123); + mAdapter.setCallingPidUid(123, 456); mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0); mController = new RemoteAnimationController(mWm, mAdapter, mHandler); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index a7c84a1c28b4..8c56ffaa6314 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -23,12 +23,18 @@ import static com.android.server.wm.ActivityDisplay.POSITION_TOP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.content.pm.ApplicationInfo; import android.platform.test.annotations.Presubmit; +import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; /** * Tests for the {@link WindowProcessController} class. @@ -39,43 +45,89 @@ import org.junit.Test; @Presubmit public class WindowProcessControllerTests extends ActivityTestsBase { + WindowProcessController mWpc; + WindowProcessListener mMockListener; + + @Before + public void setUp() { + mMockListener = mock(WindowProcessListener.class); + mWpc = new WindowProcessController( + mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener); + } + @Test public void testDisplayConfigurationListener() { - final WindowProcessController wpc = new WindowProcessController( - mService, mock(ApplicationInfo.class), null, 0, -1, null, null); + //By default, the process should not listen to any display. - assertEquals(INVALID_DISPLAY, wpc.getDisplayId()); + assertEquals(INVALID_DISPLAY, mWpc.getDisplayId()); // Register to display 1 as a listener. TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer(); - wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); - assertTrue(testActivityDisplay1.containsListener(wpc)); - assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); + assertTrue(testActivityDisplay1.containsListener(mWpc)); + assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId()); // Move to display 2. TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer(); - wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2); - assertFalse(testActivityDisplay1.containsListener(wpc)); - assertTrue(testActivityDisplay2.containsListener(wpc)); - assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2); + assertFalse(testActivityDisplay1.containsListener(mWpc)); + assertTrue(testActivityDisplay2.containsListener(mWpc)); + assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId()); // Null ActivityDisplay will not change anything. - wpc.registerDisplayConfigurationListenerLocked(null); - assertTrue(testActivityDisplay2.containsListener(wpc)); - assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(null); + assertTrue(testActivityDisplay2.containsListener(mWpc)); + assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId()); // Unregister listener will remove the wpc from registered displays. - wpc.unregisterDisplayConfigurationListenerLocked(); - assertFalse(testActivityDisplay1.containsListener(wpc)); - assertFalse(testActivityDisplay2.containsListener(wpc)); - assertEquals(INVALID_DISPLAY, wpc.getDisplayId()); + mWpc.unregisterDisplayConfigurationListenerLocked(); + assertFalse(testActivityDisplay1.containsListener(mWpc)); + assertFalse(testActivityDisplay2.containsListener(mWpc)); + assertEquals(INVALID_DISPLAY, mWpc.getDisplayId()); // Unregistration still work even if the display was removed. - wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); - assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId()); + mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1); + assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId()); mRootActivityContainer.removeChild(testActivityDisplay1); - wpc.unregisterDisplayConfigurationListenerLocked(); - assertEquals(INVALID_DISPLAY, wpc.getDisplayId()); + mWpc.unregisterDisplayConfigurationListenerLocked(); + assertEquals(INVALID_DISPLAY, mWpc.getDisplayId()); + } + + @Test + public void testSetRunningRecentsAnimation() { + mWpc.setRunningRecentsAnimation(true); + mWpc.setRunningRecentsAnimation(false); + mService.mH.runWithScissors(() -> {}, 0); + + InOrder orderVerifier = Mockito.inOrder(mMockListener); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true)); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false)); + } + + @Test + public void testSetRunningRemoteAnimation() { + mWpc.setRunningRemoteAnimation(true); + mWpc.setRunningRemoteAnimation(false); + mService.mH.runWithScissors(() -> {}, 0); + + InOrder orderVerifier = Mockito.inOrder(mMockListener); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true)); + orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false)); + } + + @Test + public void testSetRunningBothAnimations() { + mWpc.setRunningRemoteAnimation(true); + mWpc.setRunningRecentsAnimation(true); + + mWpc.setRunningRecentsAnimation(false); + mWpc.setRunningRemoteAnimation(false); + mService.mH.runWithScissors(() -> {}, 0); + + InOrder orderVerifier = Mockito.inOrder(mMockListener); + orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true)); + orderVerifier.verify(mMockListener, times(1)).setRunningRemoteAnimation(eq(false)); + orderVerifier.verifyNoMoreInteractions(); } private TestActivityDisplay createTestActivityDisplayInContainer() { diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py index 7b3bf3387452..eb582f946958 100755 --- a/startop/scripts/app_startup/app_startup_runner.py +++ b/startop/scripts/app_startup/app_startup_runner.py @@ -32,21 +32,25 @@ import itertools import os import sys import tempfile +from datetime import timedelta from typing import Any, Callable, Iterable, List, NamedTuple, TextIO, Tuple, \ TypeVar, Union, Optional # local import DIR = os.path.abspath(os.path.dirname(__file__)) sys.path.append(os.path.dirname(DIR)) +import lib.cmd_utils as cmd_utils +import lib.print_utils as print_utils +import iorap.compiler as compiler from app_startup.run_app_with_prefetch import PrefetchAppRunner import app_startup.lib.args_utils as args_utils from app_startup.lib.data_frame import DataFrame -import lib.cmd_utils as cmd_utils -import lib.print_utils as print_utils +from app_startup.lib.perfetto_trace_collector import PerfettoTraceCollector # The following command line options participate in the combinatorial generation. # All other arguments have a global effect. -_COMBINATORIAL_OPTIONS = ['package', 'readahead', 'compiler_filter', 'activity'] +_COMBINATORIAL_OPTIONS = ['package', 'readahead', 'compiler_filter', + 'activity', 'trace_duration'] _TRACING_READAHEADS = ['mlock', 'fadvise'] _FORWARD_OPTIONS = {'loop_count': '--count'} _RUN_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -54,9 +58,8 @@ _RUN_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)), CollectorPackageInfo = NamedTuple('CollectorPackageInfo', [('package', str), ('compiler_filter', str)]) -_COLLECTOR_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../iorap/collector') -_COLLECTOR_TIMEOUT_MULTIPLIER = 10 # take the regular --timeout and multiply +_COMPILER_SCRIPT = os.path.join(os.path.dirname(os.path.dirname( + os.path.realpath(__file__))), 'iorap/compiler.py') # by 2; systrace starts up slowly. _UNLOCK_SCREEN_SCRIPT = os.path.join( @@ -70,11 +73,14 @@ RunCommandArgs = NamedTuple('RunCommandArgs', ('timeout', Optional[int]), ('debug', bool), ('simulate', bool), - ('input', Optional[str])]) + ('input', Optional[str]), + ('trace_duration', Optional[timedelta])]) # This must be the only mutable global variable. All other global variables are constants to avoid magic literals. _debug = False # See -d/--debug flag. _DEBUG_FORCE = None # Ignore -d/--debug if this is not none. +_PERFETTO_TRACE_DURATION_MS = 5000 # milliseconds +_PERFETTO_TRACE_DURATION = timedelta(milliseconds=_PERFETTO_TRACE_DURATION_MS) # Type hinting names. T = TypeVar('T') @@ -123,26 +129,15 @@ def parse_options(argv: List[str] = None): optional_named.add_argument('-in', '--inodes', dest='inodes', type=str, action='store', help='Path to inodes file (system/extras/pagecache/pagecache.py -d inodes)') + optional_named.add_argument('--compiler-trace-duration-ms', + dest='trace_duration', + type=lambda ms_str: timedelta(milliseconds=int(ms_str)), + action='append', + help='The trace duration (milliseconds) in ' + 'compilation') return parser.parse_args(argv) -def make_script_command_with_temp_output(script: str, - args: List[str], - **kwargs) -> Tuple[str, TextIO]: - """ - Create a command to run a script given the args. - Appends --count <loop_count> --output <tmp-file-name>. - Returns a tuple (cmd, tmp_file) - """ - tmp_output_file = tempfile.NamedTemporaryFile(mode='r') - cmd = [script] + args - for key, value in kwargs.items(): - cmd += ['--%s' % (key), "%s" % (value)] - if _debug: - cmd += ['--verbose'] - cmd = cmd + ["--output", tmp_output_file.name] - return cmd, tmp_output_file - def key_to_cmdline_flag(key: str) -> str: """Convert key into a command line flag, e.g. 'foo-bars' -> '--foo-bar' """ if key.endswith("s"): @@ -163,26 +158,26 @@ def as_run_command(tpl: NamedTuple) -> List[Union[str, Any]]: args.append(value) return args -def run_collector_script(collector_info: CollectorPackageInfo, - inodes_path: str, - timeout: int, - simulate: bool) -> Tuple[bool, TextIO]: - """Run collector to collect prefetching trace. """ - # collector_args = ["--package", package_name] - collector_args = as_run_command(collector_info) - # TODO: forward --wait_time for how long systrace runs? - # TODO: forward --trace_buffer_size for size of systrace buffer size? - collector_cmd, collector_tmp_output_file = make_script_command_with_temp_output( - _COLLECTOR_SCRIPT, collector_args, inodes=inodes_path) - - collector_timeout = timeout and _COLLECTOR_TIMEOUT_MULTIPLIER * timeout - (collector_passed, collector_script_output) = \ - cmd_utils.execute_arbitrary_command(collector_cmd, - collector_timeout, - shell=False, - simulate=simulate) - - return collector_passed, collector_tmp_output_file +def run_perfetto_collector(collector_info: CollectorPackageInfo, + timeout: int, + simulate: bool) -> Tuple[bool, TextIO]: + """Run collector to collect prefetching trace. + + Returns: + A tuple of whether the collection succeeds and the generated trace file. + """ + tmp_output_file = tempfile.NamedTemporaryFile() + + collector = PerfettoTraceCollector(package=collector_info.package, + activity=None, + compiler_filter=collector_info.compiler_filter, + timeout=timeout, + simulate=simulate, + trace_duration=_PERFETTO_TRACE_DURATION, + save_destination_file_path=tmp_output_file.name) + result = collector.run() + + return result is not None, tmp_output_file def parse_run_script_csv_file(csv_file: TextIO) -> DataFrame: """Parse a CSV file full of integers into a DataFrame.""" @@ -216,6 +211,52 @@ def parse_run_script_csv_file(csv_file: TextIO) -> DataFrame: return DataFrame(d) +def compile_perfetto_trace(inodes_path: str, + perfetto_trace_file: str, + trace_duration: Optional[timedelta]) -> TextIO: + compiler_trace_file = tempfile.NamedTemporaryFile() + argv = [_COMPILER_SCRIPT, '-i', inodes_path, '--perfetto-trace', + perfetto_trace_file, '-o', compiler_trace_file.name] + + if trace_duration is not None: + argv += ['--duration', str(int(trace_duration.total_seconds() + * PerfettoTraceCollector.MS_PER_SEC))] + + print_utils.debug_print(argv) + compiler.main(argv) + return compiler_trace_file + +def execute_run_using_perfetto_trace(collector_info, + run_combos: Iterable[RunCommandArgs], + simulate: bool, + inodes_path: str, + timeout: int) -> DataFrame: + """ Executes run based on perfetto trace. """ + passed, perfetto_trace_file = run_perfetto_collector(collector_info, + timeout, + simulate) + if not passed: + raise RuntimeError('Cannot run perfetto collector!') + + with perfetto_trace_file: + for combos in run_combos: + if combos.readahead in _TRACING_READAHEADS: + if simulate: + compiler_trace_file = tempfile.NamedTemporaryFile() + else: + compiler_trace_file = compile_perfetto_trace(inodes_path, + perfetto_trace_file.name, + combos.trace_duration) + with compiler_trace_file: + combos = combos._replace(input=compiler_trace_file.name) + print_utils.debug_print(combos) + output = PrefetchAppRunner(**combos._asdict()).run() + else: + print_utils.debug_print(combos) + output = PrefetchAppRunner(**combos._asdict()).run() + + yield DataFrame(dict((x, [y]) for x, y in output)) if output else None + def execute_run_combos( grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[RunCommandArgs]]], simulate: bool, @@ -228,19 +269,11 @@ def execute_run_combos( shell=False) for collector_info, run_combos in grouped_run_combos: - for combos in run_combos: - args = as_run_command(combos) - if combos.readahead in _TRACING_READAHEADS: - passed, collector_tmp_output_file = run_collector_script(collector_info, - inodes_path, - timeout, - simulate) - combos = combos._replace(input=collector_tmp_output_file.name) - - print_utils.debug_print(combos) - output = PrefetchAppRunner(**combos._asdict()).run() - - yield DataFrame(dict((x, [y]) for x, y in output)) if output else None + yield from execute_run_using_perfetto_trace(collector_info, + run_combos, + simulate, + inodes_path, + timeout) def gather_results(commands: Iterable[Tuple[DataFrame]], key_list: List[str], value_list: List[Tuple[str, ...]]): diff --git a/startop/scripts/app_startup/app_startup_runner_test.py b/startop/scripts/app_startup/app_startup_runner_test.py index 9aa7014d1912..42ea5f0e4bb9 100755 --- a/startop/scripts/app_startup/app_startup_runner_test.py +++ b/startop/scripts/app_startup/app_startup_runner_test.py @@ -91,7 +91,8 @@ def default_dict_for_parsed_args(**kwargs): # Combine it with all of the "optional" parameters' default values. """ d = {'compiler_filters': None, 'simulate': False, 'debug': False, - 'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None} + 'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None, + 'trace_duration': None} d.update(kwargs) return d @@ -159,19 +160,6 @@ def test_key_to_cmdline_flag(): assert asr.key_to_cmdline_flag("ba_r") == "--ba-r" assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z" -def test_make_script_command_with_temp_output(): - cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", - args=[], count=1) - with tmp_file: - assert cmd_str == ["fake_script", "--count", "1", "--output", tmp_file.name] - - cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", - args=['a', 'b'], - count=2) - with tmp_file: - assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output", - tmp_file.name] - def test_parse_run_script_csv_file(): # empty file -> empty list f = io.StringIO("") diff --git a/startop/scripts/app_startup/lib/adb_utils.py b/startop/scripts/app_startup/lib/adb_utils.py index 0e0065defd7f..1c60a17ada1b 100644 --- a/startop/scripts/app_startup/lib/adb_utils.py +++ b/startop/scripts/app_startup/lib/adb_utils.py @@ -104,4 +104,21 @@ def blocking_wait_for_logcat_displayed_time(timestamp: datetime.datetime, return None displayed_time = result[result.rfind('+'):] - return parse_time_to_milliseconds(displayed_time)
\ No newline at end of file + return parse_time_to_milliseconds(displayed_time) + +def delete_file_on_device(file_path: str) -> None: + """ Deletes a file on the device. """ + cmd_utils.run_adb_shell_command( + "[[ -f '{file_path}' ]] && rm -f '{file_path}' || " + "exit 0".format(file_path=file_path)) + +def set_prop(property: str, value: str) -> None: + """ Sets property using adb shell. """ + cmd_utils.run_adb_shell_command('setprop "{property}" "{value}"'.format( + property=property, value=value)) + +def pull_file(device_file_path: str, output_file_path: str) -> None: + """ Pulls file from device to output """ + cmd_utils.run_shell_command('adb pull "{device_file_path}" "{output_file_path}"'. + format(device_file_path=device_file_path, + output_file_path=output_file_path)) diff --git a/startop/scripts/app_startup/lib/app_runner.py b/startop/scripts/app_startup/lib/app_runner.py index a8afd6a22e38..78873fa51ab5 100644 --- a/startop/scripts/app_startup/lib/app_runner.py +++ b/startop/scripts/app_startup/lib/app_runner.py @@ -51,6 +51,7 @@ class AppRunnerListener(object): returns: a string in the format of "<metric>=<value>\n<metric>=<value>\n..." for further parsing. For example "TotalTime=123\nDisplayedTime=121". + Return an empty string if no metrics need to be parsed further. """ pass @@ -61,7 +62,7 @@ class AppRunner(object): APP_STARTUP_DIR = os.path.dirname(DIR) IORAP_COMMON_BASH_SCRIPT = os.path.realpath(os.path.join(DIR, '../../iorap/common')) - DEFAULT_TIMEOUT = 30 + DEFAULT_TIMEOUT = 30 # seconds def __init__(self, package: str, diff --git a/startop/scripts/app_startup/lib/perfetto_trace_collector.py b/startop/scripts/app_startup/lib/perfetto_trace_collector.py new file mode 100644 index 000000000000..9ffb3494da49 --- /dev/null +++ b/startop/scripts/app_startup/lib/perfetto_trace_collector.py @@ -0,0 +1,166 @@ +# Copyright 2019, 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. + +"""Class to collector perfetto trace.""" +import datetime +import os +import re +import sys +import time +from datetime import timedelta +from typing import Optional, List, Tuple + +# global variables +DIR = os.path.abspath(os.path.dirname(__file__)) + +sys.path.append(os.path.dirname(os.path.dirname(DIR))) + +import app_startup.lib.adb_utils as adb_utils +from app_startup.lib.app_runner import AppRunner, AppRunnerListener +import lib.print_utils as print_utils +import lib.logcat_utils as logcat_utils +import iorap.lib.iorapd_utils as iorapd_utils + +class PerfettoTraceCollector(AppRunnerListener): + """ Class to collect perfetto trace. + + To set trace duration of perfetto, change the 'trace_duration_ms'. + To pull the generated perfetto trace on device, set the 'output'. + """ + TRACE_FILE_SUFFIX = 'perfetto_trace.pb' + TRACE_DURATION_PROP = 'iorapd.perfetto.trace_duration_ms' + MS_PER_SEC = 1000 + DEFAULT_TRACE_DURATION = timedelta(milliseconds=5000) # 5 seconds + _COLLECTOR_TIMEOUT_MULTIPLIER = 10 # take the regular timeout and multiply + + def __init__(self, + package: str, + activity: Optional[str], + compiler_filter: Optional[str], + timeout: Optional[int], + simulate: bool, + trace_duration: timedelta = DEFAULT_TRACE_DURATION, + save_destination_file_path: Optional[str] = None): + """ Initialize the perfetto trace collector. """ + self.app_runner = AppRunner(package, + activity, + compiler_filter, + timeout, + simulate) + self.app_runner.add_callbacks(self) + + self.trace_duration = trace_duration + self.save_destination_file_path = save_destination_file_path + + def purge_file(self, suffix: str) -> None: + print_utils.debug_print('iorapd-perfetto: purge file in ' + + self._get_remote_path()) + adb_utils.delete_file_on_device(self._get_remote_path()) + + def run(self) -> Optional[List[Tuple[str]]]: + """Runs an app. + + Returns: + A list of (metric, value) tuples. + """ + return self.app_runner.run() + + def preprocess(self): + # Sets up adb environment. + adb_utils.root() + adb_utils.disable_selinux() + time.sleep(1) + + # Kill any existing process of this app + adb_utils.pkill(self.app_runner.package) + + # Remove existing trace and compiler files + self.purge_file(PerfettoTraceCollector.TRACE_FILE_SUFFIX) + + # Set perfetto trace duration prop to milliseconds. + adb_utils.set_prop(PerfettoTraceCollector.TRACE_DURATION_PROP, + int(self.trace_duration.total_seconds()* + PerfettoTraceCollector.MS_PER_SEC)) + + if not iorapd_utils.stop_iorapd(): + raise RuntimeError('Cannot stop iorapd!') + + if not iorapd_utils.enable_iorapd_perfetto(): + raise RuntimeError('Cannot enable perfetto!') + + if not iorapd_utils.disable_iorapd_readahead(): + raise RuntimeError('Cannot disable readahead!') + + if not iorapd_utils.start_iorapd(): + raise RuntimeError('Cannot start iorapd!') + + # Drop all caches to get cold starts. + adb_utils.vm_drop_cache() + + def postprocess(self, pre_launch_timestamp: str): + # Kill any existing process of this app + adb_utils.pkill(self.app_runner.package) + + iorapd_utils.disable_iorapd_perfetto() + + if self.save_destination_file_path is not None: + adb_utils.pull_file(self._get_remote_path(), + self.save_destination_file_path) + + def metrics_selector(self, am_start_output: str, + pre_launch_timestamp: str) -> str: + """Parses the metric after app startup by reading from logcat in a blocking + manner until all metrics have been found". + + Returns: + An empty string because the metric needs no further parsing. + """ + if not self._wait_for_perfetto_trace(pre_launch_timestamp): + raise RuntimeError('Could not save perfetto app trace file!') + + return '' + + def _wait_for_perfetto_trace(self, pre_launch_timestamp) -> Optional[str]: + """ Waits for the perfetto trace being saved to file. + + The string is in the format of r".*Perfetto TraceBuffer saved to file: + <file path>.*" + + Returns: + the string what the program waits for. If the string doesn't show up, + return None. + """ + pattern = re.compile(r'.*Perfetto TraceBuffer saved to file: {}.*'. + format(self._get_remote_path())) + + # The pre_launch_timestamp is longer than what the datetime can parse. Trim + # last three digits to make them align. For example: + # 2019-07-02 23:20:06.972674825999 -> 2019-07-02 23:20:06.972674825 + assert len(pre_launch_timestamp) == len('2019-07-02 23:20:06.972674825') + timestamp = datetime.datetime.strptime(pre_launch_timestamp[:-3], + '%Y-%m-%d %H:%M:%S.%f') + + # The timeout of perfetto trace is longer than the normal app run timeout. + timeout_dt = self.app_runner.timeout * PerfettoTraceCollector._COLLECTOR_TIMEOUT_MULTIPLIER + timeout_end = timestamp + datetime.timedelta(seconds=timeout_dt) + + return logcat_utils.blocking_wait_for_logcat_pattern(timestamp, + pattern, + timeout_end) + + def _get_remote_path(self): + # For example: android.music%2Fmusic.TopLevelActivity.perfetto_trace.pb + return iorapd_utils._iorapd_path_to_data_file(self.app_runner.package, + self.app_runner.activity, + PerfettoTraceCollector.TRACE_FILE_SUFFIX) diff --git a/startop/scripts/app_startup/lib/perfetto_trace_collector_test.py b/startop/scripts/app_startup/lib/perfetto_trace_collector_test.py new file mode 100644 index 000000000000..8d94fc58bede --- /dev/null +++ b/startop/scripts/app_startup/lib/perfetto_trace_collector_test.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# +# Copyright 2019, 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. +# + +"""Unit tests for the data_frame.py script.""" +import os +import sys +from pathlib import Path +from datetime import timedelta + +from mock import call, patch +from perfetto_trace_collector import PerfettoTraceCollector + +sys.path.append(Path(os.path.realpath(__file__)).parents[2]) +from app_startup.lib.app_runner import AppRunner + +RUNNER = PerfettoTraceCollector(package='music', + activity='MainActivity', + compiler_filter=None, + timeout=10, + simulate=False, + trace_duration = timedelta(milliseconds=1000), + # No actual file will be created. Just to + # check the command. + save_destination_file_path='/tmp/trace.pb') + +def _mocked_run_shell_command(*args, **kwargs): + if args[0] == 'adb shell ps | grep "music" | awk \'{print $2;}\'': + return (True, '9999') + else: + return (True, '') + +@patch('lib.logcat_utils.blocking_wait_for_logcat_pattern') +@patch('lib.cmd_utils.run_shell_command') +def test_perfetto_trace_collector_preprocess(mock_run_shell_command, + mock_blocking_wait_for_logcat_pattern): + mock_run_shell_command.side_effect = _mocked_run_shell_command + mock_blocking_wait_for_logcat_pattern.return_value = "Succeed!" + + RUNNER.preprocess() + + calls = [call('adb root'), + call('adb shell "getenforce"'), + call('adb shell "setenforce 0"'), + call('adb shell "stop"'), + call('adb shell "start"'), + call('adb wait-for-device'), + call('adb shell ps | grep "music" | awk \'{print $2;}\''), + call('adb shell "kill 9999"'), + call( + 'adb shell "[[ -f \'/data/misc/iorapd/music%2FMainActivity.perfetto_trace.pb\' ]] ' + '&& rm -f \'/data/misc/iorapd/music%2FMainActivity.perfetto_trace.pb\' || exit 0"'), + call('adb shell "setprop "iorapd.perfetto.trace_duration_ms" "1000""'), + call( + 'bash -c "source {}; iorapd_stop"'.format( + AppRunner.IORAP_COMMON_BASH_SCRIPT)), + call( + 'bash -c "source {}; iorapd_perfetto_enable"'.format( + AppRunner.IORAP_COMMON_BASH_SCRIPT)), + call( + 'bash -c "source {}; iorapd_readahead_disable"'.format( + AppRunner.IORAP_COMMON_BASH_SCRIPT)), + call( + 'bash -c "source {}; iorapd_start"'.format( + AppRunner.IORAP_COMMON_BASH_SCRIPT)), + call('adb shell "echo 3 > /proc/sys/vm/drop_caches"')] + + mock_run_shell_command.assert_has_calls(calls) + +@patch('lib.logcat_utils.blocking_wait_for_logcat_pattern') +@patch('lib.cmd_utils.run_shell_command') +def test_perfetto_trace_collector_postprocess(mock_run_shell_command, + mock_blocking_wait_for_logcat_pattern): + mock_run_shell_command.side_effect = _mocked_run_shell_command + mock_blocking_wait_for_logcat_pattern.return_value = "Succeed!" + + RUNNER.postprocess('2019-07-02 23:20:06.972674825') + + calls = [call('adb shell ps | grep "music" | awk \'{print $2;}\''), + call('adb shell "kill 9999"'), + call( + 'bash -c "source {}; iorapd_perfetto_disable"'.format( + AppRunner.IORAP_COMMON_BASH_SCRIPT)), + call('adb pull ' + '"/data/misc/iorapd/music%2FMainActivity.perfetto_trace.pb" ' + '"/tmp/trace.pb"')] + + mock_run_shell_command.assert_has_calls(calls) diff --git a/startop/scripts/iorap/compiler.py b/startop/scripts/iorap/compiler.py index 9527e28c94fe..ef9b870b8113 100755 --- a/startop/scripts/iorap/compiler.py +++ b/startop/scripts/iorap/compiler.py @@ -31,8 +31,10 @@ import tempfile from pathlib import Path from typing import Iterable, Optional, List -from generated.TraceFile_pb2 import * -from lib.inode2filename import Inode2Filename +DIR = os.path.abspath(os.path.dirname(__file__)) +sys.path.append(os.path.dirname(DIR)) +from iorap.generated.TraceFile_pb2 import * +from iorap.lib.inode2filename import Inode2Filename parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) sys.path.append(parent_dir_name) diff --git a/startop/scripts/iorap/lib/iorapd_utils.py b/startop/scripts/iorap/lib/iorapd_utils.py index c03e9b0ae04d..0d62180a01e3 100644 --- a/startop/scripts/iorap/lib/iorapd_utils.py +++ b/startop/scripts/iorap/lib/iorapd_utils.py @@ -111,3 +111,50 @@ def disable_iorapd_readahead() -> bool: passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT, 'iorapd_readahead_disable', []) return passed + +def enable_iorapd_perfetto() -> bool: + """ + Enable Perfetto. Subsequent launches of an application will record a perfetto + trace protobuf. + + Returns: + A bool indicates whether the enabling is done successfully or not. + """ + passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT, + 'iorapd_perfetto_enable', []) + return passed + +def disable_iorapd_perfetto() -> bool: + """ + Disable Perfetto. Subsequent launches of applications will no longer record + perfetto trace protobufs. + + Returns: + A bool indicates whether the disabling is done successfully or not. + """ + passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT, + 'iorapd_perfetto_disable', []) + return passed + +def start_iorapd() -> bool: + """ + Starts iorapd. + + Returns: + A bool indicates whether the starting is done successfully or not. + """ + passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT, + 'iorapd_start', []) + return passed + +def stop_iorapd() -> bool: + """ + Stops iorapd. + + Returns: + A bool indicates whether the stopping is done successfully or not. + """ + passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT, + 'iorapd_stop', []) + return passed + diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp index 92ea872f04fc..4f6524e0528b 100644 --- a/startop/view_compiler/Android.bp +++ b/startop/view_compiler/Android.bp @@ -77,7 +77,6 @@ cc_test_host { name: "view-compiler-tests", defaults: ["viewcompiler_defaults"], srcs: [ - "dex_builder_test.cc", "layout_validation_test.cc", "util_test.cc", ], diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc index 09f9c04d9e2c..499c42e2888b 100644 --- a/startop/view_compiler/dex_builder.cc +++ b/startop/view_compiler/dex_builder.cc @@ -108,6 +108,12 @@ std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) { case Instruction::Op::kSetStaticField: out << "kSetStaticField"; return out; + case Instruction::Op::kGetInstanceField: + out << "kGetInstanceField"; + return out; + case Instruction::Op::kSetInstanceField: + out << "kSetInstanceField"; + return out; } } @@ -246,6 +252,7 @@ ir::FieldDecl* DexBuilder::GetOrAddField(TypeDescriptor parent, const std::strin field->parent = GetOrAddType(parent); field->name = GetOrAddString(name); field->type = GetOrAddType(type); + field->orig_index = dex_file_->fields_indexes.AllocateIndex(); dex_file_->fields_map[field->orig_index] = field; field_decls_by_key_[key] = field; return field; @@ -384,7 +391,9 @@ void MethodBuilder::EncodeInstruction(const Instruction& instruction) { return EncodeCast(instruction); case Instruction::Op::kGetStaticField: case Instruction::Op::kSetStaticField: - return EncodeStaticFieldOp(instruction); + case Instruction::Op::kGetInstanceField: + case Instruction::Op::kSetInstanceField: + return EncodeFieldOp(instruction); } } @@ -539,7 +548,8 @@ void MethodBuilder::EncodeCast(const Instruction& instruction) { Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value()); } -void MethodBuilder::EncodeStaticFieldOp(const Instruction& instruction) { +void MethodBuilder::EncodeFieldOp(const Instruction& instruction) { + const auto& args = instruction.args(); switch (instruction.opcode()) { case Instruction::Op::kGetStaticField: { CHECK(instruction.dest().has_value()); @@ -553,18 +563,36 @@ void MethodBuilder::EncodeStaticFieldOp(const Instruction& instruction) { } case Instruction::Op::kSetStaticField: { CHECK(!instruction.dest().has_value()); - const auto& args = instruction.args(); CHECK_EQ(1, args.size()); CHECK(args[0].is_variable()); - Encode21c(::art::Instruction::SPUT, + Encode21c(::art::Instruction::SPUT, RegisterValue(args[0]), instruction.index_argument()); + break; + } + case Instruction::Op::kGetInstanceField: { + CHECK(instruction.dest().has_value()); + CHECK(instruction.dest()->is_variable()); + CHECK_EQ(1, instruction.args().size()); + + Encode22c(::art::Instruction::IGET, + RegisterValue(*instruction.dest()), RegisterValue(args[0]), instruction.index_argument()); break; } - default: { - LOG(FATAL) << "Unsupported static field operation"; + case Instruction::Op::kSetInstanceField: { + CHECK(!instruction.dest().has_value()); + CHECK_EQ(2, args.size()); + CHECK(args[0].is_variable()); + CHECK(args[1].is_variable()); + + Encode22c(::art::Instruction::IPUT, + RegisterValue(args[1]), + RegisterValue(args[0]), + instruction.index_argument()); + break; } + default: { LOG(FATAL) << "Unsupported field operation"; } } } diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h index 3f9ac43ae532..292d6599c115 100644 --- a/startop/view_compiler/dex_builder.h +++ b/startop/view_compiler/dex_builder.h @@ -153,6 +153,7 @@ class Instruction { kBranchEqz, kBranchNEqz, kCheckCast, + kGetInstanceField, kGetStaticField, kInvokeDirect, kInvokeInterface, @@ -163,6 +164,7 @@ class Instruction { kNew, kReturn, kReturnObject, + kSetInstanceField, kSetStaticField }; @@ -195,8 +197,9 @@ class Instruction { } // Returns an object template <typename... T> - static inline Instruction InvokeVirtualObject(size_t index_argument, std::optional<const Value> dest, - Value this_arg, T... args) { + static inline Instruction InvokeVirtualObject(size_t index_argument, + std::optional<const Value> dest, Value this_arg, + T... args) { return Instruction{ Op::kInvokeVirtual, index_argument, /*result_is_object=*/true, dest, this_arg, args...}; } @@ -209,8 +212,9 @@ class Instruction { } // Returns an object template <typename... T> - static inline Instruction InvokeDirectObject(size_t index_argument, std::optional<const Value> dest, - Value this_arg, T... args) { + static inline Instruction InvokeDirectObject(size_t index_argument, + std::optional<const Value> dest, Value this_arg, + T... args) { return Instruction{ Op::kInvokeDirect, index_argument, /*result_is_object=*/true, dest, this_arg, args...}; } @@ -218,20 +222,21 @@ class Instruction { template <typename... T> static inline Instruction InvokeStatic(size_t index_argument, std::optional<const Value> dest, T... args) { - return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/false, dest, args...}; + return Instruction{ + Op::kInvokeStatic, index_argument, /*result_is_object=*/false, dest, args...}; } // Returns an object template <typename... T> - static inline Instruction InvokeStaticObject(size_t index_argument, std::optional<const Value> dest, - T... args) { + static inline Instruction InvokeStaticObject(size_t index_argument, + std::optional<const Value> dest, T... args) { return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/true, dest, args...}; } // For static calls. template <typename... T> static inline Instruction InvokeInterface(size_t index_argument, std::optional<const Value> dest, T... args) { - return Instruction{Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...}; - + return Instruction{ + Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...}; } static inline Instruction GetStaticField(size_t field_id, Value dest) { @@ -239,9 +244,18 @@ class Instruction { } static inline Instruction SetStaticField(size_t field_id, Value value) { - return Instruction{Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value}; + return Instruction{ + Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value}; + } + + static inline Instruction GetField(size_t field_id, Value dest, Value object) { + return Instruction{Op::kGetInstanceField, field_id, /*result_is_object=*/false, dest, object}; } + static inline Instruction SetField(size_t field_id, Value object, Value value) { + return Instruction{ + Op::kSetInstanceField, field_id, /*result_is_object=*/false, /*dest=*/{}, object, value}; + } /////////////// // Accessors // @@ -255,10 +269,14 @@ class Instruction { private: inline Instruction(Op opcode, size_t index_argument, std::optional<const Value> dest) - : opcode_{opcode}, index_argument_{index_argument}, result_is_object_{false}, dest_{dest}, args_{} {} + : opcode_{opcode}, + index_argument_{index_argument}, + result_is_object_{false}, + dest_{dest}, + args_{} {} template <typename... T> - inline constexpr Instruction(Op opcode, size_t index_argument, bool result_is_object, + inline Instruction(Op opcode, size_t index_argument, bool result_is_object, std::optional<const Value> dest, T... args) : opcode_{opcode}, index_argument_{index_argument}, @@ -331,7 +349,7 @@ class MethodBuilder { void EncodeBranch(art::Instruction::Code op, const Instruction& instruction); void EncodeNew(const Instruction& instruction); void EncodeCast(const Instruction& instruction); - void EncodeStaticFieldOp(const Instruction& instruction); + void EncodeFieldOp(const Instruction& instruction); // Low-level instruction format encoding. See // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of @@ -364,6 +382,14 @@ class MethodBuilder { buffer_.push_back(b); } + inline void Encode22c(art::Instruction::Code opcode, uint8_t a, uint8_t b, uint16_t c) { + // b|a|op|bbbb + CHECK(IsShortRegister(a)); + CHECK(IsShortRegister(b)); + buffer_.push_back((b << 12) | (a << 8) | opcode); + buffer_.push_back(c); + } + inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) { buffer_.push_back(opcode); buffer_.push_back(a); diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc deleted file mode 100644 index 90c256f271cf..000000000000 --- a/startop/view_compiler/dex_builder_test.cc +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#include "dex_builder.h" - -#include "dex/art_dex_file_loader.h" -#include "dex/dex_file.h" -#include "gtest/gtest.h" - -using namespace startop::dex; - -// Takes a DexBuilder, encodes it into an in-memory DEX file, verifies the resulting DEX file and -// returns whether the verification was successful. -bool EncodeAndVerify(DexBuilder* dex_file) { - slicer::MemView image{dex_file->CreateImage()}; - - art::ArtDexFileLoader loader; - std::string error_msg; - std::unique_ptr<const art::DexFile> loaded_dex_file{loader.Open(image.ptr<const uint8_t>(), - image.size(), - /*location=*/"", - /*location_checksum=*/0, - /*oat_dex_file=*/nullptr, - /*verify=*/true, - /*verify_checksum=*/false, - &error_msg)}; - return loaded_dex_file != nullptr; -} - -// Write out and verify a DEX file that corresponds to: -// -// package dextest; -// public class DexTest { -// public static void foo() {} -// } -TEST(DexBuilderTest, VerifyDexWithClassMethod) { - DexBuilder dex_file; - - auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; - - auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void()})}; - method.BuildReturn(); - method.Encode(); - - EXPECT_TRUE(EncodeAndVerify(&dex_file)); -} - -// Makes sure a bad DEX class fails to verify. -TEST(DexBuilderTest, VerifyBadDexWithClassMethod) { - DexBuilder dex_file; - - auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; - - // This method has the error, because methods cannot take Void() as a parameter. - auto method{ - cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void(), TypeDescriptor::Void()})}; - method.BuildReturn(); - method.Encode(); - - EXPECT_FALSE(EncodeAndVerify(&dex_file)); -} - -// Write out and verify a DEX file that corresponds to: -// -// package dextest; -// public class DexTest { -// public static int foo() { return 5; } -// } -TEST(DexBuilderTest, VerifyDexReturn5) { - DexBuilder dex_file; - - auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; - - auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})}; - auto r = method.MakeRegister(); - method.BuildConst4(r, 5); - method.BuildReturn(r); - method.Encode(); - - EXPECT_TRUE(EncodeAndVerify(&dex_file)); -} - -// Write out and verify a DEX file that corresponds to: -// -// package dextest; -// public class DexTest { -// public static int foo(int x) { return x; } -// } -TEST(DexBuilderTest, VerifyDexReturnIntParam) { - DexBuilder dex_file; - - auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; - - auto method{ - cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})}; - method.BuildReturn(Value::Parameter(0)); - method.Encode(); - - EXPECT_TRUE(EncodeAndVerify(&dex_file)); -} - -// Write out and verify a DEX file that corresponds to: -// -// package dextest; -// public class DexTest { -// public static int foo(String s) { return s.length(); } -// } -TEST(DexBuilderTest, VerifyDexCallStringLength) { - DexBuilder dex_file; - - auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; - - MethodBuilder method{cbuilder.CreateMethod( - "foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::FromClassname("java.lang.String")})}; - - Value result = method.MakeRegister(); - - MethodDeclData string_length = - dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"), - "length", - Prototype{TypeDescriptor::Int()}); - - method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0))); - method.BuildReturn(result); - - method.Encode(); - - EXPECT_TRUE(EncodeAndVerify(&dex_file)); -} - -// Write out and verify a DEX file that corresponds to: -// -// package dextest; -// public class DexTest { -// public static int foo(String s) { return s.length(); } -// } -TEST(DexBuilderTest, VerifyDexCallManyRegisters) { - DexBuilder dex_file; - - auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; - - MethodBuilder method{cbuilder.CreateMethod( - "foo", Prototype{TypeDescriptor::Int()})}; - - Value result = method.MakeRegister(); - - // Make a bunch of registers - for (size_t i = 0; i < 25; ++i) { - method.MakeRegister(); - } - - // Now load a string literal into a register - Value string_val = method.MakeRegister(); - method.BuildConstString(string_val, "foo"); - - MethodDeclData string_length = - dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"), - "length", - Prototype{TypeDescriptor::Int()}); - - method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, string_val)); - method.BuildReturn(result); - - method.Encode(); - - EXPECT_TRUE(EncodeAndVerify(&dex_file)); -} diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java index 6c0b8bbe8b83..d1fe58800bbf 100644 --- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java @@ -186,4 +186,25 @@ public final class DexBuilderTest { method.invoke(null); Assert.assertEquals(7, TestClass.staticInteger); } + + @Test + public void readInstanceField() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("readInstanceField", TestClass.class); + TestClass obj = new TestClass(); + obj.instanceField = 5; + Assert.assertEquals(5, method.invoke(null, obj)); + } + + @Test + public void setInstanceField() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("setInstanceField", TestClass.class); + TestClass obj = new TestClass(); + obj.instanceField = 5; + method.invoke(null, obj); + Assert.assertEquals(7, obj.instanceField); + } } diff --git a/startop/view_compiler/dex_layout_compiler.cc b/startop/view_compiler/dex_layout_compiler.cc index c68793d10399..8febfb71ecd1 100644 --- a/startop/view_compiler/dex_layout_compiler.cc +++ b/startop/view_compiler/dex_layout_compiler.cc @@ -23,25 +23,6 @@ namespace startop { using android::base::StringPrintf; -void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) { - if (0 == name.compare(u"merge")) { - message_ = "Merge tags are not supported"; - can_compile_ = false; - } - if (0 == name.compare(u"include")) { - message_ = "Include tags are not supported"; - can_compile_ = false; - } - if (0 == name.compare(u"view")) { - message_ = "View tags are not supported"; - can_compile_ = false; - } - if (0 == name.compare(u"fragment")) { - message_ = "Fragment tags are not supported"; - can_compile_ = false; - } -} - DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method) : method_{method}, context_{dex::Value::Parameter(0)}, diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc index fee5e722bc55..6dedf24e290d 100644 --- a/startop/view_compiler/dex_testcase_generator.cc +++ b/startop/view_compiler/dex_testcase_generator.cc @@ -282,15 +282,15 @@ void GenerateSimpleTestCases(const string& outdir) { method.Encode(); }(castObjectToString); + TypeDescriptor test_class = TypeDescriptor::FromClassname("android.startop.test.TestClass"); + // Read a static field - // integer readStaticField() { return TestClass.staticInteger; } + // int readStaticField() { return TestClass.staticInteger; } MethodBuilder readStaticField{ cbuilder.CreateMethod("readStaticField", Prototype{TypeDescriptor::Int()})}; [&](MethodBuilder& method) { const ir::FieldDecl* field = - dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"), - "staticInteger", - TypeDescriptor::Int()); + dex_file.GetOrAddField(test_class, "staticInteger", TypeDescriptor::Int()); Value result{method.MakeRegister()}; method.AddInstruction(Instruction::GetStaticField(field->orig_index, result)); method.BuildReturn(result, /*is_object=*/false); @@ -303,9 +303,7 @@ void GenerateSimpleTestCases(const string& outdir) { cbuilder.CreateMethod("setStaticField", Prototype{TypeDescriptor::Void()})}; [&](MethodBuilder& method) { const ir::FieldDecl* field = - dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"), - "staticInteger", - TypeDescriptor::Int()); + dex_file.GetOrAddField(test_class, "staticInteger", TypeDescriptor::Int()); Value number{method.MakeRegister()}; method.BuildConst4(number, 7); method.AddInstruction(Instruction::SetStaticField(field->orig_index, number)); @@ -313,6 +311,33 @@ void GenerateSimpleTestCases(const string& outdir) { method.Encode(); }(setStaticField); + // Read an instance field + // int readInstanceField(TestClass obj) { return obj.instanceField; } + MethodBuilder readInstanceField{ + cbuilder.CreateMethod("readInstanceField", Prototype{TypeDescriptor::Int(), test_class})}; + [&](MethodBuilder& method) { + const ir::FieldDecl* field = + dex_file.GetOrAddField(test_class, "instanceField", TypeDescriptor::Int()); + Value result{method.MakeRegister()}; + method.AddInstruction(Instruction::GetField(field->orig_index, result, Value::Parameter(0))); + method.BuildReturn(result, /*is_object=*/false); + method.Encode(); + }(readInstanceField); + + // Set an instance field + // void setInstanceField(TestClass obj) { obj.instanceField = 7; } + MethodBuilder setInstanceField{ + cbuilder.CreateMethod("setInstanceField", Prototype{TypeDescriptor::Void(), test_class})}; + [&](MethodBuilder& method) { + const ir::FieldDecl* field = + dex_file.GetOrAddField(test_class, "instanceField", TypeDescriptor::Int()); + Value number{method.MakeRegister()}; + method.BuildConst4(number, 7); + method.AddInstruction(Instruction::SetField(field->orig_index, Value::Parameter(0), number)); + method.BuildReturn(); + method.Encode(); + }(setInstanceField); + slicer::MemView image{dex_file.CreateImage()}; std::ofstream out_file(outdir + "/simple.dex"); out_file.write(image.ptr<const char>(), image.size()); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index cd79f37bb2ce..9849ec73542b 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2328,6 +2328,13 @@ public class CarrierConfigManager { public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool"; /** + * Indicates if the TTY HCO and VCO options should be hidden in the accessibility menu + * if the device is capable of RTT. + * @hide + */ + public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt"; + + /** * The flag to disable the popup dialog which warns the user of data charges. * @hide */ @@ -2407,6 +2414,14 @@ public class CarrierConfigManager { public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; + /** + * Determines whether we should show a notification when the phone established a data + * connection in roaming network, to warn users about possible roaming charges. + * @hide + */ + public static final String KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL = + "show_data_connected_roaming_notification"; + /** * A list of 4 LTE RSRP thresholds above which a signal level is considered POOR, * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting. @@ -2703,12 +2718,20 @@ public class CarrierConfigManager { /** * Controls hysteresis time in milli seconds for which OpportunisticNetworkService - * will wait before switching data to a network. + * will wait before switching data to an opportunistic network. */ public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG = "opportunistic_network_data_switch_hysteresis_time_long"; /** + * Controls hysteresis time in milli seconds for which OpportunisticNetworkService + * will wait before switching data from opportunistic network to primary network. + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG = + "opportunistic_network_data_switch_exit_hysteresis_time_long"; + + /** * Indicates zero or more emergency number prefix(es), because some carrier requires * if users dial an emergency number address with a specific prefix, the combination of the * prefix and the address is also a valid emergency number to dial. For example, an emergency @@ -2894,7 +2917,7 @@ public class CarrierConfigManager { defaults.putString(KEY_SUPL_VER_STRING, "0x20000"); defaults.putString(KEY_SUPL_MODE_STRING, "1"); defaults.putString(KEY_SUPL_ES_STRING, "1"); - defaults.putString(KEY_LPP_PROFILE_STRING, "0"); + defaults.putString(KEY_LPP_PROFILE_STRING, "2"); defaults.putString(KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING, "1"); defaults.putString(KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, "0"); defaults.putString(KEY_GPS_LOCK_STRING, "3"); @@ -2908,10 +2931,10 @@ public class CarrierConfigManager { /** * Wi-Fi configs used in Carrier Wi-Fi application. - * TODO(b/132059890): Expose it in a future release as systemapi. * * @hide */ + @SystemApi public static final class Wifi { /** Prefix of all Wifi.KEY_* constants. */ public static final String KEY_PREFIX = "wifi."; @@ -3406,6 +3429,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false); sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false); sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true); + sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false); sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true); sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null); @@ -3424,6 +3448,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING, ""); sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false); sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false); + sDefaults.putBoolean(KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL, false); sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, new int[] { -128, /* SIGNAL_STRENGTH_POOR */ @@ -3467,6 +3492,8 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG, 10000); /* Default value is 10 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000); + /* Default value is 3 seconds. */ + sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000); sDefaults.putAll(Gps.getDefaults()); sDefaults.putAll(Wifi.getDefaults()); sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY, diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index cdf4c935f84b..aa7e21a82500 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -340,6 +340,19 @@ public final class DisconnectCause { */ public static final int MEDIA_TIMEOUT = 77; + /** + * Indicates that an emergency call cannot be placed over WFC because the service is not + * available in the current location. + * @hide + */ + public static final int EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 78; + + /** + * Indicates that WiFi calling service is not available in the current location. + * @hide + */ + public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79; + //********************************************************************************************* // When adding a disconnect type: // 1) Update toString() with the newly added disconnect type. @@ -510,6 +523,10 @@ public final class DisconnectCause { return "OTASP_PROVISIONING_IN_PROCESS"; case MEDIA_TIMEOUT: return "MEDIA_TIMEOUT"; + case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE: + return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE"; + case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: + return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION"; default: return "INVALID: " + cause; } diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index b75e51577fdb..f03a9dc0f963 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -22,9 +22,11 @@ import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; import android.annotation.IntDef; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.database.Cursor; import android.location.CountryDetector; import android.net.Uri; @@ -164,6 +166,33 @@ public class PhoneNumberUtils { return c == 'w'||c == 'W'; } + private static int sMinMatch = 0; + + private static int getMinMatch() { + if (sMinMatch == 0) { + sMinMatch = Resources.getSystem().getInteger( + com.android.internal.R.integer.config_phonenumber_compare_min_match); + } + return sMinMatch; + } + + /** + * A Test API to get current sMinMatch. + * @hide + */ + @TestApi + public static int getMinMatchForTest() { + return getMinMatch(); + } + + /** + * A Test API to set sMinMatch. + * @hide + */ + @TestApi + public static void setMinMatchForTest(int minMatch) { + sMinMatch = minMatch; + } /** Returns true if ch is not dialable or alpha char */ private static boolean isSeparator(char ch) { @@ -475,7 +504,7 @@ public class PhoneNumberUtils { * enough for caller ID purposes. * * - Compares from right to left - * - requires MIN_MATCH (7) characters to match + * - requires minimum characters to match * - handles common trunk prefixes and international prefixes * (basically, everything except the Russian trunk prefix) * @@ -491,6 +520,7 @@ public class PhoneNumberUtils { int matched; int numNonDialableCharsInA = 0; int numNonDialableCharsInB = 0; + int minMatch = getMinMatch(); if (a == null || b == null) return a == b; @@ -530,12 +560,12 @@ public class PhoneNumberUtils { } } - if (matched < MIN_MATCH) { + if (matched < minMatch) { int effectiveALen = a.length() - numNonDialableCharsInA; int effectiveBLen = b.length() - numNonDialableCharsInB; - // if the number of dialable chars in a and b match, but the matched chars < MIN_MATCH, + // if the number of dialable chars in a and b match, but the matched chars < minMatch, // treat them as equal (i.e. 404-04 and 40404) if (effectiveALen == effectiveBLen && effectiveALen == matched) { return true; @@ -545,7 +575,7 @@ public class PhoneNumberUtils { } // At least one string has matched completely; - if (matched >= MIN_MATCH && (ia < 0 || ib < 0)) { + if (matched >= minMatch && (ia < 0 || ib < 0)) { return true; } @@ -736,7 +766,7 @@ public class PhoneNumberUtils { } /** - * Returns the rightmost MIN_MATCH (5) characters in the network portion + * Returns the rightmost minimum matched characters in the network portion * in *reversed* order * * This can be used to do a database lookup against the column @@ -747,7 +777,7 @@ public class PhoneNumberUtils { public static String toCallerIDMinMatch(String phoneNumber) { String np = extractNetworkPortionAlt(phoneNumber); - return internalGetStrippedReversed(np, MIN_MATCH); + return internalGetStrippedReversed(np, getMinMatch()); } /** @@ -1709,26 +1739,6 @@ public class PhoneNumberUtils { return normalizedDigits.toString(); } - // Three and four digit phone numbers for either special services, - // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should - // not match. - // - // This constant used to be 5, but SMS short codes has increased in length and - // can be easily 6 digits now days. Most countries have SMS short code length between - // 3 to 6 digits. The exceptions are - // - // Australia: Short codes are six or eight digits in length, starting with the prefix "19" - // followed by an additional four or six digits and two. - // Czechia: Codes are seven digits in length for MO and five (not billed) or - // eight (billed) for MT direction - // - // see http://en.wikipedia.org/wiki/Short_code#Regional_differences for reference - // - // However, in order to loose match 650-555-1212 and 555-1212, we need to set the min match - // to 7. - @UnsupportedAppUsage - static final int MIN_MATCH = 7; - /** * Checks a given number against the list of * emergency numbers provided by the RIL and SIM card. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index fd475619ca15..35b435d8dfb7 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2418,6 +2418,10 @@ public class TelephonyManager { * <p> * The ISO-3166 country code is provided in lowercase 2 character format. * <p> + * Note: In multi-sim, this returns a shared emergency network country iso from other + * subscription if the subscription used to create the TelephonyManager doesn't camp on + * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding + * slot. * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine * if on a CDMA network). * <p> diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index 511adf6ad65b..19d07242132b 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -22,6 +22,7 @@ import android.hardware.radio.V1_4.EmergencyNumberSource; import android.hardware.radio.V1_4.EmergencyServiceCategory; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; import android.telephony.Rlog; @@ -301,6 +302,9 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * The character in the number string is only the dial pad * character('0'-'9', '*', '+', or '#'). For example: 911. * + * If the number starts with carrier prefix, the carrier prefix is configured in + * {@link CarrierConfigManager#KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY}. + * * @return the dialing number. */ public @NonNull String getNumber() { diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java index a478606da22a..20aba4d97849 100644 --- a/telephony/java/android/telephony/ims/ImsReasonInfo.java +++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java @@ -871,6 +871,19 @@ public final class ImsReasonInfo implements Parcelable { */ public static final int CODE_REJECT_ONGOING_CS_CALL = 1621; + /** + * An attempt was made to place an emergency call over WFC when emergency services is not + * currently available in the current location. + * @hide + */ + public static final int CODE_EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 1622; + + /** + * Indicates that WiFi calling service is not available in the current location. + * @hide + */ + public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623; + /* * OEM specific error codes. To be used by OEMs when they don't want to reveal error code which * would be replaced by ERROR_UNSPECIFIED. diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 74af6bf6fe6e..8f8989909f9f 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -34,7 +34,9 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.Set; import java.util.WeakHashMap; @@ -106,6 +108,16 @@ public abstract class ImsFeature { public static final int FEATURE_MAX = 3; /** + * Used for logging purposes. + * @hide + */ + public static final Map<Integer, String> FEATURE_LOG_MAP = new HashMap<Integer, String>() {{ + put(FEATURE_EMERGENCY_MMTEL, "EMERGENCY_MMTEL"); + put(FEATURE_MMTEL, "MMTEL"); + put(FEATURE_RCS, "RCS"); + }}; + + /** * Integer values defining IMS features that are supported in ImsFeature. * @hide */ @@ -132,19 +144,34 @@ public abstract class ImsFeature { public @interface ImsState {} /** - * This {@link ImsFeature}'s state is unavailable and should not be communicated with. + * This {@link ImsFeature}'s state is unavailable and should not be communicated with. This will + * remove all bindings back to the framework. Any attempt to communicate with the framework + * during this time will result in an {@link IllegalStateException}. */ public static final int STATE_UNAVAILABLE = 0; /** - * This {@link ImsFeature} state is initializing and should not be communicated with. + * This {@link ImsFeature} state is initializing and should not be communicated with. This will + * remove all bindings back to the framework. Any attempt to communicate with the framework + * during this time will result in an {@link IllegalStateException}. */ public static final int STATE_INITIALIZING = 1; /** - * This {@link ImsFeature} is ready for communication. + * This {@link ImsFeature} is ready for communication. Do not attempt to call framework methods + * until {@link #onFeatureReady()} is called. */ public static final int STATE_READY = 2; /** + * Used for logging purposes. + * @hide + */ + public static final Map<Integer, String> STATE_LOG_MAP = new HashMap<Integer, String>() {{ + put(STATE_UNAVAILABLE, "UNAVAILABLE"); + put(STATE_INITIALIZING, "INITIALIZING"); + put(STATE_READY, "READY"); + }}; + + /** * Integer values defining the result codes that should be returned from * {@link #changeEnabledCapabilities} when the framework tries to set a feature's capability. * @hide @@ -208,11 +235,14 @@ public abstract class ImsFeature { /** * Contains the capabilities defined and supported by an ImsFeature in the form of a bit mask. + * <p> + * Typically this class is not used directly, but rather extended in subclasses of + * {@link ImsFeature} to provide service specific capabilities. * @hide - * @deprecated Use {@link MmTelFeature.MmTelCapabilities} instead. */ - @SystemApi // SystemApi only because it was leaked through type usage in a previous release. + @SystemApi public static class Capabilities { + /** @deprecated Use getters and accessors instead. */ protected int mCapabilities = 0; /** @@ -305,12 +335,12 @@ public abstract class ImsFeature { /** @hide */ protected final Object mLock = new Object(); - private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap( - new WeakHashMap<IImsFeatureStatusCallback, Boolean>()); + private final Set<IImsFeatureStatusCallback> mStatusCallbacks = + Collections.newSetFromMap(new WeakHashMap<>()); private @ImsState int mState = STATE_UNAVAILABLE; private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks - = new RemoteCallbackList<>(); + private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks = + new RemoteCallbackList<>(); private Capabilities mCapabilityStatus = new Capabilities(); /** @@ -322,6 +352,16 @@ public abstract class ImsFeature { } /** + * @return The SIM slot index associated with this ImsFeature. + * + * @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the + * subscription IDs associated with this slot. + */ + public final int getSlotIndex() { + return mSlotId; + } + + /** * @return The current state of the feature, defined as {@link #STATE_UNAVAILABLE}, * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}. * @hide @@ -490,7 +530,9 @@ public abstract class ImsFeature { public abstract void onFeatureRemoved(); /** - * Called when the feature has been initialized and communication with the framework is set up. + * Called after this ImsFeature has been initialized and has been set to the + * {@link ImsState#STATE_READY} state. + * <p> * Any attempt by this feature to access the framework before this method is called will return * with an {@link IllegalStateException}. * The IMS provider should use this method to trigger registration for this feature on the IMS diff --git a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java index 6ab946590899..3b298bb82f8b 100644 --- a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java +++ b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java @@ -21,7 +21,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.ims.feature.ImsFeature; import android.util.ArraySet; -import android.util.Pair; import java.util.Set; @@ -80,7 +79,7 @@ public final class ImsFeatureConfiguration implements Parcelable { @Override public String toString() { - return "{s=" + slotId + ", f=" + featureType + "}"; + return "{s=" + slotId + ", f=" + ImsFeature.FEATURE_LOG_MAP.get(featureType) + "}"; } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index dcfd193185cf..a65acac737d9 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -319,6 +319,7 @@ interface ITelephony { /** * Replaced by getDataActivityForSubId. */ + @UnsupportedAppUsage(maxTargetSdk = 28) int getDataActivity(); /** @@ -336,6 +337,7 @@ interface ITelephony { /** * Replaced by getDataStateForSubId. */ + @UnsupportedAppUsage(maxTargetSdk = 28) int getDataState(); /** diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index dc026d48c6cf..98fee83d83a9 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -49,8 +49,10 @@ interface ITelephonyRegistry { void notifySignalStrengthForPhoneId(in int phoneId, in int subId, in SignalStrength signalStrength); void notifyMessageWaitingChangedForPhoneId(in int phoneId, in int subId, in boolean mwi); + @UnsupportedAppUsage(maxTargetSdk = 28) void notifyCallForwardingChanged(boolean cfi); void notifyCallForwardingChangedForSubscriber(in int subId, boolean cfi); + @UnsupportedAppUsage(maxTargetSdk = 28) void notifyDataActivity(int state); void notifyDataActivityForSubscriber(in int subId, int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, @@ -63,8 +65,10 @@ interface ITelephonyRegistry { @UnsupportedAppUsage void notifyDataConnectionFailed(String apnType); void notifyDataConnectionFailedForSubscriber(int phoneId, int subId, String apnType); + @UnsupportedAppUsage(maxTargetSdk = 28) void notifyCellLocation(in Bundle cellLocation); void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation); + @UnsupportedAppUsage(maxTargetSdk = 28) void notifyOtaspChanged(in int subId, in int otaspMode); @UnsupportedAppUsage void notifyCellInfo(in List<CellInfo> cellInfo); diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java index 98f52cbf93da..90e2c1f6fe5e 100644 --- a/telephony/java/com/android/internal/telephony/SmsApplication.java +++ b/telephony/java/com/android/internal/telephony/SmsApplication.java @@ -158,7 +158,7 @@ public final class SmsApplication { ApplicationInfo appInfo; try { appInfo = pm.getApplicationInfoAsUser(mPackageName, 0, - UserHandle.getUserId(mUid)); + UserHandle.getUserHandleForUid(mUid)); } catch (NameNotFoundException e) { return null; } @@ -300,7 +300,7 @@ public final class SmsApplication { Uri.fromParts(SCHEME_SMSTO, "", null)); List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + UserHandle.of(userId)); for (ResolveInfo resolveInfo : respondServices) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; if (serviceInfo == null) { diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index 51c5d12dfe15..67103bfddce1 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -178,7 +178,7 @@ public final class TelephonyPermissions { // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage) + return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } @@ -226,7 +226,7 @@ public final class TelephonyPermissions { // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage) == + return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } @@ -367,7 +367,7 @@ public final class TelephonyPermissions { ApplicationInfo callingPackageInfo = null; try { callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser( - callingPackage, 0, UserHandle.getUserId(uid)); + callingPackage, 0, UserHandle.getUserHandleForUid(uid)); if (callingPackageInfo != null) { if (callingPackageInfo.isSystemApp()) { isPreinstalled = true; @@ -448,7 +448,7 @@ public final class TelephonyPermissions { // We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - return appOps.noteOp(AppOpsManager.OP_READ_CALL_LOG, uid, callingPackage) == + return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } @@ -471,7 +471,7 @@ public final class TelephonyPermissions { String callingPackage, String message) { // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) == + if (appOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage) == AppOpsManager.MODE_ALLOWED) { return true; } @@ -488,25 +488,18 @@ public final class TelephonyPermissions { // Can be read with READ_SMS too. try { context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message); - int opCode = AppOpsManager.permissionToOpCode(android.Manifest.permission.READ_SMS); - if (opCode != AppOpsManager.OP_NONE) { - return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; - } else { - return true; - } + return appOps.noteOp(AppOpsManager.OPSTR_READ_SMS, uid, callingPackage) + == AppOpsManager.MODE_ALLOWED; + } catch (SecurityException readSmsSecurityException) { } // Can be read with READ_PHONE_NUMBERS too. try { context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid, message); - int opCode = AppOpsManager.permissionToOpCode( - android.Manifest.permission.READ_PHONE_NUMBERS); - if (opCode != AppOpsManager.OP_NONE) { - return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; - } else { - return true; - } + return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, uid, callingPackage) + == AppOpsManager.MODE_ALLOWED; + } catch (SecurityException readPhoneNumberSecurityException) { } diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh index bc1aae03e9a6..614cbb7c9eb6 100755 --- a/tests/Codegen/runTest.sh +++ b/tests/Codegen/runTest.sh @@ -12,6 +12,7 @@ else header_and_eval m -j16 codegen_cli && \ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \ + header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java && \ cd $ANDROID_BUILD_TOP && header_and_eval mmma -j16 frameworks/base/tests/Codegen && \ header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \ diff --git a/tests/Codegen/src/com/android/codegentest/DateParcelling.java b/tests/Codegen/src/com/android/codegentest/MyDateParcelling.java index b0b00d032553..4faeb8ee8893 100644 --- a/tests/Codegen/src/com/android/codegentest/DateParcelling.java +++ b/tests/Codegen/src/com/android/codegentest/MyDateParcelling.java @@ -31,11 +31,11 @@ import java.util.concurrent.atomic.AtomicInteger; * * Ignore {@link #sInstanceCount} - used for testing. */ -public class DateParcelling implements Parcelling<Date> { +public class MyDateParcelling implements Parcelling<Date> { static AtomicInteger sInstanceCount = new AtomicInteger(0); - public DateParcelling() { + public MyDateParcelling() { sInstanceCount.getAndIncrement(); } diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java index f69a092ed3f7..30bb3ef5456b 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java @@ -53,11 +53,13 @@ import java.util.regex.Pattern; // genAidl = true, // implied by `implements Parcelable` // genGetters = true, // on by default // genConstDefs = true, // implied by presence of constants with common prefix + genBuilder = true, // on by default if optional fields present, but suppressed by + // genConstructor + genConstructor = true, // on by default but normally suppressed by genBuilder genEqualsHashCode = true, - genBuilder = true, genToString = true, genForEachField = true, - genConstructor = true // on by default but normally suppressed by genBuilder + genSetters = true ) public final class SampleDataClass implements Parcelable { @@ -136,48 +138,53 @@ public final class SampleDataClass implements Parcelable { private int mNum4; /** - * {@link Nullable} fields are considered optional and will not throw an exception if omitted - * (or set to null) when creating an instance either via a {@link Builder} or constructor. + * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields. */ private @Nullable String mName; /** - * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically + * Fields with default value expressions ("mFoo = ...") are optional, and are automatically * initialized to the provided default expression, unless explicitly set. + * + * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter} + * while mandatory fields are passed via {@link Builder#Builder constructor}. */ - private String mName2 = "Bob"; + private @NonNull String mName2 = "Bob"; /** - * Fields without {@link Nullable} annotation or default value are considered required. - * - * {@link NonNull} annotation is recommended on such non-primitive fields for documentation. + * Alternatively, when default value computation is expensive, + * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value. */ private @NonNull String mName4; + private static String defaultName4() { + // Expensive computation + return "Bob4"; + } /** * For parcelling, any field type supported by {@link Parcel} is supported out of the box. * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc. */ - private AccessibilityNodeInfo mOtherParcelable = null; + private @Nullable AccessibilityNodeInfo mOtherParcelable = null; /** * Additionally, support for parcelling other types can be added by implementing a * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation. * - * @see DateParcelling an example {@link Parcelling} implementation + * @see MyDateParcelling an example {@link Parcelling} implementation */ - @DataClass.ParcelWith(DateParcelling.class) - private Date mDate = new Date(42 * 42); + @DataClass.ParcelWith(MyDateParcelling.class) + private @NonNull Date mDate = new Date(42 * 42); /** * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn} * to encourage its reuse. */ @DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class) - private Pattern mPattern = Pattern.compile(""); + private @NonNull Pattern mPattern = Pattern.compile(""); /** * For lists, when using a {@link Builder}, other than a regular * {@link Builder#setLinkAddresses2(List) setter}, and additional * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience. */ - private List<LinkAddress> mLinkAddresses2 = new ArrayList<>(); + private @NonNull List<LinkAddress> mLinkAddresses2 = new ArrayList<>(); /** * For aesthetics, you may want to consider providing a singular version of the plural field * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method. @@ -185,7 +192,7 @@ public final class SampleDataClass implements Parcelable { * @see Builder#addLinkAddress(LinkAddress) */ @DataClass.PluralOf("linkAddress") - private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>(); + private @NonNull ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>(); /** * For array fields, when using a {@link Builder}, vararg argument format is used for * convenience. @@ -193,11 +200,6 @@ public final class SampleDataClass implements Parcelable { * @see Builder#setLinkAddresses4(LinkAddress...) */ private @Nullable LinkAddress[] mLinkAddresses4 = null; - /** - * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods - * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated. - */ - private boolean mActive = true; /** * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to @@ -206,7 +208,7 @@ public final class SampleDataClass implements Parcelable { * @see #getStateName * @see Builder#setStateName */ - private @StateName String mStateName = STATE_NAME_UNDEFINED; + private @StateName @NonNull String mStateName = STATE_NAME_UNDEFINED; /** * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value. */ @@ -220,11 +222,11 @@ public final class SampleDataClass implements Parcelable { /** * Making a field public will suppress getter generation in favor of accessing it directly. */ - public CharSequence charSeq = ""; + public @NonNull CharSequence charSeq = ""; /** * Final fields suppress generating a setter (when setters are requested). */ - private final LinkAddress[] mLinkAddresses5; + private final @Nullable LinkAddress[] mLinkAddresses5; /** * Transient fields are completely ignored and can be used for caching. */ @@ -261,7 +263,7 @@ public final class SampleDataClass implements Parcelable { * * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int) */ - private @android.annotation.IntRange(from = 0, to = 4) int mLimited = 3; + private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek = 3; /** * Unnamed validation annotation parameter gets supplied to the validating method named as * "value". @@ -272,6 +274,7 @@ public final class SampleDataClass implements Parcelable { * @see AnnotationValidations#validate(Class, Size, int, String, int) */ @Size(2) + @NonNull @Each @FloatRange(from = 0f) private float[] mCoords = new float[] {0f, 0f}; @@ -340,7 +343,6 @@ public final class SampleDataClass implements Parcelable { // Code below generated by codegen v1.0.0. - // on Jul 29, 2019, 2:50:21 PM PDT // // DO NOT MODIFY! // @@ -408,13 +410,9 @@ public final class SampleDataClass implements Parcelable { @DataClass.Generated.Member public @interface StateName {} - @DataClass.Generated( - time = 1564437021513L, - codegenVersion = "1.0.0", - sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java", - inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.DateParcelling.class) java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) java.util.regex.Pattern mPattern\nprivate java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate boolean mActive\nprivate @com.android.codegentest.SampleDataClass.StateName java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic java.lang.CharSequence charSeq\nprivate final android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=4L) int mLimited\nprivate @android.annotation.Size(2L) @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)") - -/** + /** + * Creates a new SampleDataClass. + * * @param num * Any property javadoc should go onto the field, and will be copied where appropriate, * including getters, constructor parameters, builder setters, etc. @@ -429,15 +427,16 @@ public final class SampleDataClass implements Parcelable { * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the * desired public API surface. * @param name - * {@link Nullable} fields are considered optional and will not throw an exception if omitted - * (or set to null) when creating an instance either via a {@link Builder} or constructor. + * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields. * @param name2 - * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically + * Fields with default value expressions ("mFoo = ...") are optional, and are automatically * initialized to the provided default expression, unless explicitly set. - * @param name4 - * Fields without {@link Nullable} annotation or default value are considered required. * - * {@link NonNull} annotation is recommended on such non-primitive fields for documentation. + * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter} + * while mandatory fields are passed via {@link Builder#Builder constructor}. + * @param name4 + * Alternatively, when default value computation is expensive, + * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value. * @param otherParcelable * For parcelling, any field type supported by {@link Parcel} is supported out of the box. * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc. @@ -457,9 +456,6 @@ public final class SampleDataClass implements Parcelable { * @param linkAddresses4 * For array fields, when using a {@link Builder}, vararg argument format is used for * convenience. - * @param active - * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods - * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated. * @param stateName * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to * getter/constructor/setter/builder parameters, making for a nicer api. @@ -480,7 +476,7 @@ public final class SampleDataClass implements Parcelable { * You can also extend support to your custom annotations by creating another corresponding * overloads like * {@link AnnotationValidations#validate(Class, UserIdInt, int)}. - * @param limited + * @param dayOfWeek * Validation annotations may also have parameters. * * Parameter values will be supplied to validation method as name-value pairs. @@ -497,50 +493,49 @@ public final class SampleDataClass implements Parcelable { int num2, int num4, @Nullable String name, - String name2, + @NonNull String name2, @NonNull String name4, - AccessibilityNodeInfo otherParcelable, - Date date, - Pattern pattern, - List<LinkAddress> linkAddresses2, - ArrayList<LinkAddress> linkAddresses, + @Nullable AccessibilityNodeInfo otherParcelable, + @NonNull Date date, + @NonNull Pattern pattern, + @NonNull List<LinkAddress> linkAddresses2, + @NonNull ArrayList<LinkAddress> linkAddresses, @Nullable LinkAddress[] linkAddresses4, - boolean active, - @StateName String stateName, + @StateName @NonNull String stateName, @RequestFlags int flags, @State int state, - CharSequence charSeq, - LinkAddress[] linkAddresses5, + @NonNull CharSequence charSeq, + @Nullable LinkAddress[] linkAddresses5, @StringRes int stringRes, - @android.annotation.IntRange(from = 0, to = 4) int limited, - @Size(2) @FloatRange(from = 0f) float[] coords) { + @android.annotation.IntRange(from = 0, to = 6) int dayOfWeek, + @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] coords) { this.mNum = num; this.mNum2 = num2; this.mNum4 = num4; this.mName = name; this.mName2 = name2; - this.mName4 = Preconditions.checkNotNull(name4); + AnnotationValidations.validate( + NonNull.class, null, mName2); + this.mName4 = name4; + AnnotationValidations.validate( + NonNull.class, null, mName4); this.mOtherParcelable = otherParcelable; this.mDate = date; + AnnotationValidations.validate( + NonNull.class, null, mDate); this.mPattern = pattern; + AnnotationValidations.validate( + NonNull.class, null, mPattern); this.mLinkAddresses2 = linkAddresses2; + AnnotationValidations.validate( + NonNull.class, null, mLinkAddresses2); this.mLinkAddresses = linkAddresses; + AnnotationValidations.validate( + NonNull.class, null, mLinkAddresses); this.mLinkAddresses4 = linkAddresses4; - this.mActive = active; this.mStateName = stateName; - this.mFlags = flags; - this.mState = state; - this.charSeq = charSeq; - this.mLinkAddresses5 = linkAddresses5; - this.mStringRes = stringRes; - this.mLimited = limited; - this.mCoords = coords; - AnnotationValidations.validate( - NonNull.class, null, mName4); - //noinspection PointlessBooleanExpression - if (true - && !(Objects.equals(mStateName, STATE_NAME_UNDEFINED)) + if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED)) && !(Objects.equals(mStateName, STATE_NAME_ON)) && !(Objects.equals(mStateName, STATE_NAME_OFF))) { throw new java.lang.IllegalArgumentException( @@ -550,17 +545,18 @@ public final class SampleDataClass implements Parcelable { + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")"); } + AnnotationValidations.validate( + NonNull.class, null, mStateName); + this.mFlags = flags; - //noinspection PointlessBitwiseExpression Preconditions.checkFlagsArgument( - mFlags, 0 - | FLAG_MANUAL_REQUEST + mFlags, + FLAG_MANUAL_REQUEST | FLAG_COMPATIBILITY_MODE_REQUEST | FLAG_AUGMENTED_REQUEST); + this.mState = state; - //noinspection PointlessBooleanExpression - if (true - && !(mState == STATE_UNDEFINED) + if (!(mState == STATE_UNDEFINED) && !(mState == STATE_ON) && !(mState == STATE_OFF)) { throw new java.lang.IllegalArgumentException( @@ -570,15 +566,24 @@ public final class SampleDataClass implements Parcelable { + "STATE_OFF(" + STATE_OFF + ")"); } + this.charSeq = charSeq; + AnnotationValidations.validate( + NonNull.class, null, charSeq); + this.mLinkAddresses5 = linkAddresses5; + this.mStringRes = stringRes; AnnotationValidations.validate( StringRes.class, null, mStringRes); + this.mDayOfWeek = dayOfWeek; AnnotationValidations.validate( - android.annotation.IntRange.class, null, mLimited, + android.annotation.IntRange.class, null, mDayOfWeek, "from", 0, - "to", 4); + "to", 6); + this.mCoords = coords; AnnotationValidations.validate( Size.class, null, mCoords.length, "value", 2); + AnnotationValidations.validate( + NonNull.class, null, mCoords); int coordsSize = mCoords.length; for (int i = 0; i < coordsSize; i++) { AnnotationValidations.validate( @@ -628,8 +633,7 @@ public final class SampleDataClass implements Parcelable { } /** - * {@link Nullable} fields are considered optional and will not throw an exception if omitted - * (or set to null) when creating an instance either via a {@link Builder} or constructor. + * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields. */ @DataClass.Generated.Member public @Nullable String getName() { @@ -637,18 +641,20 @@ public final class SampleDataClass implements Parcelable { } /** - * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically + * Fields with default value expressions ("mFoo = ...") are optional, and are automatically * initialized to the provided default expression, unless explicitly set. + * + * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter} + * while mandatory fields are passed via {@link Builder#Builder constructor}. */ @DataClass.Generated.Member - public String getName2() { + public @NonNull String getName2() { return mName2; } /** - * Fields without {@link Nullable} annotation or default value are considered required. - * - * {@link NonNull} annotation is recommended on such non-primitive fields for documentation. + * Alternatively, when default value computation is expensive, + * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value. */ @DataClass.Generated.Member public @NonNull String getName4() { @@ -660,7 +666,7 @@ public final class SampleDataClass implements Parcelable { * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc. */ @DataClass.Generated.Member - public AccessibilityNodeInfo getOtherParcelable() { + public @Nullable AccessibilityNodeInfo getOtherParcelable() { return mOtherParcelable; } @@ -668,10 +674,10 @@ public final class SampleDataClass implements Parcelable { * Additionally, support for parcelling other types can be added by implementing a * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation. * - * @see DateParcelling an example {@link Parcelling} implementation + * @see MyDateParcelling an example {@link Parcelling} implementation */ @DataClass.Generated.Member - public Date getDate() { + public @NonNull Date getDate() { return mDate; } @@ -680,7 +686,7 @@ public final class SampleDataClass implements Parcelable { * to encourage its reuse. */ @DataClass.Generated.Member - public Pattern getPattern() { + public @NonNull Pattern getPattern() { return mPattern; } @@ -690,7 +696,7 @@ public final class SampleDataClass implements Parcelable { * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience. */ @DataClass.Generated.Member - public List<LinkAddress> getLinkAddresses2() { + public @NonNull List<LinkAddress> getLinkAddresses2() { return mLinkAddresses2; } @@ -701,20 +707,11 @@ public final class SampleDataClass implements Parcelable { * @see Builder#addLinkAddress(LinkAddress) */ @DataClass.Generated.Member - public ArrayList<LinkAddress> getLinkAddresses() { + public @NonNull ArrayList<LinkAddress> getLinkAddresses() { return mLinkAddresses; } /** - * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods - * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated. - */ - @DataClass.Generated.Member - public boolean isActive() { - return mActive; - } - - /** * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to * getter/constructor/setter/builder parameters, making for a nicer api. * @@ -722,7 +719,7 @@ public final class SampleDataClass implements Parcelable { * @see Builder#setStateName */ @DataClass.Generated.Member - public @StateName String getStateName() { + public @StateName @NonNull String getStateName() { return mStateName; } @@ -746,7 +743,7 @@ public final class SampleDataClass implements Parcelable { * Final fields suppress generating a setter (when setters are requested). */ @DataClass.Generated.Member - public LinkAddress[] getLinkAddresses5() { + public @Nullable LinkAddress[] getLinkAddresses5() { return mLinkAddresses5; } @@ -775,8 +772,8 @@ public final class SampleDataClass implements Parcelable { * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int) */ @DataClass.Generated.Member - public @android.annotation.IntRange(from = 0, to = 4) int getLimited() { - return mLimited; + public @android.annotation.IntRange(from = 0, to = 6) int getDayOfWeek() { + return mDayOfWeek; } /** @@ -789,7 +786,7 @@ public final class SampleDataClass implements Parcelable { * @see AnnotationValidations#validate(Class, Size, int, String, int) */ @DataClass.Generated.Member - public @Size(2) @FloatRange(from = 0f) float[] getCoords() { + public @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] getCoords() { return mCoords; } @@ -810,6 +807,282 @@ public final class SampleDataClass implements Parcelable { return tmpStorage; } + /** + * Any property javadoc should go onto the field, and will be copied where appropriate, + * including getters, constructor parameters, builder setters, etc. + * + * <p> + * This allows to avoid the burden of maintaining copies of the same documentation + * pieces in multiple places for each field. + */ + @DataClass.Generated.Member + public SampleDataClass setNum(int value) { + mNum = value; + return this; + } + + /** + * Various javadoc features should work as expected when copied, e.g {@code code}, + * {@link #mName links}, <a href="https://google.com">html links</a>, etc. + * + * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks. + */ + @DataClass.Generated.Member + public SampleDataClass setNum2(int value) { + mNum2 = value; + return this; + } + + /** + * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the + * desired public API surface. + * + * @see #getNum4() is hidden + * @see Builder#setNum4(int) also hidden + * @hide + */ + @DataClass.Generated.Member + public SampleDataClass setNum4(int value) { + mNum4 = value; + return this; + } + + /** + * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields. + */ + @DataClass.Generated.Member + public SampleDataClass setName(@Nullable String value) { + mName = value; + return this; + } + + /** + * Fields with default value expressions ("mFoo = ...") are optional, and are automatically + * initialized to the provided default expression, unless explicitly set. + * + * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter} + * while mandatory fields are passed via {@link Builder#Builder constructor}. + */ + @DataClass.Generated.Member + public SampleDataClass setName2(@NonNull String value) { + mName2 = value; + AnnotationValidations.validate( + NonNull.class, null, mName2); + return this; + } + + /** + * Alternatively, when default value computation is expensive, + * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value. + */ + @DataClass.Generated.Member + public SampleDataClass setName4(@NonNull String value) { + mName4 = value; + AnnotationValidations.validate( + NonNull.class, null, mName4); + return this; + } + + /** + * For parcelling, any field type supported by {@link Parcel} is supported out of the box. + * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc. + */ + @DataClass.Generated.Member + public SampleDataClass setOtherParcelable(@Nullable AccessibilityNodeInfo value) { + mOtherParcelable = value; + return this; + } + + /** + * Additionally, support for parcelling other types can be added by implementing a + * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation. + * + * @see MyDateParcelling an example {@link Parcelling} implementation + */ + @DataClass.Generated.Member + public SampleDataClass setDate(@NonNull Date value) { + mDate = value; + AnnotationValidations.validate( + NonNull.class, null, mDate); + return this; + } + + /** + * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn} + * to encourage its reuse. + */ + @DataClass.Generated.Member + public SampleDataClass setPattern(@NonNull Pattern value) { + mPattern = value; + AnnotationValidations.validate( + NonNull.class, null, mPattern); + return this; + } + + /** + * For lists, when using a {@link Builder}, other than a regular + * {@link Builder#setLinkAddresses2(List) setter}, and additional + * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience. + */ + @DataClass.Generated.Member + public SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) { + mLinkAddresses2 = value; + AnnotationValidations.validate( + NonNull.class, null, mLinkAddresses2); + return this; + } + + /** + * For aesthetics, you may want to consider providing a singular version of the plural field + * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method. + * + * @see Builder#addLinkAddress(LinkAddress) + */ + @DataClass.Generated.Member + public SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) { + mLinkAddresses = value; + AnnotationValidations.validate( + NonNull.class, null, mLinkAddresses); + return this; + } + + /** + * For array fields, when using a {@link Builder}, vararg argument format is used for + * convenience. + * + * @see Builder#setLinkAddresses4(LinkAddress...) + */ + @DataClass.Generated.Member + public SampleDataClass setLinkAddresses4(@Nullable LinkAddress... value) { + mLinkAddresses4 = value; + return this; + } + + /** + * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to + * getter/constructor/setter/builder parameters, making for a nicer api. + * + * @see #getStateName + * @see Builder#setStateName + */ + @DataClass.Generated.Member + public SampleDataClass setStateName(@StateName @NonNull String value) { + mStateName = value; + + if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED)) + && !(Objects.equals(mStateName, STATE_NAME_ON)) + && !(Objects.equals(mStateName, STATE_NAME_OFF))) { + throw new java.lang.IllegalArgumentException( + "stateName was " + mStateName + " but must be one of: " + + "STATE_NAME_UNDEFINED(" + STATE_NAME_UNDEFINED + "), " + + "STATE_NAME_ON(" + STATE_NAME_ON + "), " + + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")"); + } + + AnnotationValidations.validate( + NonNull.class, null, mStateName); + return this; + } + + /** + * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value. + */ + @DataClass.Generated.Member + public SampleDataClass setFlags(@RequestFlags int value) { + mFlags = value; + + Preconditions.checkFlagsArgument( + mFlags, + FLAG_MANUAL_REQUEST + | FLAG_COMPATIBILITY_MODE_REQUEST + | FLAG_AUGMENTED_REQUEST); + return this; + } + + /** + * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s + */ + @DataClass.Generated.Member + public SampleDataClass setState(@State int value) { + mState = value; + + if (!(mState == STATE_UNDEFINED) + && !(mState == STATE_ON) + && !(mState == STATE_OFF)) { + throw new java.lang.IllegalArgumentException( + "state was " + mState + " but must be one of: " + + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), " + + "STATE_ON(" + STATE_ON + "), " + + "STATE_OFF(" + STATE_OFF + ")"); + } + + return this; + } + + /** + * Fields with certain annotations are automatically validated in constructor + * + * You can see overloads in {@link AnnotationValidations} for a list of currently + * supported ones. + * + * You can also extend support to your custom annotations by creating another corresponding + * overloads like + * {@link AnnotationValidations#validate(Class, UserIdInt, int)}. + * + * @see #SampleDataClass + */ + @DataClass.Generated.Member + public SampleDataClass setStringRes(@StringRes int value) { + mStringRes = value; + AnnotationValidations.validate( + StringRes.class, null, mStringRes); + return this; + } + + /** + * Validation annotations may also have parameters. + * + * Parameter values will be supplied to validation method as name-value pairs. + * + * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int) + */ + @DataClass.Generated.Member + public SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) { + mDayOfWeek = value; + AnnotationValidations.validate( + android.annotation.IntRange.class, null, mDayOfWeek, + "from", 0, + "to", 6); + return this; + } + + /** + * Unnamed validation annotation parameter gets supplied to the validating method named as + * "value". + * + * Validation annotations following {@link Each} annotation, will be applied for each + * array/collection element instead. + * + * @see AnnotationValidations#validate(Class, Size, int, String, int) + */ + @DataClass.Generated.Member + public SampleDataClass setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) { + mCoords = value; + AnnotationValidations.validate( + Size.class, null, mCoords.length, + "value", 2); + AnnotationValidations.validate( + NonNull.class, null, mCoords); + int coordsSize = mCoords.length; + for (int i = 0; i < coordsSize; i++) { + AnnotationValidations.validate( + FloatRange.class, null, mCoords[i], + "from", 0f); + } + + return this; + } + @Override @DataClass.Generated.Member public String toString() { @@ -829,14 +1102,13 @@ public final class SampleDataClass implements Parcelable { "linkAddresses2 = " + mLinkAddresses2 + ", " + "linkAddresses = " + mLinkAddresses + ", " + "linkAddresses4 = " + java.util.Arrays.toString(mLinkAddresses4) + ", " + - "active = " + mActive + ", " + "stateName = " + mStateName + ", " + "flags = " + requestFlagsToString(mFlags) + ", " + "state = " + stateToString(mState) + ", " + "charSeq = " + charSeq + ", " + "linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " + "stringRes = " + mStringRes + ", " + - "limited = " + mLimited + ", " + + "dayOfWeek = " + mDayOfWeek + ", " + "coords = " + java.util.Arrays.toString(mCoords) + " }"; } @@ -866,14 +1138,13 @@ public final class SampleDataClass implements Parcelable { && Objects.equals(mLinkAddresses2, that.mLinkAddresses2) && Objects.equals(mLinkAddresses, that.mLinkAddresses) && java.util.Arrays.equals(mLinkAddresses4, that.mLinkAddresses4) - && mActive == that.mActive && Objects.equals(mStateName, that.mStateName) && mFlags == that.mFlags && mState == that.mState && Objects.equals(charSeq, that.charSeq) && java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5) && mStringRes == that.mStringRes - && mLimited == that.mLimited + && mDayOfWeek == that.mDayOfWeek && java.util.Arrays.equals(mCoords, that.mCoords); } @@ -896,14 +1167,13 @@ public final class SampleDataClass implements Parcelable { _hash = 31 * _hash + Objects.hashCode(mLinkAddresses2); _hash = 31 * _hash + Objects.hashCode(mLinkAddresses); _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses4); - _hash = 31 * _hash + Boolean.hashCode(mActive); _hash = 31 * _hash + Objects.hashCode(mStateName); _hash = 31 * _hash + mFlags; _hash = 31 * _hash + mState; _hash = 31 * _hash + Objects.hashCode(charSeq); _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses5); _hash = 31 * _hash + mStringRes; - _hash = 31 * _hash + mLimited; + _hash = 31 * _hash + mDayOfWeek; _hash = 31 * _hash + java.util.Arrays.hashCode(mCoords); return _hash; } @@ -924,14 +1194,13 @@ public final class SampleDataClass implements Parcelable { actionObject.acceptObject(this, "linkAddresses2", mLinkAddresses2); actionObject.acceptObject(this, "linkAddresses", mLinkAddresses); actionObject.acceptObject(this, "linkAddresses4", mLinkAddresses4); - actionObject.acceptObject(this, "active", mActive); actionObject.acceptObject(this, "stateName", mStateName); actionInt.acceptInt(this, "flags", mFlags); actionInt.acceptInt(this, "state", mState); actionObject.acceptObject(this, "charSeq", charSeq); actionObject.acceptObject(this, "linkAddresses5", mLinkAddresses5); actionInt.acceptInt(this, "stringRes", mStringRes); - actionInt.acceptInt(this, "limited", mLimited); + actionInt.acceptInt(this, "dayOfWeek", mDayOfWeek); actionObject.acceptObject(this, "coords", mCoords); } @@ -951,25 +1220,24 @@ public final class SampleDataClass implements Parcelable { action.acceptObject(this, "linkAddresses2", mLinkAddresses2); action.acceptObject(this, "linkAddresses", mLinkAddresses); action.acceptObject(this, "linkAddresses4", mLinkAddresses4); - action.acceptObject(this, "active", mActive); action.acceptObject(this, "stateName", mStateName); action.acceptObject(this, "flags", mFlags); action.acceptObject(this, "state", mState); action.acceptObject(this, "charSeq", charSeq); action.acceptObject(this, "linkAddresses5", mLinkAddresses5); action.acceptObject(this, "stringRes", mStringRes); - action.acceptObject(this, "limited", mLimited); + action.acceptObject(this, "dayOfWeek", mDayOfWeek); action.acceptObject(this, "coords", mCoords); } @DataClass.Generated.Member static Parcelling<Date> sParcellingForDate = Parcelling.Cache.get( - DateParcelling.class); + MyDateParcelling.class); static { if (sParcellingForDate == null) { sParcellingForDate = Parcelling.Cache.put( - new DateParcelling()); + new MyDateParcelling()); } } @@ -991,40 +1259,31 @@ public final class SampleDataClass implements Parcelable { // void parcelFieldName(Parcel dest, int flags) { ... } long flg = 0; - if (mActive) flg |= 0x1000; if (mName != null) flg |= 0x8; - if (mName2 != null) flg |= 0x10; if (mOtherParcelable != null) flg |= 0x40; - if (mDate != null) flg |= 0x80; - if (mPattern != null) flg |= 0x100; - if (mLinkAddresses2 != null) flg |= 0x200; - if (mLinkAddresses != null) flg |= 0x400; if (mLinkAddresses4 != null) flg |= 0x800; - if (mStateName != null) flg |= 0x2000; - if (charSeq != null) flg |= 0x10000; - if (mLinkAddresses5 != null) flg |= 0x20000; - if (mCoords != null) flg |= 0x100000; + if (mLinkAddresses5 != null) flg |= 0x10000; dest.writeLong(flg); dest.writeInt(mNum); dest.writeInt(mNum2); dest.writeInt(mNum4); if (mName != null) dest.writeString(mName); - if (mName2 != null) dest.writeString(mName2); + dest.writeString(mName2); dest.writeString(mName4); if (mOtherParcelable != null) dest.writeTypedObject(mOtherParcelable, flags); sParcellingForDate.parcel(mDate, dest, flags); sParcellingForPattern.parcel(mPattern, dest, flags); - if (mLinkAddresses2 != null) dest.writeParcelableList(mLinkAddresses2, flags); - if (mLinkAddresses != null) dest.writeParcelableList(mLinkAddresses, flags); + dest.writeParcelableList(mLinkAddresses2, flags); + dest.writeParcelableList(mLinkAddresses, flags); if (mLinkAddresses4 != null) dest.writeTypedArray(mLinkAddresses4, flags); - if (mStateName != null) dest.writeString(mStateName); + dest.writeString(mStateName); dest.writeInt(mFlags); dest.writeInt(mState); - if (charSeq != null) dest.writeCharSequence(charSeq); + dest.writeCharSequence(charSeq); if (mLinkAddresses5 != null) dest.writeTypedArray(mLinkAddresses5, flags); dest.writeInt(mStringRes); - dest.writeInt(mLimited); - if (mCoords != null) dest.writeFloatArray(mCoords); + dest.writeInt(mDayOfWeek); + dest.writeFloatArray(mCoords); } @Override @@ -1046,35 +1305,28 @@ public final class SampleDataClass implements Parcelable { // static FieldType unparcelFieldName(Parcel in) { ... } long flg = in.readLong(); - boolean active = (flg & 0x1000) != 0; int num = in.readInt(); int num2 = in.readInt(); int num4 = in.readInt(); String name = (flg & 0x8) == 0 ? null : in.readString(); - String name2 = (flg & 0x10) == 0 ? null : in.readString(); + String name2 = in.readString(); String name4 = in.readString(); AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR); Date date = sParcellingForDate.unparcel(in); Pattern pattern = sParcellingForPattern.unparcel(in); - List<LinkAddress> linkAddresses2 = null; - if ((flg & 0x200) != 0) { - linkAddresses2 = new ArrayList<>(); - in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader()); - } - ArrayList<LinkAddress> linkAddresses = null; - if ((flg & 0x400) != 0) { - linkAddresses = new ArrayList<>(); - in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader()); - } + List<LinkAddress> linkAddresses2 = new ArrayList<>(); + in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader()); + ArrayList<LinkAddress> linkAddresses = new ArrayList<>(); + in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader()); LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR); - String stateName = (flg & 0x2000) == 0 ? null : in.readString(); + String stateName = in.readString(); int flags = in.readInt(); int state = in.readInt(); - CharSequence _charSeq = (flg & 0x10000) == 0 ? null : (CharSequence) in.readCharSequence(); - LinkAddress[] linkAddresses5 = (flg & 0x20000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR); + CharSequence _charSeq = (CharSequence) in.readCharSequence(); + LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR); int stringRes = in.readInt(); - int limited = in.readInt(); - float[] coords = (flg & 0x100000) == 0 ? null : in.createFloatArray(); + int dayOfWeek = in.readInt(); + float[] coords = in.createFloatArray(); return new SampleDataClass( num, num2, @@ -1088,14 +1340,13 @@ public final class SampleDataClass implements Parcelable { linkAddresses2, linkAddresses, linkAddresses4, - active, stateName, flags, state, _charSeq, linkAddresses5, stringRes, - limited, + dayOfWeek, coords); } }; @@ -1105,34 +1356,74 @@ public final class SampleDataClass implements Parcelable { */ @SuppressWarnings("WeakerAccess") @DataClass.Generated.Member - public static class Builder - extends android.provider.OneTimeUseBuilder<SampleDataClass> { - - protected int mNum; - protected int mNum2; - protected int mNum4; - protected @Nullable String mName; - protected String mName2; - protected @NonNull String mName4; - protected AccessibilityNodeInfo mOtherParcelable; - protected Date mDate; - protected Pattern mPattern; - protected List<LinkAddress> mLinkAddresses2; - protected ArrayList<LinkAddress> mLinkAddresses; - protected @Nullable LinkAddress[] mLinkAddresses4; - protected boolean mActive; - protected @StateName String mStateName; - protected @RequestFlags int mFlags; - protected @State int mState; - protected CharSequence charSeq; - protected LinkAddress[] mLinkAddresses5; - protected @StringRes int mStringRes; - protected @android.annotation.IntRange(from = 0, to = 4) int mLimited; - protected @Size(2) @FloatRange(from = 0f) float[] mCoords; - - protected long mBuilderFieldsSet = 0L; - - public Builder() {}; + public static class Builder { + + private int mNum; + private int mNum2; + private int mNum4; + private @Nullable String mName; + private @NonNull String mName2; + private @NonNull String mName4; + private @Nullable AccessibilityNodeInfo mOtherParcelable; + private @NonNull Date mDate; + private @NonNull Pattern mPattern; + private @NonNull List<LinkAddress> mLinkAddresses2; + private @NonNull ArrayList<LinkAddress> mLinkAddresses; + private @Nullable LinkAddress[] mLinkAddresses4; + private @StateName @NonNull String mStateName; + private @RequestFlags int mFlags; + private @State int mState; + private @NonNull CharSequence charSeq; + private @Nullable LinkAddress[] mLinkAddresses5; + private @StringRes int mStringRes; + private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek; + private @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] mCoords; + + private long mBuilderFieldsSet = 0L; + + /** + * Creates a new Builder. + * + * @param num + * Any property javadoc should go onto the field, and will be copied where appropriate, + * including getters, constructor parameters, builder setters, etc. + * + * <p> + * This allows to avoid the burden of maintaining copies of the same documentation + * pieces in multiple places for each field. + * @param num2 + * Various javadoc features should work as expected when copied, e.g {@code code}, + * {@link #mName links}, <a href="https://google.com">html links</a>, etc. + * @param num4 + * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the + * desired public API surface. + * @param name + * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields. + * @param flags + * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value. + * @param linkAddresses5 + * Final fields suppress generating a setter (when setters are requested). + */ + public Builder( + int num, + int num2, + int num4, + @Nullable String name, + @RequestFlags int flags, + @Nullable LinkAddress[] linkAddresses5) { + mNum = num; + mNum2 = num2; + mNum4 = num4; + mName = name; + mFlags = flags; + + Preconditions.checkFlagsArgument( + mFlags, + FLAG_MANUAL_REQUEST + | FLAG_COMPATIBILITY_MODE_REQUEST + | FLAG_AUGMENTED_REQUEST); + mLinkAddresses5 = linkAddresses5; + } /** * Any property javadoc should go onto the field, and will be copied where appropriate, @@ -1143,7 +1434,7 @@ public final class SampleDataClass implements Parcelable { * pieces in multiple places for each field. */ @DataClass.Generated.Member - public Builder setNum(int value) { + public @NonNull Builder setNum(int value) { checkNotUsed(); mBuilderFieldsSet |= 0x1; mNum = value; @@ -1157,7 +1448,7 @@ public final class SampleDataClass implements Parcelable { * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks. */ @DataClass.Generated.Member - public Builder setNum2(int value) { + public @NonNull Builder setNum2(int value) { checkNotUsed(); mBuilderFieldsSet |= 0x2; mNum2 = value; @@ -1173,7 +1464,7 @@ public final class SampleDataClass implements Parcelable { * @hide */ @DataClass.Generated.Member - public Builder setNum4(int value) { + public @NonNull Builder setNum4(int value) { checkNotUsed(); mBuilderFieldsSet |= 0x4; mNum4 = value; @@ -1181,11 +1472,10 @@ public final class SampleDataClass implements Parcelable { } /** - * {@link Nullable} fields are considered optional and will not throw an exception if omitted - * (or set to null) when creating an instance either via a {@link Builder} or constructor. + * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields. */ @DataClass.Generated.Member - public Builder setName(@Nullable String value) { + public @NonNull Builder setName(@Nullable String value) { checkNotUsed(); mBuilderFieldsSet |= 0x8; mName = value; @@ -1193,11 +1483,14 @@ public final class SampleDataClass implements Parcelable { } /** - * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically + * Fields with default value expressions ("mFoo = ...") are optional, and are automatically * initialized to the provided default expression, unless explicitly set. + * + * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter} + * while mandatory fields are passed via {@link Builder#Builder constructor}. */ @DataClass.Generated.Member - public Builder setName2(String value) { + public @NonNull Builder setName2(@NonNull String value) { checkNotUsed(); mBuilderFieldsSet |= 0x10; mName2 = value; @@ -1205,12 +1498,11 @@ public final class SampleDataClass implements Parcelable { } /** - * Fields without {@link Nullable} annotation or default value are considered required. - * - * {@link NonNull} annotation is recommended on such non-primitive fields for documentation. + * Alternatively, when default value computation is expensive, + * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value. */ @DataClass.Generated.Member - public Builder setName4(@NonNull String value) { + public @NonNull Builder setName4(@NonNull String value) { checkNotUsed(); mBuilderFieldsSet |= 0x20; mName4 = value; @@ -1222,7 +1514,7 @@ public final class SampleDataClass implements Parcelable { * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc. */ @DataClass.Generated.Member - public Builder setOtherParcelable(AccessibilityNodeInfo value) { + public @NonNull Builder setOtherParcelable(@Nullable AccessibilityNodeInfo value) { checkNotUsed(); mBuilderFieldsSet |= 0x40; mOtherParcelable = value; @@ -1233,10 +1525,10 @@ public final class SampleDataClass implements Parcelable { * Additionally, support for parcelling other types can be added by implementing a * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation. * - * @see DateParcelling an example {@link Parcelling} implementation + * @see MyDateParcelling an example {@link Parcelling} implementation */ @DataClass.Generated.Member - public Builder setDate(Date value) { + public @NonNull Builder setDate(@NonNull Date value) { checkNotUsed(); mBuilderFieldsSet |= 0x80; mDate = value; @@ -1248,7 +1540,7 @@ public final class SampleDataClass implements Parcelable { * to encourage its reuse. */ @DataClass.Generated.Member - public Builder setPattern(Pattern value) { + public @NonNull Builder setPattern(@NonNull Pattern value) { checkNotUsed(); mBuilderFieldsSet |= 0x100; mPattern = value; @@ -1261,7 +1553,7 @@ public final class SampleDataClass implements Parcelable { * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience. */ @DataClass.Generated.Member - public Builder setLinkAddresses2(List<LinkAddress> value) { + public @NonNull Builder setLinkAddresses2(@NonNull List<LinkAddress> value) { checkNotUsed(); mBuilderFieldsSet |= 0x200; mLinkAddresses2 = value; @@ -1270,7 +1562,7 @@ public final class SampleDataClass implements Parcelable { /** @see #setLinkAddresses2 */ @DataClass.Generated.Member - public Builder addLinkAddresses2(@NonNull LinkAddress value) { + public @NonNull Builder addLinkAddresses2(LinkAddress value) { // You can refine this method's name by providing item's singular name, e.g.: // @DataClass.PluralOf("item")) mItems = ... @@ -1286,7 +1578,7 @@ public final class SampleDataClass implements Parcelable { * @see Builder#addLinkAddress(LinkAddress) */ @DataClass.Generated.Member - public Builder setLinkAddresses(ArrayList<LinkAddress> value) { + public @NonNull Builder setLinkAddresses(@NonNull ArrayList<LinkAddress> value) { checkNotUsed(); mBuilderFieldsSet |= 0x400; mLinkAddresses = value; @@ -1295,7 +1587,7 @@ public final class SampleDataClass implements Parcelable { /** @see #setLinkAddresses */ @DataClass.Generated.Member - public Builder addLinkAddress(@NonNull LinkAddress value) { + public @NonNull Builder addLinkAddress(LinkAddress value) { if (mLinkAddresses == null) setLinkAddresses(new ArrayList<>()); mLinkAddresses.add(value); return this; @@ -1308,7 +1600,7 @@ public final class SampleDataClass implements Parcelable { * @see Builder#setLinkAddresses4(LinkAddress...) */ @DataClass.Generated.Member - public Builder setLinkAddresses4(@Nullable LinkAddress... value) { + public @NonNull Builder setLinkAddresses4(@Nullable LinkAddress... value) { checkNotUsed(); mBuilderFieldsSet |= 0x800; mLinkAddresses4 = value; @@ -1316,30 +1608,6 @@ public final class SampleDataClass implements Parcelable { } /** - * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods - * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated. - */ - @DataClass.Generated.Member - public Builder setActive(boolean value) { - checkNotUsed(); - mBuilderFieldsSet |= 0x1000; - mActive = value; - return this; - } - - /** @see #setActive */ - @DataClass.Generated.Member - public Builder markActive() { - return setActive(true); - } - - /** @see #setActive */ - @DataClass.Generated.Member - public Builder markNotActive() { - return setActive(false); - } - - /** * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to * getter/constructor/setter/builder parameters, making for a nicer api. * @@ -1347,9 +1615,9 @@ public final class SampleDataClass implements Parcelable { * @see Builder#setStateName */ @DataClass.Generated.Member - public Builder setStateName(@StateName String value) { + public @NonNull Builder setStateName(@StateName @NonNull String value) { checkNotUsed(); - mBuilderFieldsSet |= 0x2000; + mBuilderFieldsSet |= 0x1000; mStateName = value; return this; } @@ -1358,9 +1626,9 @@ public final class SampleDataClass implements Parcelable { * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value. */ @DataClass.Generated.Member - public Builder setFlags(@RequestFlags int value) { + public @NonNull Builder setFlags(@RequestFlags int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x4000; + mBuilderFieldsSet |= 0x2000; mFlags = value; return this; } @@ -1369,9 +1637,9 @@ public final class SampleDataClass implements Parcelable { * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s */ @DataClass.Generated.Member - public Builder setState(@State int value) { + public @NonNull Builder setState(@State int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x8000; + mBuilderFieldsSet |= 0x4000; mState = value; return this; } @@ -1380,9 +1648,9 @@ public final class SampleDataClass implements Parcelable { * Making a field public will suppress getter generation in favor of accessing it directly. */ @DataClass.Generated.Member - public Builder setCharSeq(CharSequence value) { + public @NonNull Builder setCharSeq(@NonNull CharSequence value) { checkNotUsed(); - mBuilderFieldsSet |= 0x10000; + mBuilderFieldsSet |= 0x8000; charSeq = value; return this; } @@ -1391,9 +1659,9 @@ public final class SampleDataClass implements Parcelable { * Final fields suppress generating a setter (when setters are requested). */ @DataClass.Generated.Member - public Builder setLinkAddresses5(LinkAddress... value) { + public @NonNull Builder setLinkAddresses5(@Nullable LinkAddress... value) { checkNotUsed(); - mBuilderFieldsSet |= 0x20000; + mBuilderFieldsSet |= 0x10000; mLinkAddresses5 = value; return this; } @@ -1411,9 +1679,9 @@ public final class SampleDataClass implements Parcelable { * @see #SampleDataClass */ @DataClass.Generated.Member - public Builder setStringRes(@StringRes int value) { + public @NonNull Builder setStringRes(@StringRes int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x40000; + mBuilderFieldsSet |= 0x20000; mStringRes = value; return this; } @@ -1426,10 +1694,10 @@ public final class SampleDataClass implements Parcelable { * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int) */ @DataClass.Generated.Member - public Builder setLimited(@android.annotation.IntRange(from = 0, to = 4) int value) { + public @NonNull Builder setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x80000; - mLimited = value; + mBuilderFieldsSet |= 0x40000; + mDayOfWeek = value; return this; } @@ -1443,30 +1711,23 @@ public final class SampleDataClass implements Parcelable { * @see AnnotationValidations#validate(Class, Size, int, String, int) */ @DataClass.Generated.Member - public Builder setCoords(@Size(2) @FloatRange(from = 0f) float... value) { + public @NonNull Builder setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) { checkNotUsed(); - mBuilderFieldsSet |= 0x100000; + mBuilderFieldsSet |= 0x80000; mCoords = value; return this; } /** Builds the instance. This builder should not be touched after calling this! */ public SampleDataClass build() { - markUsed(); - if ((mBuilderFieldsSet & 0x1) == 0) { - throw new IllegalStateException("Required field not set: num"); - } - if ((mBuilderFieldsSet & 0x2) == 0) { - throw new IllegalStateException("Required field not set: num2"); - } - if ((mBuilderFieldsSet & 0x4) == 0) { - throw new IllegalStateException("Required field not set: num4"); - } + checkNotUsed(); + mBuilderFieldsSet |= 0x100000; // Mark builder used + if ((mBuilderFieldsSet & 0x10) == 0) { mName2 = "Bob"; } if ((mBuilderFieldsSet & 0x20) == 0) { - throw new IllegalStateException("Required field not set: name4"); + mName4 = defaultName4(); } if ((mBuilderFieldsSet & 0x40) == 0) { mOtherParcelable = null; @@ -1487,30 +1748,21 @@ public final class SampleDataClass implements Parcelable { mLinkAddresses4 = null; } if ((mBuilderFieldsSet & 0x1000) == 0) { - mActive = true; - } - if ((mBuilderFieldsSet & 0x2000) == 0) { mStateName = STATE_NAME_UNDEFINED; } if ((mBuilderFieldsSet & 0x4000) == 0) { - throw new IllegalStateException("Required field not set: flags"); - } - if ((mBuilderFieldsSet & 0x8000) == 0) { mState = STATE_UNDEFINED; } - if ((mBuilderFieldsSet & 0x10000) == 0) { + if ((mBuilderFieldsSet & 0x8000) == 0) { charSeq = ""; } if ((mBuilderFieldsSet & 0x20000) == 0) { - throw new IllegalStateException("Required field not set: linkAddresses5"); + mStringRes = 0; } if ((mBuilderFieldsSet & 0x40000) == 0) { - mStringRes = 0; + mDayOfWeek = 3; } if ((mBuilderFieldsSet & 0x80000) == 0) { - mLimited = 3; - } - if ((mBuilderFieldsSet & 0x100000) == 0) { mCoords = new float[] { 0f, 0f }; } SampleDataClass o = new SampleDataClass( @@ -1526,17 +1778,31 @@ public final class SampleDataClass implements Parcelable { mLinkAddresses2, mLinkAddresses, mLinkAddresses4, - mActive, mStateName, mFlags, mState, charSeq, mLinkAddresses5, mStringRes, - mLimited, + mDayOfWeek, mCoords); return o; } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x100000) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } } + @DataClass.Generated( + time = 1565126122525L, + codegenVersion = "1.0.0", + sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java", + inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)") + @Deprecated + private void __metadata() {} + } diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java index 71e85ab00eab..663620743af9 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java @@ -49,7 +49,7 @@ public class SampleDataClassTest { private SampleDataClass mSpecimen = newBuilder().build(); private static SampleDataClass.Builder newBuilder() { - return newIncompleteBuilder() + return newInvalidBuilder() .setNum(42) .setNum2(42) .setNum4(42) @@ -57,9 +57,8 @@ public class SampleDataClassTest { .setLinkAddresses5(); } - private static SampleDataClass.Builder newIncompleteBuilder() { - return new SampleDataClass.Builder() - .markActive() + private static SampleDataClass.Builder newInvalidBuilder() { + return new SampleDataClass.Builder(1, 2, 3, "a", 0, null) .setName("some parcelable") .setFlags(SampleDataClass.FLAG_MANUAL_REQUEST); } @@ -91,7 +90,7 @@ public class SampleDataClassTest { public void testCustomParcelling_instanceIsCached() { parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR); parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR); - assertEquals(1, DateParcelling.sInstanceCount.get()); + assertEquals(1, MyDateParcelling.sInstanceCount.get()); } @Test @@ -149,8 +148,8 @@ public class SampleDataClassTest { } @Test(expected = IllegalStateException.class) - public void testBuilder_throwsWhenRequiredFieldMissing() { - newIncompleteBuilder().build(); + public void testBuilder_performsValidation() { + newInvalidBuilder().build(); } @Test @@ -205,6 +204,11 @@ public class SampleDataClassTest { assertSame(tmpStorage, tmpStorageAgain); } + @Test(expected = IllegalStateException.class) + public void testCustomAnnotationValidation_isRun() { + newBuilder().setDayOfWeek(42).build(); + } + private static <T extends Parcelable> T parcelAndUnparcel( T original, Parcelable.Creator<T> creator) { Parcel p = Parcel.obtain(); diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java new file mode 100644 index 000000000000..11f03a72c051 --- /dev/null +++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2019 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.codegentest; + +import android.annotation.NonNull; +import android.os.SystemClock; + +import com.android.internal.util.DataClass; + +import java.util.concurrent.TimeUnit; + +@DataClass(genBuilder = true) +public class SampleWithCustomBuilder { + + long delayAmount = 0; + @NonNull + TimeUnit delayUnit = TimeUnit.MILLISECONDS; + + long creationTimestamp = SystemClock.uptimeMillis(); + + /** + * You can declare a class named {@code BaseBuilder} to have the generated builder extend from + * it instead. + * + * Same rules apply where defining a non-abstract method will suppress the generation of a + * method with the same signature. + * + * For abstract generatable methods, implementations are generated as normal, but original + * visibility is used, allowing you to hide methods. + * + * Here for example, we hide {@link #setDelayUnit} and {@link #setDelayAmount} from public API, + * replacing it with {@link #setDelay} instead. + */ + // Suppress setter generation for a field that is not supposed to come from user input. + @DataClass.Suppress("setCreationTimestamp") + static abstract class BaseBuilder { + + /** + * Hide methods by declaring them with reduced (package-private) visibility. + */ + abstract Builder setDelayAmount(long value); + + /** + * Alternatively, hide methods by using @hide, to hide them from public API only. + * + * @hide + */ + public abstract Builder setDelayUnit(TimeUnit value); + + /** + * Can provide additional method on the builder, e.g. as a replacement for the ones we've + * just hidden. + */ + public Builder setDelay(long amount, TimeUnit unit) { + setDelayAmount(amount); + setDelayUnit(unit); + return (Builder) this; + } + } + + + + // Code below generated by codegen v1.0.0. + // + // DO NOT MODIFY! + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java + // + // CHECKSTYLE:OFF Generated code + + @DataClass.Generated.Member + /* package-private */ SampleWithCustomBuilder( + long delayAmount, + @NonNull TimeUnit delayUnit, + long creationTimestamp) { + this.delayAmount = delayAmount; + this.delayUnit = delayUnit; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, delayUnit); + this.creationTimestamp = creationTimestamp; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public long getDelayAmount() { + return delayAmount; + } + + @DataClass.Generated.Member + public @NonNull TimeUnit getDelayUnit() { + return delayUnit; + } + + @DataClass.Generated.Member + public long getCreationTimestamp() { + return creationTimestamp; + } + + /** + * A builder for {@link SampleWithCustomBuilder} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static class Builder extends BaseBuilder { + + private long delayAmount; + private @NonNull TimeUnit delayUnit; + private long creationTimestamp; + + private long mBuilderFieldsSet = 0L; + + public Builder() { + } + + @DataClass.Generated.Member + @Override + @NonNull Builder setDelayAmount(long value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + delayAmount = value; + return this; + } + + @DataClass.Generated.Member + @Override + public @NonNull Builder setDelayUnit(@NonNull TimeUnit value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + delayUnit = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public SampleWithCustomBuilder build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + delayAmount = 0; + } + if ((mBuilderFieldsSet & 0x2) == 0) { + delayUnit = TimeUnit.MILLISECONDS; + } + if ((mBuilderFieldsSet & 0x4) == 0) { + creationTimestamp = SystemClock.uptimeMillis(); + } + SampleWithCustomBuilder o = new SampleWithCustomBuilder( + delayAmount, + delayUnit, + creationTimestamp); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x8) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1565126123496L, + codegenVersion = "1.0.0", + sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java", + inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nclass SampleWithCustomBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") + @Deprecated + private void __metadata() {} + +} diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 5260b30acdfa..502aa97bfc68 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -56,6 +56,7 @@ android_test { "androidx.test.rules", "FrameworksNetCommonTests", "frameworks-base-testutils", + "frameworks-net-integration-testutils", "framework-protos", "mockito-target-minus-junit4", "net-tests-utils", diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp new file mode 100644 index 000000000000..16a68d79596b --- /dev/null +++ b/tests/net/integration/Android.bp @@ -0,0 +1,31 @@ +// +// Copyright (C) 2019 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. +// + +// Utilities for testing framework code both in integration and unit tests. +java_library { + name: "frameworks-net-integration-testutils", + srcs: ["util/**/*.java", "util/**/*.kt"], + static_libs: [ + "androidx.annotation_annotation", + "androidx.test.rules", + "junit", + "net-tests-utils", + ], + libs: [ + "services.core", + "services.net", + ], +} diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt new file mode 100644 index 000000000000..fa2b99ce5cc6 --- /dev/null +++ b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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 + +import android.net.ConnectivityManager.TYPE_BLUETOOTH +import android.net.ConnectivityManager.TYPE_ETHERNET +import android.net.ConnectivityManager.TYPE_MOBILE +import android.net.ConnectivityManager.TYPE_NONE +import android.net.ConnectivityManager.TYPE_TEST +import android.net.ConnectivityManager.TYPE_VPN +import android.net.ConnectivityManager.TYPE_WIFI +import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH +import android.net.NetworkCapabilities.TRANSPORT_CELLULAR +import android.net.NetworkCapabilities.TRANSPORT_ETHERNET +import android.net.NetworkCapabilities.TRANSPORT_TEST +import android.net.NetworkCapabilities.TRANSPORT_VPN +import android.net.NetworkCapabilities.TRANSPORT_WIFI + +fun transportToLegacyType(transport: Int) = when (transport) { + TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH + TRANSPORT_CELLULAR -> TYPE_MOBILE + TRANSPORT_ETHERNET -> TYPE_ETHERNET + TRANSPORT_TEST -> TYPE_TEST + TRANSPORT_VPN -> TYPE_VPN + TRANSPORT_WIFI -> TYPE_WIFI + else -> TYPE_NONE +}
\ No newline at end of file diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java new file mode 100644 index 000000000000..1e8d83c3c6cd --- /dev/null +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2019 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; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; + +import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType; + +import static junit.framework.Assert.assertTrue; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkAgent; +import android.net.NetworkCapabilities; +import android.net.NetworkFactory; +import android.net.NetworkInfo; +import android.net.NetworkMisc; +import android.net.NetworkSpecifier; +import android.net.SocketKeepalive; +import android.net.UidRange; +import android.os.ConditionVariable; +import android.os.HandlerThread; +import android.os.Message; +import android.util.Log; + +import com.android.server.connectivity.ConnectivityConstants; +import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.TestableNetworkCallback; + +import java.util.Set; + +public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { + private final NetworkInfo mNetworkInfo; + private final NetworkCapabilities mNetworkCapabilities; + private final HandlerThread mHandlerThread; + private final Context mContext; + private final String mLogTag; + + private final ConditionVariable mDisconnected = new ConditionVariable(); + private final ConditionVariable mPreventReconnectReceived = new ConditionVariable(); + private int mScore; + private NetworkAgent mNetworkAgent; + private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED; + private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE; + private Integer mExpectedKeepaliveSlot = null; + + public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context) + throws Exception { + final int type = transportToLegacyType(transport); + final String typeName = ConnectivityManager.getNetworkTypeName(type); + mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock"); + mNetworkCapabilities = new NetworkCapabilities(); + mNetworkCapabilities.addTransportType(transport); + switch (transport) { + case TRANSPORT_ETHERNET: + mScore = 70; + break; + case TRANSPORT_WIFI: + mScore = 60; + break; + case TRANSPORT_CELLULAR: + mScore = 50; + break; + case TRANSPORT_WIFI_AWARE: + mScore = 20; + break; + case TRANSPORT_VPN: + mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN); + mScore = ConnectivityConstants.VPN_DEFAULT_SCORE; + break; + default: + throw new UnsupportedOperationException("unimplemented network type"); + } + mContext = context; + mLogTag = "Mock-" + typeName; + mHandlerThread = new HandlerThread(mLogTag); + mHandlerThread.start(); + + mNetworkAgent = makeNetworkAgent(linkProperties); + } + + protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties) + throws Exception { + return new InstrumentedNetworkAgent(this, linkProperties); + } + + public static class InstrumentedNetworkAgent extends NetworkAgent { + private final NetworkAgentWrapper mWrapper; + + public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) { + super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag, + wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore, + new NetworkMisc(), NetworkFactory.SerialNumber.NONE); + mWrapper = wrapper; + } + + @Override + public void unwanted() { + mWrapper.mDisconnected.open(); + } + + @Override + public void startSocketKeepalive(Message msg) { + int slot = msg.arg1; + if (mWrapper.mExpectedKeepaliveSlot != null) { + assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot); + } + onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError); + } + + @Override + public void stopSocketKeepalive(Message msg) { + onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError); + } + + @Override + protected void preventAutomaticReconnect() { + mWrapper.mPreventReconnectReceived.open(); + } + + @Override + protected void addKeepalivePacketFilter(Message msg) { + Log.i(mWrapper.mLogTag, "Add keepalive packet filter."); + } + + @Override + protected void removeKeepalivePacketFilter(Message msg) { + Log.i(mWrapper.mLogTag, "Remove keepalive packet filter."); + } + } + + public void adjustScore(int change) { + mScore += change; + mNetworkAgent.sendNetworkScore(mScore); + } + + public int getScore() { + return mScore; + } + + public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { + mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated); + } + + public void addCapability(int capability) { + mNetworkCapabilities.addCapability(capability); + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + + public void removeCapability(int capability) { + mNetworkCapabilities.removeCapability(capability); + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + + public void setUids(Set<UidRange> uids) { + mNetworkCapabilities.setUids(uids); + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + + public void setSignalStrength(int signalStrength) { + mNetworkCapabilities.setSignalStrength(signalStrength); + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + + public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) { + mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + + public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) { + mNetworkCapabilities.set(nc); + if (sendToConnectivityService) { + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + } + + public void connect() { + assertNotEquals("MockNetworkAgents can only be connected once", + getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED); + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + + public void suspend() { + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + + public void resume() { + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + + public void disconnect() { + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + + @Override + public Network getNetwork() { + return new Network(mNetworkAgent.netId); + } + + public void expectPreventReconnectReceived(long timeoutMs) { + assertTrue(mPreventReconnectReceived.block(timeoutMs)); + } + + public void expectDisconnected(long timeoutMs) { + assertTrue(mDisconnected.block(timeoutMs)); + } + + public void sendLinkProperties(LinkProperties lp) { + mNetworkAgent.sendLinkProperties(lp); + } + + public void setStartKeepaliveEvent(int reason) { + mStartKeepaliveError = reason; + } + + public void setStopKeepaliveEvent(int reason) { + mStopKeepaliveError = reason; + } + + public void setExpectedKeepaliveSlot(Integer slot) { + mExpectedKeepaliveSlot = slot; + } + + public NetworkAgent getNetworkAgent() { + return mNetworkAgent; + } + + public NetworkInfo getNetworkInfo() { + return mNetworkInfo; + } + + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + public void waitForIdle(long timeoutMs) { + HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs); + } +} diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/tests/net/integration/util/com/android/server/TestNetIdManager.kt new file mode 100644 index 000000000000..eb290dc7d24a --- /dev/null +++ b/tests/net/integration/util/com/android/server/TestNetIdManager.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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 + +import java.util.concurrent.atomic.AtomicInteger + +/** + * A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather + * than starting from [NetIdManager.MIN_NET_ID] and increasing. + * + * Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs + * overlapping with netIDs used by the real ConnectivityService on the device. + * + * IDs may still overlap if many networks have been used on the device (so the "real" netIDs + * are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there + * is no way to fully solve the overlap issue without altering ID allocation in non-test code, as + * the real ConnectivityService could start using netIds that have been used by the test in the + * past. + */ +class TestNetIdManager : NetIdManager() { + private val nextId = AtomicInteger(MAX_NET_ID) + override fun reserveNetId() = nextId.decrementAndGet() + override fun releaseNetId(id: Int) = Unit +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 5cc95d9f2bc3..f3c735cd8880 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -28,8 +28,6 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; -import static android.net.ConnectivityManager.TYPE_NONE; -import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK; @@ -69,6 +67,7 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.RouteInfo.RTN_UNREACHABLE; +import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType; import static com.android.testutils.ConcurrentUtilsKt.await; import static com.android.testutils.ConcurrentUtilsKt.durationOf; import static com.android.testutils.ExceptionUtils.ignoreExceptions; @@ -86,6 +85,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.anyInt; @@ -93,6 +93,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -105,6 +106,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.annotation.NonNull; +import android.app.AlarmManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -125,6 +127,7 @@ import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.ConnectivityManager.TooManyRequestsException; import android.net.ConnectivityThread; import android.net.IDnsResolver; +import android.net.IIpConnectivityMetrics; import android.net.INetd; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; @@ -139,12 +142,8 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MatchAllNetworkSpecifier; import android.net.Network; -import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkFactory; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkMisc; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; @@ -168,7 +167,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Looper; -import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; @@ -265,10 +263,12 @@ public class ConnectivityServiceTest { // timeout. For this, our assertions should run fast enough to leave less than // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are // supposedly fired, and the time we call expectCallback. - private final static int TEST_CALLBACK_TIMEOUT_MS = 200; + private static final int TEST_CALLBACK_TIMEOUT_MS = 200; // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to // complete before callbacks are verified. - private final static int TEST_REQUEST_TIMEOUT_MS = 150; + private static final int TEST_REQUEST_TIMEOUT_MS = 150; + + private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000; private static final String CLAT_PREFIX = "v4-"; private static final String MOBILE_IFNAME = "test_rmnet_data0"; @@ -276,15 +276,19 @@ public class ConnectivityServiceTest { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private MockContext mServiceContext; - private WrappedConnectivityService mService; + private HandlerThread mCsHandlerThread; + private ConnectivityService mService; private WrappedConnectivityManager mCm; - private MockNetworkAgent mWiFiNetworkAgent; - private MockNetworkAgent mCellNetworkAgent; - private MockNetworkAgent mEthernetNetworkAgent; + private TestNetworkAgentWrapper mWiFiNetworkAgent; + private TestNetworkAgentWrapper mCellNetworkAgent; + private TestNetworkAgentWrapper mEthernetNetworkAgent; private MockVpn mMockVpn; private Context mContext; private INetworkPolicyListener mPolicyListener; + private WrappedMultinetworkPolicyTracker mPolicyTracker; + private HandlerThread mAlarmManagerThread; + @Mock IIpConnectivityMetrics mIpConnectivityMetrics; @Mock IpConnectivityMetrics.Logger mMetricsService; @Mock DefaultNetworkMetrics mDefaultNetworkMetrics; @Mock INetworkManagementService mNetworkManagementService; @@ -296,6 +300,7 @@ public class ConnectivityServiceTest { @Mock PackageManager mPackageManager; @Mock UserManager mUserManager; @Mock NotificationManager mNotificationManager; + @Mock AlarmManager mAlarmManager; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -368,6 +373,7 @@ public class ConnectivityServiceTest { if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager; if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack; if (Context.USER_SERVICE.equals(name)) return mUserManager; + if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager; return super.getSystemService(name); } @@ -397,25 +403,20 @@ public class ConnectivityServiceTest { } } - public void waitForIdle(int timeoutMsAsInt) { - long timeoutMs = timeoutMsAsInt; - HandlerUtilsKt.waitForIdle(mService.mHandlerThread, timeoutMs); - waitForIdle(mCellNetworkAgent, timeoutMs); - waitForIdle(mWiFiNetworkAgent, timeoutMs); - waitForIdle(mEthernetNetworkAgent, timeoutMs); - HandlerUtilsKt.waitForIdle(mService.mHandlerThread, timeoutMs); - HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), timeoutMs); + private void waitForIdle() { + HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + waitForIdle(mCellNetworkAgent, TIMEOUT_MS); + waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS); + waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS); + HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS); } - public void waitForIdle(MockNetworkAgent agent, long timeoutMs) { + private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) { if (agent == null) { return; } - HandlerUtilsKt.waitForIdle(agent.mHandlerThread, timeoutMs); - } - - private void waitForIdle() { - waitForIdle(TIMEOUT_MS); + agent.waitForIdle(timeoutMs); } @Test @@ -429,7 +430,7 @@ public class ConnectivityServiceTest { // Bring up a network that we can use to send messages to ConnectivityService. ConditionVariable cv = waitForConnectivityBroadcasts(1); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); waitFor(cv); Network n = mWiFiNetworkAgent.getNetwork(); @@ -449,7 +450,7 @@ public class ConnectivityServiceTest { public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception { // Bring up a network that we can use to send messages to ConnectivityService. ConditionVariable cv = waitForConnectivityBroadcasts(1); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); waitFor(cv); Network n = mWiFiNetworkAgent.getNetwork(); @@ -469,7 +470,7 @@ public class ConnectivityServiceTest { fail("expected race condition at least once in " + attempts + " attempts"); } - private class MockNetworkAgent implements TestableNetworkCallback.HasNetwork { + private class TestNetworkAgentWrapper extends NetworkAgentWrapper { private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP | NETWORK_VALIDATION_PROBE_HTTPS; @@ -480,86 +481,35 @@ public class ConnectivityServiceTest { | NETWORK_VALIDATION_RESULT_PARTIAL; private static final int VALIDATION_RESULT_INVALID = 0; - private final INetworkMonitor mNetworkMonitor; - private final NetworkInfo mNetworkInfo; - private final NetworkCapabilities mNetworkCapabilities; - private final HandlerThread mHandlerThread; - private final ConditionVariable mDisconnected = new ConditionVariable(); - private final ConditionVariable mNetworkStatusReceived = new ConditionVariable(); - private final ConditionVariable mPreventReconnectReceived = new ConditionVariable(); - private int mScore; - private NetworkAgent mNetworkAgent; - private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED; - private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE; - private Integer mExpectedKeepaliveSlot = null; - // Contains the redirectUrl from networkStatus(). Before reading, wait for - // mNetworkStatusReceived. - private String mRedirectUrl; - + private INetworkMonitor mNetworkMonitor; private INetworkMonitorCallbacks mNmCallbacks; private int mNmValidationResult = VALIDATION_RESULT_BASE; private String mNmValidationRedirectUrl = null; private boolean mNmProvNotificationRequested = false; - void setNetworkValid() { - mNmValidationResult = VALIDATION_RESULT_VALID; - mNmValidationRedirectUrl = null; - } - - void setNetworkInvalid() { - mNmValidationResult = VALIDATION_RESULT_INVALID; - mNmValidationRedirectUrl = null; - } - - void setNetworkPortal(String redirectUrl) { - setNetworkInvalid(); - mNmValidationRedirectUrl = redirectUrl; - } + private final ConditionVariable mNetworkStatusReceived = new ConditionVariable(); + // Contains the redirectUrl from networkStatus(). Before reading, wait for + // mNetworkStatusReceived. + private String mRedirectUrl; - void setNetworkPartial() { - mNmValidationResult = VALIDATION_RESULT_PARTIAL; - mNmValidationRedirectUrl = null; + TestNetworkAgentWrapper(int transport) throws Exception { + this(transport, new LinkProperties()); } - void setNetworkPartialValid() { - mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID; - mNmValidationRedirectUrl = null; - } + TestNetworkAgentWrapper(int transport, LinkProperties linkProperties) + throws Exception { + super(transport, linkProperties, mServiceContext); - MockNetworkAgent(int transport) throws Exception { - this(transport, new LinkProperties()); + // Waits for the NetworkAgent to be registered, which includes the creation of the + // NetworkMonitor. + waitForIdle(TIMEOUT_MS); } - MockNetworkAgent(int transport, LinkProperties linkProperties) throws Exception { - final int type = transportToLegacyType(transport); - final String typeName = ConnectivityManager.getNetworkTypeName(type); - mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock"); - mNetworkCapabilities = new NetworkCapabilities(); - mNetworkCapabilities.addTransportType(transport); - switch (transport) { - case TRANSPORT_ETHERNET: - mScore = 70; - break; - case TRANSPORT_WIFI: - mScore = 60; - break; - case TRANSPORT_CELLULAR: - mScore = 50; - break; - case TRANSPORT_WIFI_AWARE: - mScore = 20; - break; - case TRANSPORT_VPN: - mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN); - mScore = ConnectivityConstants.VPN_DEFAULT_SCORE; - break; - default: - throw new UnsupportedOperationException("unimplemented network type"); - } - mHandlerThread = new HandlerThread("Mock-" + typeName); - mHandlerThread.start(); - + @Override + protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties) + throws Exception { mNetworkMonitor = mock(INetworkMonitor.class); + final Answer validateAnswer = inv -> { new Thread(ignoreExceptions(this::onValidationRequested)).start(); return null; @@ -576,56 +526,20 @@ public class ConnectivityServiceTest { any() /* name */, nmCbCaptor.capture()); - mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext, - "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities, - linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) { - @Override - public void unwanted() { mDisconnected.open(); } - - @Override - public void startSocketKeepalive(Message msg) { - int slot = msg.arg1; - if (mExpectedKeepaliveSlot != null) { - assertEquals((int) mExpectedKeepaliveSlot, slot); - } - onSocketKeepaliveEvent(slot, mStartKeepaliveError); - } - - @Override - public void stopSocketKeepalive(Message msg) { - onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError); - } - + final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties) { @Override public void networkStatus(int status, String redirectUrl) { mRedirectUrl = redirectUrl; mNetworkStatusReceived.open(); } - - @Override - protected void preventAutomaticReconnect() { - mPreventReconnectReceived.open(); - } - - @Override - protected void addKeepalivePacketFilter(Message msg) { - Log.i(TAG, "Add keepalive packet filter."); - } - - @Override - protected void removeKeepalivePacketFilter(Message msg) { - Log.i(TAG, "Remove keepalive packet filter."); - } }; - assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId); + assertEquals(na.netId, nmNetworkCaptor.getValue().netId); mNmCallbacks = nmCbCaptor.getValue(); mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor); - // Waits for the NetworkAgent to be registered, which includes the creation of the - // NetworkMonitor. - waitForIdle(); + return na; } private void onValidationRequested() throws Exception { @@ -645,55 +559,11 @@ public class ConnectivityServiceTest { } } - public void adjustScore(int change) { - mScore += change; - mNetworkAgent.sendNetworkScore(mScore); - } - - public int getScore() { - return mScore; - } - - public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { - mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated); - } - - public void addCapability(int capability) { - mNetworkCapabilities.addCapability(capability); - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - } - - public void removeCapability(int capability) { - mNetworkCapabilities.removeCapability(capability); - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - } - - public void setUids(Set<UidRange> uids) { - mNetworkCapabilities.setUids(uids); - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - } - - public void setSignalStrength(int signalStrength) { - mNetworkCapabilities.setSignalStrength(signalStrength); - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - } - - public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) { - mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - } - - public void setNetworkCapabilities(NetworkCapabilities nc, - boolean sendToConnectivityService) { - mNetworkCapabilities.set(nc); - if (sendToConnectivityService) { - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - } - } - + /** + * Connect without adding any internet capability. + */ public void connectWithoutInternet() { - mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); + super.connect(); } /** @@ -710,23 +580,21 @@ public class ConnectivityServiceTest { * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET. */ public void connect(boolean validated, boolean hasInternet) { - assertEquals("MockNetworkAgents can only be connected once", - mNetworkInfo.getDetailedState(), DetailedState.IDLE); - assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)); + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET)); - NetworkCallback callback = null; + ConnectivityManager.NetworkCallback callback = null; final ConditionVariable validatedCv = new ConditionVariable(); if (validated) { setNetworkValid(); NetworkRequest request = new NetworkRequest.Builder() - .addTransportType(mNetworkCapabilities.getTransportTypes()[0]) + .addTransportType(getNetworkCapabilities().getTransportTypes()[0]) .clearCapabilities() .build(); - callback = new NetworkCallback() { + callback = new ConnectivityManager.NetworkCallback() { public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { if (network.equals(getNetwork()) && - networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { + networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { validatedCv.open(); } } @@ -763,47 +631,29 @@ public class ConnectivityServiceTest { connect(false); } - public void suspend() { - mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); - } - - public void resume() { - mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); - } - - public void disconnect() { - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); - } - - public Network getNetwork() { - return new Network(mNetworkAgent.netId); - } - - public ConditionVariable getPreventReconnectReceived() { - return mPreventReconnectReceived; - } - - public ConditionVariable getDisconnectedCV() { - return mDisconnected; + void setNetworkValid() { + mNmValidationResult = VALIDATION_RESULT_VALID; + mNmValidationRedirectUrl = null; } - public void sendLinkProperties(LinkProperties lp) { - mNetworkAgent.sendLinkProperties(lp); + void setNetworkInvalid() { + mNmValidationResult = VALIDATION_RESULT_INVALID; + mNmValidationRedirectUrl = null; } - public void setStartKeepaliveError(int error) { - mStartKeepaliveError = error; + void setNetworkPortal(String redirectUrl) { + setNetworkInvalid(); + mNmValidationRedirectUrl = redirectUrl; } - public void setStopKeepaliveError(int error) { - mStopKeepaliveError = error; + void setNetworkPartial() { + mNmValidationResult = VALIDATION_RESULT_PARTIAL; + mNmValidationRedirectUrl = null; } - public void setExpectedKeepaliveSlot(Integer slot) { - mExpectedKeepaliveSlot = slot; + void setNetworkPartialValid() { + mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID; + mNmValidationRedirectUrl = null; } public String waitForRedirectUrl() { @@ -811,12 +661,12 @@ public class ConnectivityServiceTest { return mRedirectUrl; } - public NetworkAgent getNetworkAgent() { - return mNetworkAgent; + public void expectDisconnected() { + expectDisconnected(TIMEOUT_MS); } - public NetworkCapabilities getNetworkCapabilities() { - return mNetworkCapabilities; + public void expectPreventReconnectReceived() { + expectPreventReconnectReceived(TIMEOUT_MS); } } @@ -995,15 +845,15 @@ public class ConnectivityServiceTest { private boolean mConnected = false; // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does // not inherit from NetworkAgent. - private MockNetworkAgent mMockNetworkAgent; + private TestNetworkAgentWrapper mMockNetworkAgent; public MockVpn(int userId) { super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService, userId); } - public void setNetworkAgent(MockNetworkAgent agent) { - waitForIdle(agent, TIMEOUT_MS); + public void setNetworkAgent(TestNetworkAgentWrapper agent) { + agent.waitForIdle(TIMEOUT_MS); mMockNetworkAgent = agent; mNetworkAgent = agent.getNetworkAgent(); mNetworkCapabilities.set(agent.getNetworkCapabilities()); @@ -1070,187 +920,45 @@ public class ConnectivityServiceTest { } } - private class FakeWakeupMessage extends WakeupMessage { - private static final int UNREASONABLY_LONG_WAIT = 1000; - - public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) { - super(context, handler, cmdName, cmd); - } - - public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd, - int arg1, int arg2, Object obj) { - super(context, handler, cmdName, cmd, arg1, arg2, obj); + private void mockVpn(int uid) { + synchronized (mService.mVpns) { + int userId = UserHandle.getUserId(uid); + mMockVpn = new MockVpn(userId); + // This has no effect unless the VPN is actually connected, because things like + // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN + // netId, and check if that network is actually connected. + mService.mVpns.put(userId, mMockVpn); } + } - @Override - public void schedule(long when) { - long delayMs = when - SystemClock.elapsedRealtime(); - if (delayMs < 0) delayMs = 0; - if (delayMs > UNREASONABLY_LONG_WAIT) { - fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT + - "ms into the future: " + delayMs); - } - Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj); - mHandler.sendMessageDelayed(msg, delayMs); - } + private void setUidRulesChanged(int uidRules) throws RemoteException { + mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules); + } - @Override - public void cancel() { - mHandler.removeMessages(mCmd, mObj); - } + private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException { + mPolicyListener.onRestrictBackgroundChanged(restrictBackground); + } - @Override - public void onAlarm() { - throw new AssertionError("Should never happen. Update this fake."); - } + private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) { + return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd; } - private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker { - public volatile boolean configRestrictsAvoidBadWifi; - public volatile int configMeteredMultipathPreference; + private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker { + volatile boolean mConfigRestrictsAvoidBadWifi; + volatile int mConfigMeteredMultipathPreference; - public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) { + WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) { super(c, h, r); } @Override public boolean configRestrictsAvoidBadWifi() { - return configRestrictsAvoidBadWifi; + return mConfigRestrictsAvoidBadWifi; } @Override public int configMeteredMultipathPreference() { - return configMeteredMultipathPreference; - } - } - - private class WrappedConnectivityService extends ConnectivityService { - public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker; - private MockableSystemProperties mSystemProperties; - - public WrappedConnectivityService(Context context, INetworkManagementService netManager, - INetworkStatsService statsService, INetworkPolicyManager policyManager, - IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) { - super(context, netManager, statsService, policyManager, dnsResolver, log, netd); - mNetd = netd; - mLingerDelayMs = TEST_LINGER_DELAY_MS; - } - - @Override - protected MockableSystemProperties getSystemProperties() { - // Minimal approach to overriding system properties: let most calls fall through to real - // device values, and only override ones values that are important to this test. - mSystemProperties = spy(new MockableSystemProperties()); - when(mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0); - when(mSystemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false); - return mSystemProperties; - } - - @Override - protected Tethering makeTethering() { - return mock(Tethering.class); - } - - @Override - protected ProxyTracker makeProxyTracker() { - return mock(ProxyTracker.class); - } - - @Override - protected int reserveNetId() { - while (true) { - final int netId = super.reserveNetId(); - - // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks - // can have odd side-effects, like network validations succeeding. - Context context = InstrumentationRegistry.getContext(); - final Network[] networks = ConnectivityManager.from(context).getAllNetworks(); - boolean overlaps = false; - for (Network network : networks) { - if (netId == network.netId) { - overlaps = true; - break; - } - } - if (overlaps) continue; - - return netId; - } - } - - @Override - protected boolean queryUserAccess(int uid, int netId) { - return true; - } - - public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) { - return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd; - } - - @Override - public MultinetworkPolicyTracker createMultinetworkPolicyTracker( - Context c, Handler h, Runnable r) { - final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r); - return tracker; - } - - public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() { - return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker; - } - - @Override - protected NetworkStackClient getNetworkStack() { - return mNetworkStack; - } - - @Override - public WakeupMessage makeWakeupMessage( - Context context, Handler handler, String cmdName, int cmd, Object obj) { - return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj); - } - - @Override - public boolean hasService(String name) { - // Currenty, the only relevant service that ConnectivityService checks for is - // ETHERNET_SERVICE. - return Context.ETHERNET_SERVICE.equals(name); - } - - @Override - protected IpConnectivityMetrics.Logger metricsLogger() { - return mMetricsService; - } - - @Override - protected void registerNetdEventCallback() { - } - - public void mockVpn(int uid) { - synchronized (mVpns) { - int userId = UserHandle.getUserId(uid); - mMockVpn = new MockVpn(userId); - // This has no effect unless the VPN is actually connected, because things like - // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN - // netId, and check if that network is actually connected. - mVpns.put(userId, mMockVpn); - } - } - - public void waitForIdle(int timeoutMs) { - HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs); - } - - public void waitForIdle() { - waitForIdle(TIMEOUT_MS); - } - - public void setUidRulesChanged(int uidRules) throws RemoteException { - mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules); - } - - public void setRestrictBackgroundChanged(boolean restrictBackground) - throws RemoteException { - mPolicyListener.onRestrictBackgroundChanged(restrictBackground); + return mConfigMeteredMultipathPreference; } } @@ -1296,13 +1004,22 @@ public class ConnectivityServiceTest { LocalServices.addService( NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); - mService = new WrappedConnectivityService(mServiceContext, + mAlarmManagerThread = new HandlerThread("TestAlarmManager"); + mAlarmManagerThread.start(); + initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler()); + + mCsHandlerThread = new HandlerThread("TestConnectivityService"); + final ConnectivityService.Dependencies deps = makeDependencies(); + mService = new ConnectivityService(mServiceContext, mNetworkManagementService, mStatsService, mNpm, + mMockDnsResolver, mock(IpConnectivityLog.class), mMockNetd, - mMockDnsResolver); + deps); + mService.mLingerDelayMs = TEST_LINGER_DELAY_MS; + verify(deps).makeMultinetworkPolicyTracker(any(), any(), any()); final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor = ArgumentCaptor.forClass(INetworkPolicyListener.class); @@ -1313,7 +1030,7 @@ public class ConnectivityServiceTest { // getSystemService() correctly. mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService); mService.systemReady(); - mService.mockVpn(Process.myUid()); + mockVpn(Process.myUid()); mCm.bindProcessToNetwork(null); // Ensure that the default setting for Captive Portals is used for most tests @@ -1322,6 +1039,57 @@ public class ConnectivityServiceTest { setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); } + private ConnectivityService.Dependencies makeDependencies() { + final MockableSystemProperties systemProperties = spy(new MockableSystemProperties()); + when(systemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0); + when(systemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false); + + final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class); + doReturn(mCsHandlerThread).when(deps).makeHandlerThread(); + doReturn(new TestNetIdManager()).when(deps).makeNetIdManager(); + doReturn(mNetworkStack).when(deps).getNetworkStack(); + doReturn(systemProperties).when(deps).getSystemProperties(); + doReturn(mock(Tethering.class)).when(deps).makeTethering(any(), any(), any(), any(), any()); + doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any()); + doReturn(mMetricsService).when(deps).getMetricsLogger(); + doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt()); + doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics(); + doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE); + doAnswer(inv -> { + mPolicyTracker = new WrappedMultinetworkPolicyTracker( + inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)); + return mPolicyTracker; + }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any()); + + return deps; + } + + private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) { + doAnswer(inv -> { + final long when = inv.getArgument(1); + final WakeupMessage wakeupMsg = inv.getArgument(3); + final Handler handler = inv.getArgument(4); + + long delayMs = when - SystemClock.elapsedRealtime(); + if (delayMs < 0) delayMs = 0; + if (delayMs > UNREASONABLY_LONG_ALARM_WAIT_MS) { + fail("Attempting to send msg more than " + UNREASONABLY_LONG_ALARM_WAIT_MS + + "ms into the future: " + delayMs); + } + alarmHandler.postDelayed(() -> handler.post(wakeupMsg::onAlarm), wakeupMsg /* token */, + delayMs); + + return null; + }).when(am).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(), anyString(), + any(WakeupMessage.class), any()); + + doAnswer(inv -> { + final WakeupMessage wakeupMsg = inv.getArgument(0); + alarmHandler.removeCallbacksAndMessages(wakeupMsg /* token */); + return null; + }).when(am).cancel(any(WakeupMessage.class)); + } + @After public void tearDown() throws Exception { setAlwaysOnNetworks(false); @@ -1338,6 +1106,9 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent = null; } FakeSettingsProvider.clearSettingsProvider(); + + mCsHandlerThread.quitSafely(); + mAlarmManagerThread.quitSafely(); } private void mockDefaultPackages() throws Exception { @@ -1357,21 +1128,6 @@ public class ConnectivityServiceTest { })); } - private static int transportToLegacyType(int transport) { - switch (transport) { - case TRANSPORT_ETHERNET: - return TYPE_ETHERNET; - case TRANSPORT_WIFI: - return TYPE_WIFI; - case TRANSPORT_CELLULAR: - return TYPE_MOBILE; - case TRANSPORT_VPN: - return TYPE_VPN; - default: - return TYPE_NONE; - } - } - private void verifyActiveNetwork(int transport) { // Test getActiveNetworkInfo() assertNotNull(mCm.getActiveNetworkInfo()); @@ -1449,8 +1205,8 @@ public class ConnectivityServiceTest { @Test public void testLingering() throws Exception { verifyNoNetwork(); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); assertNull(mCm.getActiveNetworkInfo()); assertNull(mCm.getActiveNetwork()); // Test bringing up validated cellular. @@ -1474,7 +1230,7 @@ public class ConnectivityServiceTest { assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) || mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork())); // Test cellular linger timeout. - waitFor(mCellNetworkAgent.getDisconnectedCV()); + mCellNetworkAgent.expectDisconnected(); waitForIdle(); assertLength(1, mCm.getAllNetworks()); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1490,13 +1246,13 @@ public class ConnectivityServiceTest { @Test public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception { // Test bringing up unvalidated WiFi - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); ConditionVariable cv = waitForConnectivityBroadcasts(1); mWiFiNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up unvalidated cellular - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false); waitForIdle(); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1505,7 +1261,7 @@ public class ConnectivityServiceTest { waitForIdle(); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up validated cellular - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); cv = waitForConnectivityBroadcasts(2); mCellNetworkAgent.connect(true); waitFor(cv); @@ -1525,13 +1281,13 @@ public class ConnectivityServiceTest { @Test public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception { // Test bringing up unvalidated cellular. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); ConditionVariable cv = waitForConnectivityBroadcasts(1); mCellNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up unvalidated WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); cv = waitForConnectivityBroadcasts(2); mWiFiNetworkAgent.connect(false); waitFor(cv); @@ -1551,7 +1307,7 @@ public class ConnectivityServiceTest { @Test public void testUnlingeringDoesNotValidate() throws Exception { // Test bringing up unvalidated WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); ConditionVariable cv = waitForConnectivityBroadcasts(1); mWiFiNetworkAgent.connect(false); waitFor(cv); @@ -1559,7 +1315,7 @@ public class ConnectivityServiceTest { assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); // Test bringing up validated cellular. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); cv = waitForConnectivityBroadcasts(2); mCellNetworkAgent.connect(true); waitFor(cv); @@ -1579,13 +1335,13 @@ public class ConnectivityServiceTest { @Test public void testCellularOutscoresWeakWifi() throws Exception { // Test bringing up validated cellular. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); ConditionVariable cv = waitForConnectivityBroadcasts(1); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); cv = waitForConnectivityBroadcasts(2); mWiFiNetworkAgent.connect(true); waitFor(cv); @@ -1606,45 +1362,41 @@ public class ConnectivityServiceTest { public void testReapingNetwork() throws Exception { // Test bringing up WiFi without NET_CAPABILITY_INTERNET. // Expect it to be torn down immediately because it satisfies no requests. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV(); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connectWithoutInternet(); - waitFor(cv); + mWiFiNetworkAgent.expectDisconnected(); // Test bringing up cellular without NET_CAPABILITY_INTERNET. // Expect it to be torn down immediately because it satisfies no requests. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - cv = mCellNetworkAgent.getDisconnectedCV(); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mCellNetworkAgent.connectWithoutInternet(); - waitFor(cv); + mCellNetworkAgent.expectDisconnected(); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - cv = waitForConnectivityBroadcasts(1); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + final ConditionVariable cv = waitForConnectivityBroadcasts(1); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up unvalidated cellular. // Expect it to be torn down because it could never be the highest scoring network // satisfying the default request even if it validated. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - cv = mCellNetworkAgent.getDisconnectedCV(); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false); - waitFor(cv); + mCellNetworkAgent.expectDisconnected(); verifyActiveNetwork(TRANSPORT_WIFI); - cv = mWiFiNetworkAgent.getDisconnectedCV(); mWiFiNetworkAgent.disconnect(); - waitFor(cv); + mWiFiNetworkAgent.expectDisconnected(); } @Test public void testCellularFallback() throws Exception { // Test bringing up validated cellular. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); ConditionVariable cv = waitForConnectivityBroadcasts(1); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); cv = waitForConnectivityBroadcasts(2); mWiFiNetworkAgent.connect(true); waitFor(cv); @@ -1676,13 +1428,13 @@ public class ConnectivityServiceTest { @Test public void testWiFiFallback() throws Exception { // Test bringing up unvalidated WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); ConditionVariable cv = waitForConnectivityBroadcasts(1); mWiFiNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up validated cellular. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); cv = waitForConnectivityBroadcasts(2); mCellNetworkAgent.connect(true); waitFor(cv); @@ -1760,7 +1512,7 @@ public class ConnectivityServiceTest { // Test unvalidated networks ConditionVariable cv = waitForConnectivityBroadcasts(1); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false); genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); @@ -1775,7 +1527,7 @@ public class ConnectivityServiceTest { assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); cv = waitForConnectivityBroadcasts(2); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -1799,7 +1551,7 @@ public class ConnectivityServiceTest { assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); // Test validated networks - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); @@ -1812,7 +1564,7 @@ public class ConnectivityServiceTest { assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); genericNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent); @@ -1850,9 +1602,9 @@ public class ConnectivityServiceTest { TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); @@ -1891,7 +1643,7 @@ public class ConnectivityServiceTest { assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); for (int i = 0; i < 4; i++) { - MockNetworkAgent oldNetwork, newNetwork; + TestNetworkAgentWrapper oldNetwork, newNetwork; if (i % 2 == 0) { mWiFiNetworkAgent.adjustScore(-15); oldNetwork = mWiFiNetworkAgent; @@ -1943,7 +1695,7 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(request, callback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false); // Score: 10 callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); @@ -1952,7 +1704,7 @@ public class ConnectivityServiceTest { // Bring up wifi with a score of 20. // Cell stays up because it would satisfy the default request if it validated. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); // Score: 20 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -1968,7 +1720,7 @@ public class ConnectivityServiceTest { // Bring up wifi with a score of 70. // Cell is lingered because it would not satisfy any request, even if it validated. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.adjustScore(50); mWiFiNetworkAgent.connect(false); // Score: 70 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -1987,7 +1739,7 @@ public class ConnectivityServiceTest { // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but // it's arguably correct to linger it, since it was the default network before it validated. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); // TODO: Investigate sending validated before losing. @@ -2008,12 +1760,12 @@ public class ConnectivityServiceTest { assertEquals(null, mCm.getActiveNetwork()); // If a network is lingering, and we add and remove a request from it, resume lingering. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2044,7 +1796,7 @@ public class ConnectivityServiceTest { mCm.requestNetwork(cellRequest, noopCallback); // Now connect wifi, and expect it to become the default network. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); @@ -2065,7 +1817,7 @@ public class ConnectivityServiceTest { TestNetworkCallback trackDefaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(trackDefaultCallback); trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET); + mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); mEthernetNetworkAgent.connect(true); callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent); callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent); @@ -2100,8 +1852,8 @@ public class ConnectivityServiceTest { TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mCellNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); @@ -2142,12 +1894,12 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(request, callback); // Bring up validated cell. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); // Bring up unvalidated wifi with explicitlySelected=true. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(true, false); mWiFiNetworkAgent.connect(false); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2170,7 +1922,7 @@ public class ConnectivityServiceTest { // Disconnect wifi, and then reconnect, again with explicitlySelected=true. mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(true, false); mWiFiNetworkAgent.connect(false); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2181,7 +1933,7 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent); // Reconnect, again with explicitlySelected=true, but this time validate. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(true, false); mWiFiNetworkAgent.connect(true); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2191,7 +1943,7 @@ public class ConnectivityServiceTest { // BUG: the network will no longer linger, even though it's validated and outscored. // TODO: fix this. - mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET); + mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); mEthernetNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork()); @@ -2202,7 +1954,7 @@ public class ConnectivityServiceTest { // wifi immediately. mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(true, true); mWiFiNetworkAgent.connect(false); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2215,7 +1967,7 @@ public class ConnectivityServiceTest { // Check that the network is not scored specially and that the device prefers cell data. mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(false, true); mWiFiNetworkAgent.connect(false); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2277,7 +2029,7 @@ public class ConnectivityServiceTest { assertTrue(testFactory.getMyStartRequested()); // Now bring in a higher scored network. - MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + TestNetworkAgentWrapper testAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); // Rather than create a validated network which complicates things by registering it's // own NetworkRequest during startup, just bump up the score to cancel out the // unvalidated penalty. @@ -2371,18 +2123,17 @@ public class ConnectivityServiceTest { @Test public void testMMSonWiFi() throws Exception { // Test bringing up cellular without MMS NetworkRequest gets reaped - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS); - ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV(); mCellNetworkAgent.connectWithoutInternet(); - waitFor(cv); + mCellNetworkAgent.expectDisconnected(); waitForIdle(); assertEmpty(mCm.getAllNetworks()); verifyNoNetwork(); // Test bringing up validated WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - cv = waitForConnectivityBroadcasts(1); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + final ConditionVariable cv = waitForConnectivityBroadcasts(1); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -2394,23 +2145,22 @@ public class ConnectivityServiceTest { mCm.requestNetwork(builder.build(), networkCallback); // Test bringing up unvalidated cellular with MMS - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS); mCellNetworkAgent.connectWithoutInternet(); networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); verifyActiveNetwork(TRANSPORT_WIFI); // Test releasing NetworkRequest disconnects cellular with MMS - cv = mCellNetworkAgent.getDisconnectedCV(); mCm.unregisterNetworkCallback(networkCallback); - waitFor(cv); + mCellNetworkAgent.expectDisconnected(); verifyActiveNetwork(TRANSPORT_WIFI); } @Test public void testMMSonCell() throws Exception { // Test bringing up cellular without MMS - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); ConditionVariable cv = waitForConnectivityBroadcasts(1); mCellNetworkAgent.connect(false); waitFor(cv); @@ -2423,16 +2173,16 @@ public class ConnectivityServiceTest { mCm.requestNetwork(builder.build(), networkCallback); // Test bringing up MMS cellular network - MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + TestNetworkAgentWrapper + mmsNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS); mmsNetworkAgent.connectWithoutInternet(); networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent - cv = mmsNetworkAgent.getDisconnectedCV(); mCm.unregisterNetworkCallback(networkCallback); - waitFor(cv); + mmsNetworkAgent.expectDisconnected(); verifyActiveNetwork(TRANSPORT_CELLULAR); } @@ -2446,12 +2196,12 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(request, callback); // Bring up validated mobile data. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); // Bring up wifi with partial connectivity. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connectWithPartialConnectivity(); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); @@ -2484,7 +2234,7 @@ public class ConnectivityServiceTest { // Disconnect and reconnect wifi with partial connectivity again. mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connectWithPartialConnectivity(); callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); @@ -2500,7 +2250,7 @@ public class ConnectivityServiceTest { // If user accepted partial connectivity before, and device reconnects to that network // again, but now the network has full connectivity. The network shouldn't contain // NET_CAPABILITY_PARTIAL_CONNECTIVITY. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); // acceptUnvalidated is also used as setting for accepting partial networks. mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */, true /* acceptUnvalidated */); @@ -2524,7 +2274,7 @@ public class ConnectivityServiceTest { // The user accepted partial connectivity and selected "don't ask again". Now the user // reconnects to the partial connectivity network. Switch to wifi as soon as partial // connectivity is detected. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */, true /* acceptUnvalidated */); mWiFiNetworkAgent.connectWithPartialConnectivity(); @@ -2548,7 +2298,7 @@ public class ConnectivityServiceTest { // If the user accepted partial connectivity, and the device auto-reconnects to the partial // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */, true /* acceptUnvalidated */); @@ -2580,7 +2330,7 @@ public class ConnectivityServiceTest { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); String redirectUrl = "http://android.com/path"; mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl); captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2629,7 +2379,7 @@ public class ConnectivityServiceTest { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); String firstRedirectUrl = "http://example.com/firstPath"; mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2642,7 +2392,7 @@ public class ConnectivityServiceTest { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); String secondRedirectUrl = "http://example.com/secondPath"; mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl); captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2680,7 +2430,7 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(validatedRequest, validatedCallback); // Bring up wifi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); @@ -2740,14 +2490,12 @@ public class ConnectivityServiceTest { setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID); // Bring up a network with a captive portal. // Expect it to fail to connect and not result in any callbacks. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); String firstRedirectUrl = "http://example.com/firstPath"; - ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV(); - ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived(); mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); - waitFor(disconnectCv); - waitFor(avoidCv); + mWiFiNetworkAgent.expectDisconnected(); + mWiFiNetworkAgent.expectPreventReconnectReceived(); assertNoCallbacks(captivePortalCallback, validatedCallback); } @@ -2846,7 +2594,7 @@ public class ConnectivityServiceTest { LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo"); LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar"); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2973,7 +2721,7 @@ public class ConnectivityServiceTest { public void writeToParcel(Parcel dest, int flags) {} } - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier(); @@ -3026,14 +2774,14 @@ public class ConnectivityServiceTest { cellNetworkCallback.assertNoCallback(); // Bring up cell and expect CALLBACK_AVAILABLE. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi and expect CALLBACK_AVAILABLE. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); cellNetworkCallback.assertNoCallback(); defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); @@ -3046,7 +2794,7 @@ public class ConnectivityServiceTest { assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up cell. Expect no default network callback, since it won't be the default. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultNetworkCallback.assertNoCallback(); @@ -3065,7 +2813,8 @@ public class ConnectivityServiceTest { assertEquals(null, mCm.getActiveNetwork()); final int uid = Process.myUid(); - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); @@ -3090,7 +2839,7 @@ public class ConnectivityServiceTest { mCm.requestNetwork(cellRequest, cellNetworkCallback); // Bring up the mobile network. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); // We should get onAvailable(), onCapabilitiesChanged(), and @@ -3160,7 +2909,7 @@ public class ConnectivityServiceTest { waitForIdle(); } - private boolean isForegroundNetwork(MockNetworkAgent network) { + private boolean isForegroundNetwork(TestNetworkAgentWrapper network) { NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork()); assertNotNull(nc); return nc.hasCapability(NET_CAPABILITY_FOREGROUND); @@ -3179,13 +2928,13 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(request, callback); mCm.registerNetworkCallback(fgRequest, fgCallback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertTrue(isForegroundNetwork(mCellNetworkAgent)); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); // When wifi connects, cell lingers. @@ -3278,7 +3027,7 @@ public class ConnectivityServiceTest { } }); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); // Don't request that the network validate, because otherwise connect() will block until // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired, // and we won't actually measure anything. @@ -3295,7 +3044,7 @@ public class ConnectivityServiceTest { onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS); // Give wifi a high enough score that we'll linger cell when wifi comes up. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.adjustScore(40); mWiFiNetworkAgent.connect(false); @@ -3338,7 +3087,7 @@ public class ConnectivityServiceTest { assertTrue(testFactory.getMyStartRequested()); // Bring up wifi. The factory stops looking for a network. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); // Score 60 - 40 penalty for not validated yet, then 60 when it validates testFactory.expectAddRequestsWithScores(20, 60); mWiFiNetworkAgent.connect(true); @@ -3355,7 +3104,7 @@ public class ConnectivityServiceTest { // Bring up cell data and check that the factory stops looking. assertLength(1, mCm.getAllNetworks()); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); @@ -3384,48 +3133,46 @@ public class ConnectivityServiceTest { @Test public void testAvoidBadWifiSetting() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); - final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker(); final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI; - tracker.configRestrictsAvoidBadWifi = false; + mPolicyTracker.mConfigRestrictsAvoidBadWifi = false; String[] values = new String[] {null, "0", "1"}; for (int i = 0; i < values.length; i++) { Settings.Global.putInt(cr, settingName, 1); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); waitForIdle(); String msg = String.format("config=false, setting=%s", values[i]); assertTrue(mService.avoidBadWifi()); - assertFalse(msg, tracker.shouldNotifyWifiUnvalidated()); + assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated()); } - tracker.configRestrictsAvoidBadWifi = true; + mPolicyTracker.mConfigRestrictsAvoidBadWifi = true; Settings.Global.putInt(cr, settingName, 0); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); waitForIdle(); assertFalse(mService.avoidBadWifi()); - assertFalse(tracker.shouldNotifyWifiUnvalidated()); + assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated()); Settings.Global.putInt(cr, settingName, 1); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); waitForIdle(); assertTrue(mService.avoidBadWifi()); - assertFalse(tracker.shouldNotifyWifiUnvalidated()); + assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated()); Settings.Global.putString(cr, settingName, null); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); waitForIdle(); assertFalse(mService.avoidBadWifi()); - assertTrue(tracker.shouldNotifyWifiUnvalidated()); + assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated()); } @Test public void testAvoidBadWifi() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); - final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker(); // Pretend we're on a carrier that restricts switching away from bad wifi. - tracker.configRestrictsAvoidBadWifi = true; + mPolicyTracker.mConfigRestrictsAvoidBadWifi = true; // File a request for cell to ensure it doesn't go down. final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); @@ -3444,17 +3191,17 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback); Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); // Bring up validated cell. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); Network cellNetwork = mCellNetworkAgent.getNetwork(); // Bring up validated wifi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); @@ -3476,14 +3223,14 @@ public class ConnectivityServiceTest { // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect // that we switch back to cell. - tracker.configRestrictsAvoidBadWifi = false; - tracker.reevaluate(); + mPolicyTracker.mConfigRestrictsAvoidBadWifi = false; + mPolicyTracker.reevaluate(); defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertEquals(mCm.getActiveNetwork(), cellNetwork); // Switch back to a restrictive carrier. - tracker.configRestrictsAvoidBadWifi = true; - tracker.reevaluate(); + mPolicyTracker.mConfigRestrictsAvoidBadWifi = true; + mPolicyTracker.reevaluate(); defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mCm.getActiveNetwork(), wifiNetwork); @@ -3498,7 +3245,7 @@ public class ConnectivityServiceTest { // Disconnect and reconnect wifi to clear the one-time switch above. mWiFiNetworkAgent.disconnect(); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); @@ -3512,7 +3259,7 @@ public class ConnectivityServiceTest { // Simulate the user selecting "switch" and checking the don't ask again checkbox. Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); // We now switch to cell. defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); @@ -3525,11 +3272,11 @@ public class ConnectivityServiceTest { // Simulate the user turning the cellular fallback setting off and then on. // We switch to wifi and then to cell. Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mCm.getActiveNetwork(), wifiNetwork); Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertEquals(mCm.getActiveNetwork(), cellNetwork); @@ -3547,14 +3294,13 @@ public class ConnectivityServiceTest { @Test public void testMeteredMultipathPreferenceSetting() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); - final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker(); final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; for (int config : Arrays.asList(0, 3, 2)) { for (String setting: Arrays.asList(null, "0", "2", "1")) { - tracker.configMeteredMultipathPreference = config; + mPolicyTracker.mConfigMeteredMultipathPreference = config; Settings.Global.putString(cr, settingName, setting); - tracker.reevaluate(); + mPolicyTracker.reevaluate(); waitForIdle(); final int expected = (setting != null) ? Integer.parseInt(setting) : config; @@ -3575,7 +3321,7 @@ public class ConnectivityServiceTest { final TestNetworkCallback networkCallback = new TestNetworkCallback(); mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false, TEST_CALLBACK_TIMEOUT_MS); @@ -3595,7 +3341,7 @@ public class ConnectivityServiceTest { final TestNetworkCallback networkCallback = new TestNetworkCallback(); mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false, TEST_CALLBACK_TIMEOUT_MS); @@ -3623,7 +3369,7 @@ public class ConnectivityServiceTest { networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null); // create a network satisfying request - validate that request not triggered - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); networkCallback.assertNoCallback(); } @@ -3646,7 +3392,7 @@ public class ConnectivityServiceTest { networkCallback.assertNoCallback(); // create a network satisfying request - validate that request not triggered - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); networkCallback.assertNoCallback(); } @@ -3876,7 +3622,7 @@ public class ConnectivityServiceTest { assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork())); } - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); ConditionVariable cv = waitForConnectivityBroadcasts(1); mWiFiNetworkAgent.connect(true); waitFor(cv); @@ -3940,10 +3686,10 @@ public class ConnectivityServiceTest { callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); // Check that a started keepalive can be stopped. - mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS); ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); - mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS); ka.stop(); callback.expectStopped(); @@ -3961,7 +3707,7 @@ public class ConnectivityServiceTest { ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); mWiFiNetworkAgent.disconnect(); - waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + mWiFiNetworkAgent.expectDisconnected(); callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK); // ... and that stopping it after that has no adverse effects. @@ -3972,7 +3718,7 @@ public class ConnectivityServiceTest { // Reconnect. myNet = connectKeepaliveNetwork(lp); - mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS); // Check that keepalive slots start from 1 and increment. The first one gets slot 1. mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); @@ -4092,12 +3838,12 @@ public class ConnectivityServiceTest { } // Check that a started keepalive can be stopped. - mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); try (SocketKeepalive ka = mCm.createSocketKeepalive( myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); callback.expectStarted(); - mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS); ka.stop(); callback.expectStopped(); @@ -4137,7 +3883,7 @@ public class ConnectivityServiceTest { ka.start(validKaInterval); callback.expectStarted(); mWiFiNetworkAgent.disconnect(); - waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + mWiFiNetworkAgent.expectDisconnected(); callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK); // ... and that stopping it after that has no adverse effects. @@ -4150,7 +3896,7 @@ public class ConnectivityServiceTest { // Reconnect. myNet = connectKeepaliveNetwork(lp); - mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); // Check that keepalive slots start from 1 and increment. The first one gets slot 1. mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); @@ -4187,7 +3933,7 @@ public class ConnectivityServiceTest { // assertFalse(isUdpPortInUse(srcPort2)); mWiFiNetworkAgent.disconnect(); - waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + mWiFiNetworkAgent.expectDisconnected(); mWiFiNetworkAgent = null; } @@ -4263,7 +4009,7 @@ public class ConnectivityServiceTest { testSocketV6.close(); mWiFiNetworkAgent.disconnect(); - waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + mWiFiNetworkAgent.expectDisconnected(); mWiFiNetworkAgent = null; } @@ -4279,8 +4025,8 @@ public class ConnectivityServiceTest { lp.addLinkAddress(new LinkAddress(myIPv4, 25)); lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254"))); Network myNet = connectKeepaliveNetwork(lp); - mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS); - mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); + mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS); TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor); @@ -4316,7 +4062,7 @@ public class ConnectivityServiceTest { // assertFalse(isUdpPortInUse(srcPort)); mWiFiNetworkAgent.disconnect(); - waitFor(mWiFiNetworkAgent.getDisconnectedCV()); + mWiFiNetworkAgent.expectDisconnected(); mWiFiNetworkAgent = null; } @@ -4379,9 +4125,9 @@ public class ConnectivityServiceTest { TestNetworkPinner.pin(mServiceContext, wifiRequest); assertNull(mCm.getBoundNetworkForProcess()); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); // When wi-fi connects, expect to be pinned. @@ -4394,7 +4140,7 @@ public class ConnectivityServiceTest { assertNotPinnedToWifi(); // Reconnecting does not cause the pin to come back. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); assertFalse(TestNetworkPinner.awaitPin(100)); assertNotPinnedToWifi(); @@ -4416,14 +4162,14 @@ public class ConnectivityServiceTest { // Pinning takes effect even if the pinned network is the default when the pin is set... TestNetworkPinner.pin(mServiceContext, wifiRequest); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); assertTrue(TestNetworkPinner.awaitPin(100)); assertPinnedToWifiWithWifiDefault(); // ... and is maintained even when that network is no longer the default. cv = waitForConnectivityBroadcasts(1); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mCellNetworkAgent.connect(true); waitFor(cv); assertPinnedToWifiWithCellDefault(); @@ -4526,7 +4272,7 @@ public class ConnectivityServiceTest { ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1); verifyNoNetwork(); - MockNetworkAgent wifiAware = new MockNetworkAgent(TRANSPORT_WIFI_AWARE); + TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE); assertNull(mCm.getActiveNetworkInfo()); Network[] allNetworks = mCm.getAllNetworks(); @@ -4599,7 +4345,7 @@ public class ConnectivityServiceTest { // Verify direct routes are added when network agent is first registered in // ConnectivityService. - MockNetworkAgent networkAgent = new MockNetworkAgent(TRANSPORT_WIFI, lp); + TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); networkAgent.connect(true); networkCallback.expectCallback(CallbackRecord.AVAILABLE, networkAgent); networkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, networkAgent); @@ -4631,8 +4377,8 @@ public class ConnectivityServiceTest { @Test public void testStatsIfacesChanged() throws Exception { - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()}; Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()}; @@ -4708,7 +4454,7 @@ public class ConnectivityServiceTest { // Clear any interactions that occur as a result of CS starting up. reset(mMockDnsResolver); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); waitForIdle(); verify(mMockDnsResolver, never()).setResolverConfiguration(any()); verifyNoMoreInteractions(mMockDnsResolver); @@ -4791,7 +4537,7 @@ public class ConnectivityServiceTest { .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); waitForIdle(); // CS tells netd about the empty DNS config for this network. verify(mMockDnsResolver, never()).setResolverConfiguration(any()); @@ -4880,7 +4626,7 @@ public class ConnectivityServiceTest { .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); waitForIdle(); LinkProperties lp = new LinkProperties(); mCellNetworkAgent.sendLinkProperties(lp); @@ -5015,7 +4761,7 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(defaultCallback); defaultCallback.assertNoCallback(); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -5025,14 +4771,16 @@ public class ConnectivityServiceTest { vpnNetworkCallback.assertNoCallback(); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.setUids(ranges); // VPN networks do not satisfy the default request and are automatically validated // by NetworkMonitor - assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities)); + assertFalse(NetworkMonitorUtils.isValidationRequired( + vpnNetworkAgent.getNetworkCapabilities())); vpnNetworkAgent.setNetworkValid(); vpnNetworkAgent.connect(false); @@ -5110,13 +4858,14 @@ public class ConnectivityServiceTest { final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); @@ -5140,13 +4889,14 @@ public class ConnectivityServiceTest { final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); @@ -5170,14 +4920,15 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(callback); // Bring up Ethernet. - mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET); + mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET); mEthernetNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); callback.assertNoCallback(); // Bring up a VPN that has the INTERNET capability, initially unvalidated. final int uid = Process.myUid(); - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); @@ -5199,9 +4950,10 @@ public class ConnectivityServiceTest { assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED)); assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET)); - assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities)); + assertFalse(NetworkMonitorUtils.isValidationRequired( + vpnNetworkAgent.getNetworkCapabilities())); assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired( - vpnNetworkAgent.mNetworkCapabilities)); + vpnNetworkAgent.getNetworkCapabilities())); // Pretend that the VPN network validates. vpnNetworkAgent.setNetworkValid(); @@ -5229,7 +4981,8 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); vpnNetworkCallback.assertNoCallback(); - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); @@ -5246,7 +4999,7 @@ public class ConnectivityServiceTest { assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); // Connect cell and use it as an underlying network. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); mService.setUnderlyingNetworksForVpn( @@ -5257,7 +5010,7 @@ public class ConnectivityServiceTest { && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.connect(true); @@ -5327,7 +5080,8 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); vpnNetworkCallback.assertNoCallback(); - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); @@ -5345,7 +5099,7 @@ public class ConnectivityServiceTest { assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); // Connect to Cell; Cell is the default network. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent, @@ -5354,7 +5108,7 @@ public class ConnectivityServiceTest { && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)); // Connect to WiFi; WiFi is the new default. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.connect(true); @@ -5382,7 +5136,7 @@ public class ConnectivityServiceTest { public void testIsActiveNetworkMeteredOverWifi() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.connect(true); waitForIdle(); @@ -5394,7 +5148,7 @@ public class ConnectivityServiceTest { public void testIsActiveNetworkMeteredOverCell() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); mCellNetworkAgent.connect(true); waitForIdle(); @@ -5406,14 +5160,15 @@ public class ConnectivityServiceTest { public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); mCellNetworkAgent.connect(true); waitForIdle(); assertTrue(mCm.isActiveNetworkMetered()); // Connect VPN network. By default it is using current default network (Cell). - MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); final int uid = Process.myUid(); ranges.add(new UidRange(uid, uid)); @@ -5429,7 +5184,7 @@ public class ConnectivityServiceTest { assertTrue(mCm.isActiveNetworkMetered()); // Connect WiFi. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.connect(true); waitForIdle(); @@ -5460,20 +5215,21 @@ public class ConnectivityServiceTest { public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); mCellNetworkAgent.connect(true); waitForIdle(); assertTrue(mCm.isActiveNetworkMetered()); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.connect(true); waitForIdle(); assertFalse(mCm.isActiveNetworkMetered()); // Connect VPN network. - MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); final int uid = Process.myUid(); ranges.add(new UidRange(uid, uid)); @@ -5531,14 +5287,15 @@ public class ConnectivityServiceTest { public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception { // Returns true by default when no network is available. assertTrue(mCm.isActiveNetworkMetered()); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.connect(true); waitForIdle(); assertFalse(mCm.isActiveNetworkMetered()); // Connect VPN network. - MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); final int uid = Process.myUid(); ranges.add(new UidRange(uid, uid)); @@ -5582,21 +5339,21 @@ public class ConnectivityServiceTest { .build(); mCm.registerNetworkCallback(cellRequest, cellNetworkCallback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - mService.setUidRulesChanged(RULE_REJECT_ALL); + setUidRulesChanged(RULE_REJECT_ALL); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); // ConnectivityService should cache it not to invoke the callback again. - mService.setUidRulesChanged(RULE_REJECT_METERED); + setUidRulesChanged(RULE_REJECT_METERED); cellNetworkCallback.assertNoCallback(); - mService.setUidRulesChanged(RULE_NONE); + setUidRulesChanged(RULE_NONE); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); - mService.setUidRulesChanged(RULE_REJECT_METERED); + setUidRulesChanged(RULE_REJECT_METERED); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); // Restrict the network based on UID rule and NOT_METERED capability change. @@ -5607,18 +5364,18 @@ public class ConnectivityServiceTest { cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); - mService.setUidRulesChanged(RULE_ALLOW_METERED); + setUidRulesChanged(RULE_ALLOW_METERED); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); - mService.setUidRulesChanged(RULE_NONE); + setUidRulesChanged(RULE_NONE); cellNetworkCallback.assertNoCallback(); // Restrict the network based on BackgroundRestricted. - mService.setRestrictBackgroundChanged(true); + setRestrictBackgroundChanged(true); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); - mService.setRestrictBackgroundChanged(true); + setRestrictBackgroundChanged(true); cellNetworkCallback.assertNoCallback(); - mService.setRestrictBackgroundChanged(false); + setRestrictBackgroundChanged(false); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); @@ -5631,18 +5388,18 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(defaultCallback); // No Networkcallbacks invoked before any network is active. - mService.setUidRulesChanged(RULE_REJECT_ALL); - mService.setUidRulesChanged(RULE_NONE); - mService.setUidRulesChanged(RULE_REJECT_METERED); + setUidRulesChanged(RULE_REJECT_ALL); + setUidRulesChanged(RULE_NONE); + setUidRulesChanged(RULE_REJECT_METERED); defaultCallback.assertNoCallback(); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent); // Allow to use the network after switching to NOT_METERED network. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mWiFiNetworkAgent.connect(true); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); @@ -5658,8 +5415,8 @@ public class ConnectivityServiceTest { defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); // Verify there's no Networkcallbacks invoked after data saver on/off. - mService.setRestrictBackgroundChanged(true); - mService.setRestrictBackgroundChanged(false); + setRestrictBackgroundChanged(true); + setRestrictBackgroundChanged(false); defaultCallback.assertNoCallback(); mCellNetworkAgent.disconnect(); @@ -5709,7 +5466,7 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(networkRequest, networkCallback); // Prepare ipv6 only link properties. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); final int cellNetId = mCellNetworkAgent.getNetwork().netId; final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -5756,7 +5513,7 @@ public class ConnectivityServiceTest { verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started. - Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent); + Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent); assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix()); mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */, kNat64PrefixString, 96); @@ -5863,7 +5620,7 @@ public class ConnectivityServiceTest { .build(); mCm.registerNetworkCallback(networkRequest, networkCallback); - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); mCellNetworkAgent.sendLinkProperties(cellLp); @@ -5873,7 +5630,7 @@ public class ConnectivityServiceTest { verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(), eq(ConnectivityManager.TYPE_MOBILE)); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName(WIFI_IFNAME); mWiFiNetworkAgent.sendLinkProperties(wifiLp); @@ -5898,7 +5655,7 @@ public class ConnectivityServiceTest { eq(ConnectivityManager.TYPE_MOBILE)); // reconnect wifi - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); wifiLp.setInterfaceName(WIFI_IFNAME); mWiFiNetworkAgent.sendLinkProperties(wifiLp); mWiFiNetworkAgent.connect(true); @@ -5944,7 +5701,7 @@ public class ConnectivityServiceTest { public void testTcpBufferReset() throws Exception { final String testTcpBufferSizes = "1,2,3,4,5,6"; - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); reset(mMockNetd); // Switching default network updates TCP buffer sizes. mCellNetworkAgent.connect(false); @@ -5960,7 +5717,7 @@ public class ConnectivityServiceTest { @Test public void testGetGlobalProxyForNetwork() throws Exception { final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); final Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo); assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork)); @@ -5969,7 +5726,7 @@ public class ConnectivityServiceTest { @Test public void testGetProxyForActiveNetwork() throws Exception { final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); waitForIdle(); assertNull(mService.getProxyForNetwork(null)); @@ -5988,14 +5745,15 @@ public class ConnectivityServiceTest { final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); // Set up a WiFi network with no proxy - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); waitForIdle(); assertNull(mService.getProxyForNetwork(null)); // Set up a VPN network with a proxy final int uid = Process.myUid(); - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); mMockVpn.setUids(ranges); @@ -6044,7 +5802,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); - final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange); + final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange); // Connected VPN should have interface rules set up. There are two expected invocations, // one during VPN uid update, one during VPN LinkProperties update @@ -6070,7 +5828,8 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); - final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange); + final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn( + lp, Process.SYSTEM_UID, vpnRange); // Legacy VPN should not have interface rules set up verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any()); @@ -6085,7 +5844,8 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); - final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange); + final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn( + lp, Process.SYSTEM_UID, vpnRange); // IPv6 unreachable route should not be misinterpreted as a default route verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any()); @@ -6098,7 +5858,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); - final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange); + final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange); // Connected VPN should have interface rules set up. There are two expected invocations, // one during VPN uid update, one during VPN LinkProperties update @@ -6147,7 +5907,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. final UidRange vpnRange = UidRange.createForUser(VPN_USER); - final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, + final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, Collections.singleton(vpnRange)); reset(mMockNetd); @@ -6169,9 +5929,10 @@ public class ConnectivityServiceTest { } - private MockNetworkAgent establishVpn(LinkProperties lp, int establishingUid, + private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid, Set<UidRange> vpnRange) throws Exception { - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN, lp); + final TestNetworkAgentWrapper + vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp); vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.connect(); diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp index 54f0816f0398..31aa2494052c 100644 --- a/tools/aapt2/dump/DumpManifest.cpp +++ b/tools/aapt2/dump/DumpManifest.cpp @@ -468,14 +468,12 @@ class Manifest : public ManifestExtractor::Element { } if (platformVersionName) { printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data())); - } - if (platformVersionNameInt) { + } else if (platformVersionNameInt) { printer->Print(StringPrintf(" platformBuildVersionName='%d'", *platformVersionNameInt)); } if (platformVersionCode) { printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data())); - } - if (platformVersionCodeInt) { + } else if (platformVersionCodeInt) { printer->Print(StringPrintf(" platformBuildVersionCode='%d'", *platformVersionCodeInt)); } if (compilesdkVersion) { diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp index 7f5d10475f93..7ff9bf5aa8df 100644 --- a/tools/aapt2/optimize/ResourcePathShortener.cpp +++ b/tools/aapt2/optimize/ResourcePathShortener.cpp @@ -16,6 +16,7 @@ #include "optimize/ResourcePathShortener.h" +#include <set> #include <unordered_set> #include "androidfw/StringPiece.h" @@ -71,10 +72,19 @@ std::string GetShortenedPath(const android::StringPiece& shortened_filename, return shortened_path; } +// implement custom comparator of FileReference pointers so as to use the +// underlying filepath as key rather than the integer address. This is to ensure +// determinism of output for colliding files. +struct PathComparator { + bool operator() (const FileReference* lhs, const FileReference* rhs) const { + return lhs->path->compare(*rhs->path); + } +}; + bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) { // used to detect collisions std::unordered_set<std::string> shortened_paths; - std::unordered_set<FileReference*> file_refs; + std::set<FileReference*, PathComparator> file_refs; for (auto& package : table->packages) { for (auto& type : package->types) { for (auto& entry : type->entries) { diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp index 1f4569495186..f5a02be0ea5e 100644 --- a/tools/aapt2/optimize/ResourcePathShortener_test.cpp +++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp @@ -29,6 +29,14 @@ android::StringPiece GetExtension(android::StringPiece path) { return android::StringPiece(iter, path.end() - iter); } +void FillTable(aapt::test::ResourceTableBuilder& builder, int start, int end) { + for (int i=start; i<end; i++) { + builder.AddFileReference( + "android:drawable/xmlfile" + std::to_string(i), + "res/drawable/xmlfile" + std::to_string(i) + ".xml"); + } +} + namespace aapt { TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) { @@ -114,4 +122,45 @@ TEST(ResourcePathShortenerTest, KeepExtensions) { EXPECT_THAT(GetExtension(path_map[original_png_path]), Eq(android::StringPiece(".png"))); } +TEST(ResourcePathShortenerTest, DeterministicallyHandleCollisions) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + + // 4000 resources is the limit at which the hash space is expanded to 3 + // letters to reduce collisions, we want as many collisions as possible thus + // N-1. + const auto kNumResources = 3999; + const auto kNumTries = 5; + + test::ResourceTableBuilder builder1; + FillTable(builder1, 0, kNumResources); + std::unique_ptr<ResourceTable> table1 = builder1.Build(); + std::map<std::string, std::string> expected_mapping; + ASSERT_TRUE(ResourcePathShortener(expected_mapping).Consume(context.get(), table1.get())); + + // We are trying to ensure lack of non-determinism, it is not simple to prove + // a negative, thus we must try the test a few times so that the test itself + // is non-flaky. Basically create the pathmap 5 times from the same set of + // resources but a different order of addition and then ensure they are always + // mapped to the same short path. + for (int i=0; i<kNumTries; i++) { + test::ResourceTableBuilder builder2; + // This loop adds resources to the resource table in the range of + // [0:kNumResources). Adding the file references in different order makes + // non-determinism more likely to surface. Thus we add resources + // [start_index:kNumResources) first then [0:start_index). We also use a + // different start_index each run. + int start_index = (kNumResources/kNumTries)*i; + FillTable(builder2, start_index, kNumResources); + FillTable(builder2, 0, start_index); + std::unique_ptr<ResourceTable> table2 = builder2.Build(); + + std::map<std::string, std::string> actual_mapping; + ASSERT_TRUE(ResourcePathShortener(actual_mapping).Consume(context.get(), table2.get())); + + for (auto& item : actual_mapping) { + ASSERT_THAT(expected_mapping[item.first], Eq(item.second)); + } + } +} + } // namespace aapt diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt index 7ee79f651274..5061be2091e5 100644 --- a/tools/codegen/src/com/android/codegen/ClassInfo.kt +++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt @@ -1,30 +1,39 @@ package com.android.codegen -import com.github.javaparser.JavaParser import com.github.javaparser.ParseProblemException +import com.github.javaparser.ParseResult +import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration open class ClassInfo(val sourceLines: List<String>) { private val userSourceCode = (sourceLines + "}").joinToString("\n") - val fileAst = try { - JavaParser.parse(userSourceCode)!! + val fileAst: CompilationUnit = try { + JAVA_PARSER.parse(userSourceCode).throwIfFailed() } catch (e: ParseProblemException) { - throw RuntimeException("Failed to parse code:\n" + + throw parseFailed(cause = e) + } + + fun <T> ParseResult<T>.throwIfFailed(): T { + if (problems.isNotEmpty()) { + throw parseFailed( + desc = this@throwIfFailed.problems.joinToString("\n"), + cause = this@throwIfFailed.problems.mapNotNull { it.cause.orElse(null) }.firstOrNull()) + } + return result.get() + } + + private fun parseFailed(cause: Throwable? = null, desc: String = ""): RuntimeException { + return RuntimeException("Failed to parse code:\n" + userSourceCode .lines() .mapIndexed { lnNum, ln -> "/*$lnNum*/$ln" } - .joinToString("\n"), - e) + .joinToString("\n") + "\n$desc", + cause) } - val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration - fun hasMethod(name: String, vararg argTypes: String): Boolean { - return classAst.methods.any { - it.name.asString() == name && - it.parameters.map { it.type.asString() } == argTypes.toList() - } - } + val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration + val nestedClasses = classAst.members.filterIsInstance<ClassOrInterfaceDeclaration>() val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration) .implementedTypes.map { it.asString() } @@ -42,8 +51,4 @@ open class ClassInfo(val sourceLines: List<String>) { .filterNot { it.isTransient || it.isStatic } .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) } .apply { lastOrNull()?.isLast = true } - val lazyTransientFields = classAst.fields - .filter { it.isTransient && !it.isStatic } - .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) } - .filter { hasMethod("lazyInit${it.NameUpperCamel}") } }
\ No newline at end of file diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt index 33256b787964..22b5d8815e7d 100644 --- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt +++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt @@ -1,9 +1,9 @@ package com.android.codegen +import com.github.javaparser.ast.Modifier import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration import com.github.javaparser.ast.body.TypeDeclaration -import com.github.javaparser.ast.expr.BooleanLiteralExpr -import com.github.javaparser.ast.expr.NormalAnnotationExpr +import com.github.javaparser.ast.expr.* import com.github.javaparser.ast.type.ClassOrInterfaceType /** @@ -32,10 +32,31 @@ class ClassPrinter( val PluralOf by lazy { classRef("com.android.internal.util.DataClass.PluralOf") } val Each by lazy { classRef("com.android.internal.util.DataClass.Each") } val DataClassGenerated by lazy { classRef("com.android.internal.util.DataClass.Generated") } + val DataClassSuppressConstDefs by lazy { classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") } + val DataClassSuppress by lazy { classRef("com.android.internal.util.DataClass.Suppress") } val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") } val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") } + val Parcelable by lazy { classRef("android.os.Parcelable") } val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") } + init { + val fieldsWithMissingNullablity = fields.filter { field -> + !field.isPrimitive + && field.fieldAst.modifiers.none { it.keyword == Modifier.Keyword.TRANSIENT } + && "@$Nullable" !in field.annotations + && "@$NonNull" !in field.annotations + } + if (fieldsWithMissingNullablity.isNotEmpty()) { + abort("Non-primitive fields must have @$Nullable or @$NonNull annotation.\n" + + "Missing nullability annotations on: " + + fieldsWithMissingNullablity.joinToString(", ") { it.name }) + } + + if (!classAst.isFinal && + classAst.extendedTypes.any { it.nameAsString == Parcelable }) { + abort("Parcelable classes must be final") + } + } /** * Optionally shortens a class reference if there's a corresponding import present @@ -54,7 +75,7 @@ class ClassPrinter( return simpleName } else { val outerClass = pkg.substringAfterLast(".", "") - if (outerClass.firstOrNull()?.isUpperCase() ?: false) { + if (outerClass.firstOrNull()?.isUpperCase() == true) { return classRef(pkg) + "." + simpleName } } @@ -89,7 +110,9 @@ class ClassPrinter( ?.toMap() ?: emptyMap() - val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, Each, UnsupportedAppUsage) + val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, UnsupportedAppUsage, + DataClassSuppressConstDefs) + val knownNonValidationAnnotations = internalAnnotations + Each + Nullable /** * @return whether the given feature is enabled @@ -109,7 +132,9 @@ class ClassPrinter( return when (this) { FeatureFlag.SETTERS -> !FeatureFlag.CONSTRUCTOR() && !FeatureFlag.BUILDER() && fields.any { !it.isFinal } - FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS) || onByDefault + FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS) + || fields.any { it.hasDefault } + || onByDefault FeatureFlag.CONSTRUCTOR -> !FeatureFlag.BUILDER() FeatureFlag.PARCELABLE -> "Parcelable" in superInterfaces FeatureFlag.AIDL -> FeatureFlag.PARCELABLE() @@ -287,6 +312,48 @@ class ClassPrinter( var BuilderClass = CANONICAL_BUILDER_CLASS var BuilderType = BuilderClass + genericArgs + val customBaseBuilderAst: ClassOrInterfaceDeclaration? by lazy { + nestedClasses.find { it.nameAsString == BASE_BUILDER_CLASS } + } + + val suppressedMembers by lazy { + getSuppressedMembers(classAst) + } + val builderSuppressedMembers by lazy { + getSuppressedMembers(customBaseBuilderAst) + } + + private fun getSuppressedMembers(clazz: ClassOrInterfaceDeclaration?): List<String> { + return clazz + ?.annotations + ?.find { it.nameAsString == DataClassSuppress } + ?.as_<SingleMemberAnnotationExpr>() + ?.memberValue + ?.run { + when (this) { + is ArrayInitializerExpr -> values.map { it.asLiteralStringValueExpr().value } + is StringLiteralExpr -> listOf(value) + else -> abort("Can't parse annotation arg: $this") + } + } + ?: emptyList() + } + + fun isMethodGenerationSuppressed(name: String, vararg argTypes: String): Boolean { + return name in suppressedMembers || hasMethod(name, *argTypes) + } + + fun hasMethod(name: String, vararg argTypes: String): Boolean { + return classAst.methods.any { + it.name.asString() == name && + it.parameters.map { it.type.asString() } == argTypes.toList() + } + } + + val lazyTransientFields = classAst.fields + .filter { it.isTransient && !it.isStatic } + .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) } + .filter { hasMethod("lazyInit${it.NameUpperCamel}") } init { val builderFactoryOverride = classAst.methods.find { @@ -301,7 +368,7 @@ class ClassPrinter( it.nameAsString == CANONICAL_BUILDER_CLASS } if (builderExtension != null) { - BuilderClass = GENERATED_BUILDER_CLASS + BuilderClass = BASE_BUILDER_CLASS val tp = (builderExtension as ClassOrInterfaceDeclaration).typeParameters BuilderType = if (tp.isEmpty()) BuilderClass else "$BuilderClass<${tp.map { it.nameAsString }.joinToString(", ")}>" diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt index f326fd5601fe..6b0009ccff76 100644 --- a/tools/codegen/src/com/android/codegen/FieldInfo.kt +++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt @@ -1,6 +1,5 @@ package com.android.codegen -import com.github.javaparser.JavaParser import com.github.javaparser.ast.body.FieldDeclaration import com.github.javaparser.ast.expr.ClassExpr import com.github.javaparser.ast.expr.Name @@ -9,7 +8,6 @@ import com.github.javaparser.ast.expr.StringLiteralExpr import com.github.javaparser.ast.type.ArrayType import com.github.javaparser.ast.type.ClassOrInterfaceType import com.github.javaparser.javadoc.Javadoc -import java.lang.Long data class FieldInfo( val index: Int, @@ -85,7 +83,7 @@ data class FieldInfo( variableAst.initializer.orElse(null)?.let { return it } classInfo.classAst.methods.find { it.nameAsString == "default$NameUpperCamel" && it.parameters.isEmpty() - }?.run { "$nameAsString()" }?.let { return it } + }?.run { return "$nameAsString()" } if (FieldClass == "List") return "${classPrinter.memberRef("java.util.Collections.emptyList")}()" return null } @@ -95,7 +93,7 @@ data class FieldInfo( // Generic args val isArray = Type.endsWith("[]") val isList = FieldClass == "List" || FieldClass == "ArrayList" - val fieldBit = "0x${Long.toHexString(1L shl index)}" + val fieldBit = bitAtExpr(index) var isLast = false val isFinal = fieldAst.isFinal val fieldTypeGenegicArgs = when (typeAst) { @@ -116,8 +114,9 @@ data class FieldInfo( classPrinter { fieldAst.addAnnotation(SingleMemberAnnotationExpr( Name(ParcelWith), - ClassExpr(JavaParser.parseClassOrInterfaceType( - "$Parcelling.BuiltIn.For$FieldClass")))) + ClassExpr(JAVA_PARSER + .parseClassOrInterfaceType("$Parcelling.BuiltIn.For$FieldClass") + .throwIfFailed()))) } } fieldAst.annotations.map { it.removeComment().toString() } @@ -143,8 +142,10 @@ data class FieldInfo( } val annotationsAndType by lazy { (annotationsNoInternal + Type).joinToString(" ") } val sParcelling by lazy { customParcellingClass?.let { "sParcellingFor$NameUpperCamel" } } + + val SetterParamType = if (isArray) "$FieldInnerType..." else Type val annotatedTypeForSetterParam by lazy { - (annotationsNoInternal + if (isArray) "$FieldInnerType..." else Type).joinToString(" ") + (annotationsNoInternal + SetterParamType).joinToString(" ") } // Utilities diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt index ab64f4efc8d8..c6e0a064f9b4 100644 --- a/tools/codegen/src/com/android/codegen/Generators.kt +++ b/tools/codegen/src/com/android/codegen/Generators.kt @@ -1,6 +1,7 @@ package com.android.codegen import com.github.javaparser.ast.body.FieldDeclaration +import com.github.javaparser.ast.body.MethodDeclaration import com.github.javaparser.ast.body.VariableDeclarator import com.github.javaparser.ast.expr.* import java.io.File @@ -16,7 +17,7 @@ fun ClassPrinter.generateConstDefs() { val isLiteral = initializer is LiteralExpr || (initializer is UnaryExpr && initializer.expression is LiteralExpr) isLiteral && variable.type.asString() in listOf("int", "String") - } + } && it.annotations.none { it.nameAsString == DataClassSuppressConstDefs } }.flatMap { field -> field.variables.map { it to field } } val intConsts = consts.filter { it.first.type.asString() == "int" } val strConsts = consts.filter { it.first.type.asString() == "String" } @@ -131,7 +132,7 @@ fun ClassPrinter.generateAidl(javaFile: File) { fun ClassPrinter.generateWithers() { fields.forEachApply { val metodName = "with$NameUpperCamel" - if (!hasMethod(metodName, Type)) { + if (!isMethodGenerationSuppressed(metodName, Type)) { generateFieldJavadoc(forceHide = FeatureFlag.WITHERS.hidden) """@$NonNull $GENERATED_MEMBER_HEADER @@ -171,7 +172,7 @@ fun ClassPrinter.generateCopyConstructor() { * ``` */ fun ClassPrinter.generateBuildUpon() { - if (hasMethod("buildUpon")) return + if (isMethodGenerationSuppressed("buildUpon")) return +"/**" +" * Provides an instance of {@link $BuilderClass} with state corresponding to this instance." @@ -195,7 +196,15 @@ fun ClassPrinter.generateBuilder() { val constructorVisibility = if (BuilderClass == CANONICAL_BUILDER_CLASS) "public" else "/* package-*/" - val OneTimeUseBuilder = classRef("android.provider.OneTimeUseBuilder") + val providedSubclassAst = nestedClasses.find { + it.extendedTypes.any { it.nameAsString == BASE_BUILDER_CLASS } + } + + val BuilderSupertype = if (customBaseBuilderAst != null) { + customBaseBuilderAst!!.nameAsString + } else { + "Object" + } +"/**" +" * A builder for {@link $ClassName}" @@ -203,104 +212,155 @@ fun ClassPrinter.generateBuilder() { +" */" +"@SuppressWarnings(\"WeakerAccess\")" +GENERATED_MEMBER_HEADER - "public static class $BuilderClass$genericArgs" { - +"extends $OneTimeUseBuilder<$ClassType>" + !"public static class $BuilderClass$genericArgs" + if (BuilderSupertype != "Object") { + appendSameLine(" extends $BuilderSupertype") } " {" { +"" fields.forEachApply { - +"protected $annotationsAndType $name;" + +"private $annotationsAndType $name;" } +"" - +"protected long mBuilderFieldsSet = 0L;" - +"" - +"$constructorVisibility $BuilderClass() {};" + +"private long mBuilderFieldsSet = 0L;" +"" + val requiredFields = fields.filter { !it.hasDefault } + + generateConstructorJavadoc( + fields = requiredFields, + ClassName = BuilderClass, + hidden = false) + "$constructorVisibility $BuilderClass(" { + requiredFields.forEachLastAware { field, isLast -> + +"${field.annotationsAndType} ${field._name}${if_(!isLast, ",")}" + } + }; " {" { + requiredFields.forEachApply { + generateSetFrom(_name) + } + } + generateBuilderSetters(setterVisibility) generateBuilderBuild() + "private void checkNotUsed() {" { + "if ((mBuilderFieldsSet & ${bitAtExpr(fields.size)}) != 0)" { + "throw new IllegalStateException(" { + +"\"This Builder should not be reused. Use a new Builder instance instead\"" + } + +";" + } + } + rmEmptyLine() } } +private fun ClassPrinter.generateBuilderMethod( + defVisibility: String, + name: String, + ParamAnnotations: String? = null, + paramTypes: List<String>, + paramNames: List<String> = listOf("value"), + genJavadoc: ClassPrinter.() -> Unit, + genBody: ClassPrinter.() -> Unit) { + + val providedMethod = customBaseBuilderAst?.members?.find { + it is MethodDeclaration + && it.nameAsString == name + && it.parameters.map { it.typeAsString } == paramTypes.toTypedArray().toList() + } as? MethodDeclaration + + if ((providedMethod == null || providedMethod.isAbstract) + && name !in builderSuppressedMembers) { + val visibility = providedMethod?.visibility?.asString() ?: defVisibility + val ReturnType = providedMethod?.typeAsString ?: CANONICAL_BUILDER_CLASS + val Annotations = providedMethod?.annotations?.joinToString("\n") + + genJavadoc() + +GENERATED_MEMBER_HEADER + if (providedMethod?.isAbstract == true) +"@Override" + if (!Annotations.isNullOrEmpty()) +Annotations + "$visibility @$NonNull $ReturnType $name(${if_(!ParamAnnotations.isNullOrEmpty(), "$ParamAnnotations ")}${ + paramTypes.zip(paramNames).joinToString(", ") { (Type, paramName) -> "$Type $paramName" } + })" { + genBody() + } + } +} + private fun ClassPrinter.generateBuilderSetters(visibility: String) { fields.forEachApply { val maybeCast = if_(BuilderClass != CANONICAL_BUILDER_CLASS, " ($CANONICAL_BUILDER_CLASS)") - generateFieldJavadoc() - +GENERATED_MEMBER_HEADER - "$visibility $CANONICAL_BUILDER_CLASS set$NameUpperCamel($annotatedTypeForSetterParam value)" { + val setterName = "set$NameUpperCamel" + + generateBuilderMethod( + name = setterName, + defVisibility = visibility, + ParamAnnotations = annotationsNoInternal.joinToString(" "), + paramTypes = listOf(SetterParamType), + genJavadoc = { generateFieldJavadoc() }) { +"checkNotUsed();" +"mBuilderFieldsSet |= $fieldBit;" +"$name = value;" +"return$maybeCast this;" } + val javadocSeeSetter = "/** @see #$setterName */" + val adderName = "add$SingularName" - val javadocSeeSetter = "/** @see #set$NameUpperCamel */" val singularNameCustomizationHint = if (SingularNameOrNull == null) { "// You can refine this method's name by providing item's singular name, e.g.:\n" + "// @DataClass.PluralOf(\"item\")) mItems = ...\n\n" } else "" + if (isList && FieldInnerType != null) { + generateBuilderMethod( + name = adderName, + defVisibility = visibility, + paramTypes = listOf(FieldInnerType), + genJavadoc = { +javadocSeeSetter }) { - +javadocSeeSetter - +GENERATED_MEMBER_HEADER - "$visibility $CANONICAL_BUILDER_CLASS add$SingularName(@$NonNull $FieldInnerType value)" { !singularNameCustomizationHint - +"if ($name == null) set$NameUpperCamel(new $ArrayList<>());" + +"if ($name == null) $setterName(new $ArrayList<>());" +"$name.add(value);" +"return$maybeCast this;" } } if (Type.contains("Map<")) { - val (Key, Value) = fieldTypeGenegicArgs - - +javadocSeeSetter - +GENERATED_MEMBER_HEADER - "$visibility $CANONICAL_BUILDER_CLASS add$SingularName($Key key, $Value value)" { + generateBuilderMethod( + name = adderName, + defVisibility = visibility, + paramTypes = fieldTypeGenegicArgs, + paramNames = listOf("key", "value"), + genJavadoc = { +javadocSeeSetter }) { !singularNameCustomizationHint - +"if ($name == null) set$NameUpperCamel(new $LinkedHashMap());" + +"if ($name == null) $setterName(new $LinkedHashMap());" +"$name.put(key, value);" +"return$maybeCast this;" } } - - if (Type == "boolean") { - +javadocSeeSetter - +GENERATED_MEMBER_HEADER - "$visibility $CANONICAL_BUILDER_CLASS mark$NameUpperCamel()" { - +"return set$NameUpperCamel(true);" - } - - +javadocSeeSetter - +GENERATED_MEMBER_HEADER - "$visibility $CANONICAL_BUILDER_CLASS markNot$NameUpperCamel()" { - +"return set$NameUpperCamel(false);" - } - } } } private fun ClassPrinter.generateBuilderBuild() { +"/** Builds the instance. This builder should not be touched after calling this! */" "public $ClassType build()" { - +"markUsed();" + +"checkNotUsed();" + +"mBuilderFieldsSet |= ${bitAtExpr(fields.size)}; // Mark builder used" + +"" fields.forEachApply { - if (!isNullable || hasDefault) { + if (hasDefault) { "if ((mBuilderFieldsSet & $fieldBit) == 0)" { - if (!isNullable && !hasDefault) { - +"throw new IllegalStateException(\"Required field not set: $nameLowerCamel\");" - } else { - +"$name = $defaultExpr;" - } + +"$name = $defaultExpr;" } } } @@ -348,7 +408,7 @@ fun ClassPrinter.generateParcelable() { } val Parcel = classRef("android.os.Parcel") - if (!hasMethod("writeToParcel", Parcel, "int")) { + if (!isMethodGenerationSuppressed("writeToParcel", Parcel, "int")) { +"@Override" +GENERATED_MEMBER_HEADER "public void writeToParcel($Parcel dest, int flags)" { @@ -390,7 +450,7 @@ fun ClassPrinter.generateParcelable() { } } - if (!hasMethod("describeContents")) { + if (!isMethodGenerationSuppressed("describeContents")) { +"@Override" +GENERATED_MEMBER_HEADER +"public int describeContents() { return 0; }" @@ -442,8 +502,6 @@ fun ClassPrinter.generateParcelable() { FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()" FieldClass == "List" || FieldClass == "ArrayList" -> "new ${classRef("java.util.ArrayList")}<>()" -// isArray && FieldInnerType in (PRIMITIVE_TYPES + "String") -> -// "new $FieldInnerType[in.readInt()]" else -> "" } val passContainer = containerInitExpr.isNotEmpty() @@ -519,7 +577,7 @@ fun ClassPrinter.generateParcelable() { } fun ClassPrinter.generateEqualsHashcode() { - if (!hasMethod("equals", "Object")) { + if (!isMethodGenerationSuppressed("equals", "Object")) { +"@Override" +GENERATED_MEMBER_HEADER "public boolean equals(Object o)" { @@ -546,7 +604,7 @@ fun ClassPrinter.generateEqualsHashcode() { } } - if (!hasMethod("hashCode")) { + if (!isMethodGenerationSuppressed("hashCode")) { +"@Override" +GENERATED_MEMBER_HEADER "public int hashCode()" { @@ -572,7 +630,7 @@ fun ClassPrinter.generateEqualsHashcode() { //TODO support IntDef flags? fun ClassPrinter.generateToString() { - if (!hasMethod("toString")) { + if (!isMethodGenerationSuppressed("toString")) { +"@Override" +GENERATED_MEMBER_HEADER "public String toString()" { @@ -599,7 +657,7 @@ fun ClassPrinter.generateToString() { fun ClassPrinter.generateSetters() { fields.forEachApply { - if (!hasMethod("set$NameUpperCamel", Type) + if (!isMethodGenerationSuppressed("set$NameUpperCamel", Type) && !fieldAst.isPublic && !isFinal) { @@ -618,7 +676,7 @@ fun ClassPrinter.generateGetters() { val methodPrefix = if (Type == "boolean") "is" else "get" val methodName = methodPrefix + NameUpperCamel - if (!hasMethod(methodName) && !fieldAst.isPublic) { + if (!isMethodGenerationSuppressed(methodName) && !fieldAst.isPublic) { generateFieldJavadoc(forceHide = FeatureFlag.GETTERS.hidden) +GENERATED_MEMBER_HEADER @@ -662,23 +720,8 @@ fun FieldInfo.generateFieldJavadoc(forceHide: Boolean = false) = classPrinter { } fun FieldInfo.generateSetFrom(source: String) = classPrinter { - !"$name = " - if (Type in PRIMITIVE_TYPES || mayBeNull) { - +"$source;" - } else if (defaultExpr != null) { - "$source != null" { - +"? $source" - +": $defaultExpr;" - } - } else { - val checkNotNull = memberRef("com.android.internal.util.Preconditions.checkNotNull") - +"$checkNotNull($source);" - } - if (isNonEmpty) { - "if ($isEmptyExpr)" { - +"throw new IllegalArgumentException(\"$nameLowerCamel cannot be empty\");" - } - } + +"$name = $source;" + generateFieldValidation(field = this@generateSetFrom) } fun ClassPrinter.generateConstructor(visibility: String = "public") { @@ -697,15 +740,18 @@ fun ClassPrinter.generateConstructor(visibility: String = "public") { generateSetFrom(nameLowerCamel) } - generateStateValidation() - generateOnConstructedCallback() } } -private fun ClassPrinter.generateConstructorJavadoc() { +private fun ClassPrinter.generateConstructorJavadoc( + fields: List<FieldInfo> = this.fields, + ClassName: String = this.ClassName, + hidden: Boolean = FeatureFlag.CONSTRUCTOR.hidden) { if (fields.all { it.javadoc == null } && !FeatureFlag.CONSTRUCTOR.hidden) return +"/**" + +" * Creates a new $ClassName." + +" *" fields.filter { it.javadoc != null }.forEachApply { javadocTextNoAnnotationLines?.apply { +" * @param $nameLowerCamel" @@ -718,87 +764,97 @@ private fun ClassPrinter.generateConstructorJavadoc() { +" */" } -private fun ClassPrinter.generateStateValidation() { - val Size = classRef("android.annotation.Size") - val knownNonValidationAnnotations = internalAnnotations + Nullable - - val validate = memberRef("com.android.internal.util.AnnotationValidations.validate") - fun appendValidateCall(annotation: AnnotationExpr, valueToValidate: String) { - "$validate(" { - !"${annotation.nameAsString}.class, null, $valueToValidate" - val params = when (annotation) { - is MarkerAnnotationExpr -> emptyMap() - is SingleMemberAnnotationExpr -> mapOf("value" to annotation.memberValue) - is NormalAnnotationExpr -> - annotation.pairs.map { it.name.asString() to it.value }.toMap() - else -> throw IllegalStateException() - } - params.forEach { name, value -> - !",\n\"$name\", $value" +private fun ClassPrinter.appendLinesWithContinuationIndent(text: String) { + val lines = text.lines() + if (lines.isNotEmpty()) { + !lines[0] + } + if (lines.size >= 2) { + "" { + lines.drop(1).forEach { + +it } } - +";" } +} - fields.forEachApply { - if (intOrStringDef != null) { - if (intOrStringDef!!.type == ConstDef.Type.INT_FLAGS) { - +"" - +"//noinspection PointlessBitwiseExpression" - "$Preconditions.checkFlagsArgument(" { - "$name, 0" { - intOrStringDef!!.CONST_NAMES.forEach { - +"| $it" +private fun ClassPrinter.generateFieldValidation(field: FieldInfo) = field.run { + if (isNonEmpty) { + "if ($isEmptyExpr)" { + +"throw new IllegalArgumentException(\"$nameLowerCamel cannot be empty\");" + } + } + if (intOrStringDef != null) { + if (intOrStringDef!!.type == ConstDef.Type.INT_FLAGS) { + +"" + "$Preconditions.checkFlagsArgument(" { + +"$name, " + appendLinesWithContinuationIndent(intOrStringDef!!.CONST_NAMES.joinToString("\n| ")) + } + +";" + } else { + +"" + !"if (" + appendLinesWithContinuationIndent(intOrStringDef!!.CONST_NAMES.joinToString("\n&& ") { + "!(${isEqualToExpr(it)})" + }) + rmEmptyLine(); ") {" { + "throw new ${classRef<IllegalArgumentException>()}(" { + "\"$nameLowerCamel was \" + $internalGetter + \" but must be one of: \"" { + + intOrStringDef!!.CONST_NAMES.forEachLastAware { CONST_NAME, isLast -> + +"""+ "$CONST_NAME(" + $CONST_NAME + ")${if_(!isLast, ", ")}"""" } } } +";" - } else { - +"" - +"//noinspection PointlessBooleanExpression" - "if (true" { - intOrStringDef!!.CONST_NAMES.forEach { CONST_NAME -> - +"&& !(${isEqualToExpr(CONST_NAME)})" - } - }; rmEmptyLine(); ") {" { - "throw new ${classRef<IllegalArgumentException>()}(" { - "\"$nameLowerCamel was \" + $internalGetter + \" but must be one of: \"" { - - intOrStringDef!!.CONST_NAMES.forEachLastAware { CONST_NAME, isLast -> - +"""+ "$CONST_NAME(" + $CONST_NAME + ")${if_(!isLast, ", ")}"""" - } - } - } - +";" - } } } + } - val eachLine = fieldAst.annotations.find { it.nameAsString == Each }?.range?.orElse(null)?.end?.line - val perElementValidations = if (eachLine == null) emptyList() else fieldAst.annotations.filter { - it.nameAsString != Each && + val eachLine = fieldAst.annotations.find { it.nameAsString == Each }?.range?.orElse(null)?.end?.line + val perElementValidations = if (eachLine == null) emptyList() else fieldAst.annotations.filter { + it.nameAsString != Each && it.range.orElse(null)?.begin?.line?.let { it >= eachLine } ?: false - } + } - fieldAst.annotations.filterNot { - it.nameAsString == intOrStringDef?.AnnotationName - || it.nameAsString in knownNonValidationAnnotations - || it in perElementValidations - }.forEach { annotation -> - appendValidateCall(annotation, - valueToValidate = if (annotation.nameAsString == Size) sizeExpr else name) + val Size = classRef("android.annotation.Size") + fieldAst.annotations.filterNot { + it.nameAsString == intOrStringDef?.AnnotationName + || it.nameAsString in knownNonValidationAnnotations + || it in perElementValidations + }.forEach { annotation -> + appendValidateCall(annotation, + valueToValidate = if (annotation.nameAsString == Size) sizeExpr else name) + } + + if (perElementValidations.isNotEmpty()) { + +"int ${nameLowerCamel}Size = $sizeExpr;" + "for (int i = 0; i < ${nameLowerCamel}Size; i++) {" { + perElementValidations.forEach { annotation -> + appendValidateCall(annotation, + valueToValidate = elemAtIndexExpr("i")) + } } + } +} - if (perElementValidations.isNotEmpty()) { - +"int ${nameLowerCamel}Size = $sizeExpr;" - "for (int i = 0; i < ${nameLowerCamel}Size; i++) {" { - perElementValidations.forEach { annotation -> - appendValidateCall(annotation, - valueToValidate = elemAtIndexExpr("i")) - } - } +fun ClassPrinter.appendValidateCall(annotation: AnnotationExpr, valueToValidate: String) { + val validate = memberRef("com.android.internal.util.AnnotationValidations.validate") + "$validate(" { + !"${annotation.nameAsString}.class, null, $valueToValidate" + val params = when (annotation) { + is MarkerAnnotationExpr -> emptyMap() + is SingleMemberAnnotationExpr -> mapOf("value" to annotation.memberValue) + is NormalAnnotationExpr -> + annotation.pairs.map { it.name.asString() to it.value }.toMap() + else -> throw IllegalStateException() + } + params.forEach { name, value -> + !",\n\"$name\", $value" } } + +";" } private fun ClassPrinter.generateOnConstructedCallback(prefix: String = "") { @@ -845,3 +901,15 @@ fun ClassPrinter.generateForEachField() { } } } + +fun ClassPrinter.generateMetadata(file: File) { + "@$DataClassGenerated(" { + +"time = ${System.currentTimeMillis()}L," + +"codegenVersion = \"$CODEGEN_VERSION\"," + +"sourceFile = \"${file.relativeTo(File(System.getenv("ANDROID_BUILD_TOP")))}\"," + +"inputSignatures = \"${getInputSignatures().joinToString("\\n")}\"" + } + +"" + +"@Deprecated" + +"private void __metadata() {}\n" +}
\ No newline at end of file diff --git a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt index d1dc88f4a773..1b514d7a74a0 100644 --- a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt +++ b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt @@ -1,6 +1,6 @@ package com.android.codegen -import com.github.javaparser.ast.body.TypeDeclaration +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration import com.github.javaparser.ast.expr.* import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations import com.github.javaparser.ast.type.ClassOrInterfaceType @@ -8,9 +8,17 @@ import com.github.javaparser.ast.type.Type fun ClassPrinter.getInputSignatures(): List<String> { + return generateInputSignaturesForClass(classAst) + + annotationToString(classAst.annotations.find { it.nameAsString == DataClass }) + + generateInputSignaturesForClass(customBaseBuilderAst) +} + +private fun ClassPrinter.generateInputSignaturesForClass(classAst: ClassOrInterfaceDeclaration?): List<String> { + if (classAst == null) return emptyList() + return classAst.fields.map { fieldAst -> buildString { - append(fieldAst.modifiers.joinToString(" ") {it.asString()}) + append(fieldAst.modifiers.joinToString(" ") { it.keyword.asString() }) append(" ") append(annotationsToString(fieldAst)) append(" ") @@ -20,7 +28,7 @@ fun ClassPrinter.getInputSignatures(): List<String> { } } + classAst.methods.map { methodAst -> buildString { - append(methodAst.modifiers.joinToString(" ") {it.asString()}) + append(methodAst.modifiers.joinToString(" ") { it.keyword.asString() }) append(" ") append(annotationsToString(methodAst)) append(" ") @@ -28,19 +36,26 @@ fun ClassPrinter.getInputSignatures(): List<String> { append(" ") append(methodAst.nameAsString) append("(") - append(methodAst.parameters.joinToString(",") {getFullClassName(it.type)}) + append(methodAst.parameters.joinToString(",") { getFullClassName(it.type) }) append(")") } - } + } + ("class ${classAst.nameAsString}" + + " extends ${classAst.extendedTypes.map { getFullClassName(it) }.ifEmpty { listOf("java.lang.Object") }.joinToString(", ")}" + + " implements [${classAst.implementedTypes.joinToString(", ") { getFullClassName(it) }}]") } private fun ClassPrinter.annotationsToString(annotatedAst: NodeWithAnnotations<*>): String { - return annotatedAst.annotations.joinToString(" ") { - annotationToString(it) - } + return annotatedAst + .annotations + .groupBy { it.nameAsString } // dedupe annotations by name (javaparser bug?) + .values + .joinToString(" ") { + annotationToString(it[0]) + } } -private fun ClassPrinter.annotationToString(ann: AnnotationExpr): String { +private fun ClassPrinter.annotationToString(ann: AnnotationExpr?): String { + if (ann == null) return "" return buildString { append("@") append(getFullClassName(ann.nameAsString)) @@ -78,9 +93,9 @@ private fun ClassPrinter.appendExpr(sb: StringBuilder, ex: Expression?) { private fun ClassPrinter.getFullClassName(type: Type): String { return if (type is ClassOrInterfaceType) { + getFullClassName(buildString { type.scope.ifPresent { append(it).append(".") } - type.isArrayType append(type.nameAsString) }) + (type.typeArguments.orElse(null)?.let { args -> args.joinToString(", ") {getFullClassName(it)}}?.let { "<$it>" } ?: "") } else getFullClassName(type.asString()) @@ -100,10 +115,16 @@ private fun ClassPrinter.getFullClassName(className: String): String { val thisPackagePrefix = fileAst.packageDeclaration.map { it.nameAsString + "." }.orElse("") val thisClassPrefix = thisPackagePrefix + classAst.nameAsString + "." - classAst.childNodes.filterIsInstance<TypeDeclaration<*>>().find { + if (classAst.nameAsString == className) return thisPackagePrefix + classAst.nameAsString + + nestedClasses.find { it.nameAsString == className }?.let { return thisClassPrefix + it.nameAsString } + if (className == CANONICAL_BUILDER_CLASS || className == BASE_BUILDER_CLASS) { + return thisClassPrefix + className + } + constDefs.find { it.AnnotationName == className }?.let { return thisClassPrefix + className } if (tryOrNull { Class.forName("java.lang.$className") } != null) { diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt index 8fafa7ce9b1e..0f932f3c34e1 100755 --- a/tools/codegen/src/com/android/codegen/Main.kt +++ b/tools/codegen/src/com/android/codegen/Main.kt @@ -1,5 +1,6 @@ package com.android.codegen +import com.github.javaparser.JavaParser import java.io.File @@ -9,14 +10,12 @@ const val INDENT_SINGLE = " " val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean") -const val CANONICAL_BUILDER_CLASS = "Builder" -const val GENERATED_BUILDER_CLASS = "GeneratedBuilder" - val BUILTIN_SPECIAL_PARCELLINGS = listOf("Pattern") const val FLAG_BUILDER_PROTECTED_SETTERS = "--builder-protected-setters" const val FLAG_NO_FULL_QUALIFIERS = "--no-full-qualifiers" +val JAVA_PARSER = JavaParser() /** @see [FeatureFlag] */ val USAGE = """ @@ -66,10 +65,10 @@ Special methods/etc. you can define: Will be called in constructor, after all the fields have been initialized. This is a good place to put any custom validation logic that you may have - static class $CANONICAL_BUILDER_CLASS extends $GENERATED_BUILDER_CLASS - If a class extending $GENERATED_BUILDER_CLASS is specified, generated builder's setters will + static class $CANONICAL_BUILDER_CLASS extends $BASE_BUILDER_CLASS + If a class extending $BASE_BUILDER_CLASS is specified, generated builder's setters will return the provided $CANONICAL_BUILDER_CLASS type. - $GENERATED_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead + $BASE_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead This allows you to extend the generated builder, adding or overriding any methods you may want @@ -131,7 +130,6 @@ fun main(args: Array<String>) { // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION. - // on ${currentTimestamp()} // // DO NOT MODIFY! // @@ -143,14 +141,6 @@ fun main(args: Array<String>) { if (FeatureFlag.CONST_DEFS()) generateConstDefs() - "@$DataClassGenerated(" { - +"time = ${System.currentTimeMillis()}L," - +"codegenVersion = \"$CODEGEN_VERSION\"," - +"sourceFile = \"${file.relativeTo(File(System.getenv("ANDROID_BUILD_TOP")))}\"," - +"inputSignatures = \"${getInputSignatures().joinToString("\\n")}\"" - } - +"\n" - if (FeatureFlag.CONSTRUCTOR()) { generateConstructor("public") @@ -160,6 +150,7 @@ fun main(args: Array<String>) { || FeatureFlag.PARCELABLE()) { generateConstructor("/* package-private */") } + if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor() if (FeatureFlag.GETTERS()) generateGetters() if (FeatureFlag.SETTERS()) generateSetters() @@ -168,7 +159,6 @@ fun main(args: Array<String>) { if (FeatureFlag.FOR_EACH_FIELD()) generateForEachField() - if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor() if (FeatureFlag.WITHERS()) generateWithers() if (FeatureFlag.PARCELABLE()) generateParcelable() @@ -178,6 +168,8 @@ fun main(args: Array<String>) { if (FeatureFlag.AIDL()) generateAidl(file) + generateMetadata(file) + rmEmptyLine() } stringBuilder.append("\n}\n") diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 175eea6ef0d0..7d50ad10de00 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,4 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.0"
\ No newline at end of file +const val CODEGEN_VERSION = "1.0.0" + +const val CANONICAL_BUILDER_CLASS = "Builder" +const val BASE_BUILDER_CLASS = "BaseBuilder" diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt index 95c99092e2ab..a1f068afa29a 100644 --- a/tools/codegen/src/com/android/codegen/Utils.kt +++ b/tools/codegen/src/com/android/codegen/Utils.kt @@ -1,8 +1,10 @@ package com.android.codegen +import com.github.javaparser.ast.Modifier import com.github.javaparser.ast.expr.AnnotationExpr import com.github.javaparser.ast.expr.Expression import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr +import com.github.javaparser.ast.nodeTypes.NodeWithModifiers import java.time.Instant import java.time.ZoneId import java.time.format.DateTimeFormatter @@ -22,6 +24,8 @@ fun Char.isWhitespaceNonNewline() = isWhitespace() && !isNewline() fun if_(cond: Boolean, then: String) = if (cond) then else "" +fun <T> Any?.as_(): T = this as T + inline infix fun Int.times(action: () -> Unit) { for (i in 1..this) action() } @@ -73,4 +77,14 @@ inline operator fun <reified T> Array<T>.minus(item: T) = toList().minus(item).t fun currentTimestamp() = DateTimeFormatter .ofLocalizedDateTime(/* date */ FormatStyle.MEDIUM, /* time */ FormatStyle.LONG) .withZone(ZoneId.systemDefault()) - .format(Instant.now())
\ No newline at end of file + .format(Instant.now()) + +val NodeWithModifiers<*>.visibility get() = accessSpecifier + +fun abort(msg: String): Nothing { + System.err.println("ERROR: $msg") + System.exit(1) + throw InternalError() // can't get here +} + +fun bitAtExpr(bitIndex: Int) = "0x${java.lang.Long.toHexString(1L shl bitIndex)}" diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp index 2488341bfd97..87b31d22af32 100644 --- a/tools/preload-check/Android.bp +++ b/tools/preload-check/Android.bp @@ -19,4 +19,5 @@ java_test_host { libs: ["tradefed"], test_suites: ["general-tests"], required: ["preload-check-device"], + data: [":preload-check-device"], } diff --git a/tools/preload-check/device/Android.bp b/tools/preload-check/device/Android.bp index 7782b0d378ae..f40d8ba5a287 100644 --- a/tools/preload-check/device/Android.bp +++ b/tools/preload-check/device/Android.bp @@ -20,7 +20,6 @@ java_test_helper_library { sdk_version: "current", srcs: ["src/**/*.java"], - test_suites: ["general-tests"], dex_preopt: { enabled: false, }, diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt index e5ec17a1d18d..26b15aecbe33 100644 --- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt +++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt @@ -17,6 +17,8 @@ package android.processor.staledataclass +import com.android.codegen.BASE_BUILDER_CLASS +import com.android.codegen.CANONICAL_BUILDER_CLASS import com.android.codegen.CODEGEN_NAME import com.android.codegen.CODEGEN_VERSION import com.sun.tools.javac.code.Symbol @@ -29,6 +31,7 @@ import javax.annotation.processing.SupportedAnnotationTypes import javax.lang.model.SourceVersion import javax.lang.model.element.AnnotationMirror import javax.lang.model.element.Element +import javax.lang.model.element.ElementKind import javax.lang.model.element.TypeElement import javax.tools.Diagnostic @@ -107,20 +110,30 @@ class StaleDataclassProcessor: AbstractProcessor() { private fun processSingleFile(elementAnnotatedWithGenerated: Element) { - val inputSignatures = elementAnnotatedWithGenerated - .enclosingElement - .enclosedElements - .filterNot { - it.annotationMirrors.any { "Generated" in it.annotationType.toString() } - }.map { - elemToString(it) - }.toSet() + val classElement = elementAnnotatedWithGenerated.enclosingElement + + val inputSignatures = computeSignaturesForClass(classElement) + .plus(computeSignaturesForClass(classElement.enclosedElements.find { + it.kind == ElementKind.CLASS + && !isGenerated(it) + && it.simpleName.toString() == BASE_BUILDER_CLASS + })) + .plus(computeSignaturesForClass(classElement.enclosedElements.find { + it.kind == ElementKind.CLASS + && !isGenerated(it) + && it.simpleName.toString() == CANONICAL_BUILDER_CLASS + })) + .plus(classElement + .annotationMirrors + .find { it.annotationType.toString() == DATACLASS_ANNOTATION_NAME } + .toString()) + .toSet() val annotationParams = elementAnnotatedWithGenerated .annotationMirrors .find { ann -> isGeneratedAnnotation(ann) }!! .elementValues - .map { (k, v) -> k.getSimpleName().toString() to v.getValue() } + .map { (k, v) -> k.simpleName.toString() to v.value } .toMap() val lastGenerated = annotationParams["time"] as Long @@ -140,7 +153,7 @@ class StaleDataclassProcessor: AbstractProcessor() { } val source = repoRoot!!.resolve(sourceRelative) - val clazz = elementAnnotatedWithGenerated.enclosingElement.toString() + val clazz = classElement.toString() if (inputSignatures != lastGenInputSignatures) { error(buildString { @@ -157,6 +170,23 @@ class StaleDataclassProcessor: AbstractProcessor() { } } + private fun computeSignaturesForClass(classElement: Element?): List<String> { + if (classElement == null) return emptyList() + val type = classElement as TypeElement + return classElement + .enclosedElements + .filterNot { + it.kind == ElementKind.CLASS + || it.kind == ElementKind.CONSTRUCTOR + || isGenerated(it) + }.map { + elemToString(it) + } + "class ${classElement.simpleName} extends ${type.superclass} implements [${type.interfaces.joinToString(", ")}]" + } + + private fun isGenerated(it: Element) = + it.annotationMirrors.any { "Generated" in it.annotationType.toString() } + private fun error(msg: String) { processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, msg) } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 1829baac4c58..931e5dd7405f 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -205,6 +205,8 @@ interface IWifiManager int removeNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName); + List<WifiNetworkSuggestion> getNetworkSuggestions(in String packageName); + String[] getFactoryMacAddresses(); void setDeviceMobilityState(int state); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 2f7400d001aa..20d772c8fb11 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1722,6 +1722,21 @@ public class WifiManager { } /** + * Get all network suggestions provided by the calling app. + * See {@link #addNetworkSuggestions(List)} + * See {@link #removeNetworkSuggestions(List)} + * @return a list of {@link WifiNetworkSuggestion} + */ + @RequiresPermission(ACCESS_WIFI_STATE) + public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() { + try { + return mService.getNetworkSuggestions(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** * Returns the max number of network suggestions that are allowed per app on the device. * @see #addNetworkSuggestions(List) * @see #removeNetworkSuggestions(List) diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index fcf8bd5eaa3e..bc06e7de8502 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -440,6 +440,11 @@ public class BaseWifiService extends IWifiManager.Stub { } @Override + public List<WifiNetworkSuggestion> getNetworkSuggestions(String packageName) { + throw new UnsupportedOperationException(); + } + + @Override public String[] getFactoryMacAddresses() { throw new UnsupportedOperationException(); } diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh index 219a45ee188f..7a0dfb08fcfe 100755 --- a/wifi/tests/runtests.sh +++ b/wifi/tests/runtests.sh @@ -12,7 +12,7 @@ set -e # fail early echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests" # NOTE Don't actually run the command above since this shell doesn't inherit functions from the # caller. -make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests +$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode MODULES-IN-frameworks-base-wifi-tests set -x # print commands diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index b75a1acf87c9..e478f3830c0a 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -1313,20 +1313,27 @@ i * Verify that a call to cancel WPS immediately returns a failure. } /** - * Verify calls to {@link WifiManager#addNetworkSuggestions(List)} and + * Verify calls to {@link WifiManager#addNetworkSuggestions(List)}, + * {@link WifiManager#getNetworkSuggestions()} and * {@link WifiManager#removeNetworkSuggestions(List)}. */ @Test - public void addRemoveNetworkSuggestions() throws Exception { + public void addGetRemoveNetworkSuggestions() throws Exception { + List<WifiNetworkSuggestion> testList = new ArrayList<>(); when(mWifiService.addNetworkSuggestions(any(List.class), anyString())) .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS); when(mWifiService.removeNetworkSuggestions(any(List.class), anyString())) .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS); + when(mWifiService.getNetworkSuggestions(anyString())) + .thenReturn(testList); assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, - mWifiManager.addNetworkSuggestions(new ArrayList<>())); + mWifiManager.addNetworkSuggestions(testList)); verify(mWifiService).addNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME)); + assertEquals(testList, mWifiManager.getNetworkSuggestions()); + verify(mWifiService).getNetworkSuggestions(eq(TEST_PACKAGE_NAME)); + assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, mWifiManager.removeNetworkSuggestions(new ArrayList<>())); verify(mWifiService).removeNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME)); |