Merge "Fixes the flicker when transfer splash screen view to client"
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index acc661e..1429c45 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -235,6 +235,14 @@
public static final int STOP_REASON_USER = 13;
/** The system is doing some processing that requires stopping this job. */
public static final int STOP_REASON_SYSTEM_PROCESSING = 14;
+ /**
+ * The system's estimate of when the app will be launched changed significantly enough to
+ * decide this job shouldn't be running right now. This will mostly apply to prefetch jobs.
+ *
+ * @see JobInfo#isPrefetch()
+ * @see JobInfo.Builder#setPrefetch(boolean)
+ */
+ public static final int STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED = 15;
/** @hide */
@IntDef(prefix = {"STOP_REASON_"}, value = {
@@ -253,6 +261,7 @@
STOP_REASON_APP_STANDBY,
STOP_REASON_USER,
STOP_REASON_SYSTEM_PROCESSING,
+ STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StopReason {
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 9c4cada..a23f6e1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.annotation.NonNull;
@@ -105,6 +106,7 @@
import com.android.server.job.controllers.DeviceIdleJobsController;
import com.android.server.job.controllers.IdleController;
import com.android.server.job.controllers.JobStatus;
+import com.android.server.job.controllers.PrefetchController;
import com.android.server.job.controllers.QuotaController;
import com.android.server.job.controllers.RestrictingController;
import com.android.server.job.controllers.StateController;
@@ -252,6 +254,8 @@
private final StorageController mStorageController;
/** Need directly for sending uid state changes */
private final DeviceIdleJobsController mDeviceIdleJobsController;
+ /** Needed to get next estimated launch time. */
+ private final PrefetchController mPrefetchController;
/** Needed to get remaining quota time. */
private final QuotaController mQuotaController;
/** Needed to get max execution time and expedited-job allowance. */
@@ -427,6 +431,9 @@
case Constants.KEY_CONN_PREFETCH_RELAX_FRAC:
mConstants.updateConnectivityConstantsLocked();
break;
+ case Constants.KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS:
+ mConstants.updatePrefetchConstantsLocked();
+ break;
case Constants.KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS:
case Constants.KEY_RUNTIME_MIN_GUARANTEE_MS:
case Constants.KEY_RUNTIME_MIN_EJ_GUARANTEE_MS:
@@ -482,6 +489,8 @@
private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
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_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS =
+ "prefetch_force_batch_relax_threshold_ms";
private static final String KEY_ENABLE_API_QUOTAS = "enable_api_quotas";
private static final String KEY_API_QUOTA_SCHEDULE_COUNT = "aq_schedule_count";
private static final String KEY_API_QUOTA_SCHEDULE_WINDOW_MS = "aq_schedule_window_ms";
@@ -503,6 +512,7 @@
private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
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 long DEFAULT_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS = HOUR_IN_MILLIS;
private static final boolean DEFAULT_ENABLE_API_QUOTAS = true;
private static final int DEFAULT_API_QUOTA_SCHEDULE_COUNT = 250;
private static final long DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS = MINUTE_IN_MILLIS;
@@ -557,6 +567,14 @@
public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC;
/**
+ * The amount of time within which we would consider the app to be launching relatively soon
+ * and will relax the force batching policy on prefetch jobs. If the app is not going to be
+ * launched within this amount of time from now, then we will force batch the prefetch job.
+ */
+ public long PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS =
+ DEFAULT_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS;
+
+ /**
* Whether to enable quota limits on APIs.
*/
public boolean ENABLE_API_QUOTAS = DEFAULT_ENABLE_API_QUOTAS;
@@ -635,6 +653,13 @@
DEFAULT_CONN_PREFETCH_RELAX_FRAC);
}
+ private void updatePrefetchConstantsLocked() {
+ PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS,
+ DEFAULT_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS);
+ }
+
private void updateApiQuotaConstantsLocked() {
ENABLE_API_QUOTAS = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_ENABLE_API_QUOTAS, DEFAULT_ENABLE_API_QUOTAS);
@@ -700,6 +725,8 @@
pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
+ pw.print(KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS,
+ PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS).println();
pw.print(KEY_ENABLE_API_QUOTAS, ENABLE_API_QUOTAS).println();
pw.print(KEY_API_QUOTA_SCHEDULE_COUNT, API_QUOTA_SCHEDULE_COUNT).println();
@@ -1577,6 +1604,8 @@
mControllers.add(new ContentObserverController(this));
mDeviceIdleJobsController = new DeviceIdleJobsController(this);
mControllers.add(mDeviceIdleJobsController);
+ mPrefetchController = new PrefetchController(this);
+ mControllers.add(mPrefetchController);
mQuotaController =
new QuotaController(this, backgroundJobsController, connectivityController);
mControllers.add(mQuotaController);
@@ -2333,6 +2362,15 @@
} else if (job.getEffectiveStandbyBucket() == RESTRICTED_INDEX) {
// Restricted jobs must always be batched
shouldForceBatchJob = true;
+ } else if (job.getJob().isPrefetch()) {
+ // Only relax batching on prefetch jobs if we expect the app to be launched
+ // relatively soon. PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS defines what
+ // "relatively soon" means.
+ final long relativelySoonCutoffTime = sSystemClock.millis()
+ + mConstants.PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS;
+ shouldForceBatchJob =
+ mPrefetchController.getNextEstimatedLaunchTimeLocked(job)
+ > relativelySoonCutoffTime;
} else if (job.getNumFailures() > 0) {
shouldForceBatchJob = false;
} else {
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 3801885..d35c03d 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
@@ -93,6 +93,7 @@
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint
+ static final int CONSTRAINT_PREFETCH = 1 << 23;
static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
// The following set of dynamic constraints are for specific use cases (as explained in their
@@ -147,6 +148,7 @@
private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
| CONSTRAINT_DEADLINE
| CONSTRAINT_IDLE
+ | CONSTRAINT_PREFETCH
| CONSTRAINT_TARE_WEALTH
| CONSTRAINT_TIMING_DELAY
| CONSTRAINT_WITHIN_QUOTA;
@@ -1176,6 +1178,11 @@
}
/** @return true if the constraint was changed, false otherwise. */
+ boolean setPrefetchConstraintSatisfied(final long nowElapsed, boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_PREFETCH, nowElapsed, state);
+ }
+
+ /** @return true if the constraint was changed, false otherwise. */
boolean setTimingDelayConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, nowElapsed, state);
}
@@ -1387,6 +1394,9 @@
case CONSTRAINT_DEVICE_NOT_DOZING:
return JobParameters.STOP_REASON_DEVICE_STATE;
+ case CONSTRAINT_PREFETCH:
+ return JobParameters.STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED;
+
case CONSTRAINT_TARE_WEALTH:
case CONSTRAINT_WITHIN_QUOTA:
return JobParameters.STOP_REASON_QUOTA;
@@ -1581,12 +1591,12 @@
/** All constraints besides implicit and deadline. */
static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
| CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_CONNECTIVITY
- | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
+ | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER | CONSTRAINT_PREFETCH;
// Soft override covers all non-"functional" constraints
static final int SOFT_OVERRIDE_CONSTRAINTS =
CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
- | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
+ | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE | CONSTRAINT_PREFETCH;
/** Returns true whenever all dynamically set constraints are satisfied. */
public boolean areDynamicConstraintsSatisfied() {
@@ -1775,6 +1785,9 @@
if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
pw.print(" BACKGROUND_NOT_RESTRICTED");
}
+ if ((constraints & CONSTRAINT_PREFETCH) != 0) {
+ pw.print(" PREFETCH");
+ }
if ((constraints & CONSTRAINT_TARE_WEALTH) != 0) {
pw.print(" TARE_WEALTH");
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
new file mode 100644
index 0000000..725092c
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job.controllers;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.JobSchedulerService.sSystemClock;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.NonNull;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArrayMap;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.JobSchedulerBackgroundThread;
+import com.android.server.job.JobSchedulerService;
+
+import java.util.function.Predicate;
+
+/**
+ * Controller to delay prefetch jobs until we get close to an expected app launch.
+ */
+public class PrefetchController extends StateController {
+ private static final String TAG = "JobScheduler.Prefetch";
+ private static final boolean DEBUG = JobSchedulerService.DEBUG
+ || Log.isLoggable(TAG, Log.DEBUG);
+
+ private final PcConstants mPcConstants;
+
+ @GuardedBy("mLock")
+ private final SparseArrayMap<String, ArraySet<JobStatus>> mTrackedJobs = new SparseArrayMap<>();
+ /**
+ * Cached set of the estimated next launch times of each app. Time are in the current time
+ * millis ({@link CurrentTimeMillisLong}) timebase.
+ */
+ @GuardedBy("mLock")
+ private final SparseArrayMap<String, Long> mEstimatedLaunchTimes = new SparseArrayMap<>();
+
+ /**
+ * The cutoff point to decide if a prefetch job is worth running or not. If the app is expected
+ * to launch within this amount of time into the future, then we will let a prefetch job run.
+ */
+ @GuardedBy("mLock")
+ @CurrentTimeMillisLong
+ private long mLaunchTimeThresholdMs = PcConstants.DEFAULT_LAUNCH_TIME_THRESHOLD_MS;
+
+ public PrefetchController(JobSchedulerService service) {
+ super(service);
+ mPcConstants = new PcConstants();
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+ if (jobStatus.getJob().isPrefetch()) {
+ final int userId = jobStatus.getSourceUserId();
+ final String pkgName = jobStatus.getSourcePackageName();
+ ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
+ if (jobs == null) {
+ jobs = new ArraySet<>();
+ mTrackedJobs.add(userId, pkgName, jobs);
+ }
+ jobs.add(jobStatus);
+ updateConstraintLocked(jobStatus,
+ sSystemClock.millis(), sElapsedRealtimeClock.millis());
+ }
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
+ boolean forUpdate) {
+ final ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUserId(),
+ jobStatus.getSourcePackageName());
+ if (jobs != null) {
+ jobs.remove(jobStatus);
+ }
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void onAppRemovedLocked(String packageName, int uid) {
+ if (packageName == null) {
+ Slog.wtf(TAG, "Told app removed but given null package name.");
+ return;
+ }
+ final int userId = UserHandle.getUserId(uid);
+ mTrackedJobs.delete(userId, packageName);
+ mEstimatedLaunchTimes.delete(userId, packageName);
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void onUserRemovedLocked(int userId) {
+ mTrackedJobs.delete(userId);
+ mEstimatedLaunchTimes.delete(userId);
+ }
+
+ /** Return the app's next estimated launch time. */
+ @GuardedBy("mLock")
+ @CurrentTimeMillisLong
+ public long getNextEstimatedLaunchTimeLocked(@NonNull JobStatus jobStatus) {
+ final int userId = jobStatus.getSourceUserId();
+ final String pkgName = jobStatus.getSourcePackageName();
+ Long nextEstimatedLaunchTime = mEstimatedLaunchTimes.get(userId, pkgName);
+ final long now = sSystemClock.millis();
+ if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now) {
+ // TODO(194532703): get estimated time from UsageStats
+ nextEstimatedLaunchTime = now + 2 * HOUR_IN_MILLIS;
+ mEstimatedLaunchTimes.add(userId, pkgName, nextEstimatedLaunchTime);
+ }
+ return nextEstimatedLaunchTime;
+ }
+
+ @GuardedBy("mLock")
+ private boolean maybeUpdateConstraintForPkgLocked(long now, long nowElapsed, int userId,
+ String pkgName) {
+ final ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
+ if (jobs == null) {
+ return false;
+ }
+ boolean changed = false;
+ for (int i = 0; i < jobs.size(); i++) {
+ final JobStatus js = jobs.valueAt(i);
+ changed |= updateConstraintLocked(js, now, nowElapsed);
+ }
+ return changed;
+ }
+
+ @GuardedBy("mLock")
+ private boolean updateConstraintLocked(@NonNull JobStatus jobStatus, long now,
+ long nowElapsed) {
+ return jobStatus.setPrefetchConstraintSatisfied(nowElapsed,
+ getNextEstimatedLaunchTimeLocked(jobStatus) <= now + mLaunchTimeThresholdMs);
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void prepareForUpdatedConstantsLocked() {
+ mPcConstants.mShouldReevaluateConstraints = false;
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void processConstantLocked(DeviceConfig.Properties properties, String key) {
+ mPcConstants.processConstantLocked(properties, key);
+ }
+
+ @Override
+ @GuardedBy("mLock")
+ public void onConstantsUpdatedLocked() {
+ if (mPcConstants.mShouldReevaluateConstraints) {
+ // Update job bookkeeping out of band.
+ JobSchedulerBackgroundThread.getHandler().post(() -> {
+ final ArraySet<JobStatus> changedJobs = new ArraySet<>();
+ synchronized (mLock) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final long now = sSystemClock.millis();
+ for (int u = 0; u < mTrackedJobs.numMaps(); ++u) {
+ final int userId = mTrackedJobs.keyAt(u);
+ for (int p = 0; p < mTrackedJobs.numElementsForKey(userId); ++p) {
+ final String packageName = mTrackedJobs.keyAt(u, p);
+ if (maybeUpdateConstraintForPkgLocked(
+ now, nowElapsed, userId, packageName)) {
+ changedJobs.addAll(mTrackedJobs.valueAt(u, p));
+ }
+ }
+ }
+ }
+ if (changedJobs.size() > 0) {
+ mStateChangedListener.onControllerStateChanged(changedJobs);
+ }
+ });
+ }
+ }
+
+ @VisibleForTesting
+ class PcConstants {
+ private boolean mShouldReevaluateConstraints = false;
+
+ /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */
+ private static final String PC_CONSTANT_PREFIX = "pc_";
+
+ @VisibleForTesting
+ static final String KEY_LAUNCH_TIME_THRESHOLD_MS =
+ PC_CONSTANT_PREFIX + "launch_time_threshold_ms";
+
+ private static final long DEFAULT_LAUNCH_TIME_THRESHOLD_MS = 7 * HOUR_IN_MILLIS;
+
+ /** How much time each app will have to run jobs within their standby bucket window. */
+ public long LAUNCH_TIME_THRESHOLD_MS = DEFAULT_LAUNCH_TIME_THRESHOLD_MS;
+
+ @GuardedBy("mLock")
+ public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
+ @NonNull String key) {
+ switch (key) {
+ case KEY_LAUNCH_TIME_THRESHOLD_MS:
+ LAUNCH_TIME_THRESHOLD_MS =
+ properties.getLong(key, DEFAULT_LAUNCH_TIME_THRESHOLD_MS);
+ // Limit the threshold to the range [1, 24] hours.
+ long newLaunchTimeThresholdMs = Math.min(24 * HOUR_IN_MILLIS,
+ Math.max(HOUR_IN_MILLIS, LAUNCH_TIME_THRESHOLD_MS));
+ if (mLaunchTimeThresholdMs != newLaunchTimeThresholdMs) {
+ mLaunchTimeThresholdMs = newLaunchTimeThresholdMs;
+ mShouldReevaluateConstraints = true;
+ }
+ break;
+ }
+ }
+
+ private void dump(IndentingPrintWriter pw) {
+ pw.println();
+ pw.print(PrefetchController.class.getSimpleName());
+ pw.println(":");
+ pw.increaseIndent();
+
+ pw.print(KEY_LAUNCH_TIME_THRESHOLD_MS, LAUNCH_TIME_THRESHOLD_MS).println();
+
+ pw.decreaseIndent();
+ }
+ }
+
+ //////////////////////// TESTING HELPERS /////////////////////////////
+
+ @VisibleForTesting
+ long getLaunchTimeThresholdMs() {
+ return mLaunchTimeThresholdMs;
+ }
+
+ @VisibleForTesting
+ @NonNull
+ PcConstants getPcConstants() {
+ return mPcConstants;
+ }
+
+ //////////////////////////// DATA DUMP //////////////////////////////
+
+ @Override
+ @GuardedBy("mLock")
+ public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
+ final long now = sSystemClock.millis();
+
+ pw.println("Cached launch times:");
+ pw.increaseIndent();
+ for (int u = 0; u < mEstimatedLaunchTimes.numMaps(); ++u) {
+ final int userId = mEstimatedLaunchTimes.keyAt(u);
+ for (int p = 0; p < mEstimatedLaunchTimes.numElementsForKey(userId); ++p) {
+ final String pkgName = mEstimatedLaunchTimes.keyAt(u, p);
+ final long estimatedLaunchTime = mEstimatedLaunchTimes.valueAt(u, p);
+
+ pw.print("<" + userId + ">" + pkgName + ": ");
+ pw.print(estimatedLaunchTime);
+ pw.print(" (");
+ TimeUtils.formatDuration(estimatedLaunchTime - now, pw,
+ TimeUtils.HUNDRED_DAY_FIELD_LEN);
+ pw.println(" from now)");
+ }
+ }
+ pw.decreaseIndent();
+
+ pw.println();
+ mTrackedJobs.forEach((jobs) -> {
+ for (int j = 0; j < jobs.size(); j++) {
+ final JobStatus js = jobs.valueAt(j);
+ if (!predicate.test(js)) {
+ continue;
+ }
+ pw.print("#");
+ js.printUniqueId(pw);
+ pw.print(" from ");
+ UserHandle.formatUid(pw, js.getSourceUid());
+ pw.println();
+ }
+ });
+ }
+
+ @Override
+ public void dumpConstants(IndentingPrintWriter pw) {
+ mPcConstants.dump(pw);
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index 1acb270..2b4938b 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -94,6 +94,7 @@
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
import static com.android.server.tare.TareUtils.arcToNarc;
+import static com.android.server.tare.TareUtils.narcToString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -342,6 +343,11 @@
@Override
void dump(IndentingPrintWriter pw) {
+ pw.print("Min satiated balance", narcToString(mMinSatiatedBalance)).println();
+ pw.print("Max satiated balance", narcToString(mMaxSatiatedBalance)).println();
+ pw.print("Min satiated circulation", narcToString(mMaxSatiatedCirculation)).println();
+
+ pw.println();
pw.println("Actions:");
pw.increaseIndent();
for (int i = 0; i < mActions.size(); ++i) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index fa732ea..728f5e8 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -103,6 +103,7 @@
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
import static com.android.server.tare.TareUtils.arcToNarc;
+import static com.android.server.tare.TareUtils.narcToString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -316,6 +317,11 @@
@Override
void dump(IndentingPrintWriter pw) {
+ pw.print("Min satiated balance", narcToString(mMinSatiatedBalance)).println();
+ pw.print("Max satiated balance", narcToString(mMaxSatiatedBalance)).println();
+ pw.print("Min satiated circulation", narcToString(mMaxSatiatedCirculation)).println();
+
+ pw.println();
pw.println("Actions:");
pw.increaseIndent();
for (int i = 0; i < mActions.size(); ++i) {
diff --git a/core/api/current.txt b/core/api/current.txt
index f8891b4..7855667 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -8055,6 +8055,7 @@
field public static final int STOP_REASON_CONSTRAINT_DEVICE_IDLE = 8; // 0x8
field public static final int STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW = 9; // 0x9
field public static final int STOP_REASON_DEVICE_STATE = 4; // 0x4
+ field public static final int STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED = 15; // 0xf
field public static final int STOP_REASON_PREEMPT = 2; // 0x2
field public static final int STOP_REASON_QUOTA = 10; // 0xa
field public static final int STOP_REASON_SYSTEM_PROCESSING = 14; // 0xe
@@ -10003,6 +10004,7 @@
public static final class AttributionSource.Builder {
ctor public AttributionSource.Builder(int);
+ ctor public AttributionSource.Builder(@NonNull android.content.AttributionSource);
method @NonNull public android.content.AttributionSource build();
method @NonNull public android.content.AttributionSource.Builder setAttributionTag(@Nullable String);
method @NonNull public android.content.AttributionSource.Builder setNext(@Nullable android.content.AttributionSource);
@@ -22822,7 +22824,7 @@
public class MediaMetadataRetriever implements java.lang.AutoCloseable {
ctor public MediaMetadataRetriever();
- method public void close();
+ method public void close() throws java.io.IOException;
method @Nullable public String extractMetadata(int);
method @Nullable public byte[] getEmbeddedPicture();
method @Nullable public android.graphics.Bitmap getFrameAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
@@ -22839,7 +22841,7 @@
method @Nullable public android.graphics.Bitmap getPrimaryImage();
method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int);
method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
- method public void release();
+ method public void release() throws java.io.IOException;
method public void setDataSource(String) throws java.lang.IllegalArgumentException;
method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.lang.IllegalArgumentException;
@@ -34948,6 +34950,7 @@
}
public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
+ method @Nullable public static android.accounts.Account getDefaultAccount(@NonNull android.content.ContentResolver);
field public static final String ACTION_SET_DEFAULT_ACCOUNT = "android.provider.action.SET_DEFAULT_ACCOUNT";
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9e47e96..3373d4b 100755
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -262,6 +262,7 @@
field public static final String SERIAL_PORT = "android.permission.SERIAL_PORT";
field public static final String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
field public static final String SET_CLIP_SOURCE = "android.permission.SET_CLIP_SOURCE";
+ field public static final String SET_DEFAULT_ACCOUNT_FOR_CONTACTS = "android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS";
field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
field public static final String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER";
field public static final String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
@@ -9181,6 +9182,10 @@
field @Deprecated public static final String STATE = "state";
}
+ public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
+ method @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS) public static void setDefaultAccount(@NonNull android.content.ContentResolver, @Nullable android.accounts.Account);
+ }
+
public static final class ContactsContract.SimContacts {
method @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS") public static void addSimAccount(@NonNull android.content.ContentResolver, @NonNull String, @NonNull String, int, int);
method @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS") public static void removeSimAccounts(@NonNull android.content.ContentResolver, int);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f5dd6bd..6011cc2 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -62,7 +62,6 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -80,6 +79,7 @@
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.pm.pkg.PackageUserState;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -2130,7 +2130,7 @@
return null;
}
return PackageInfoWithoutStateUtils.generate(result.getResult(), null, flags, 0, 0, null,
- new PackageUserState(), UserHandle.getCallingUserId());
+ PackageUserState.DEFAULT, UserHandle.getCallingUserId());
}
@Override
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index c21362c..20152f3 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -88,8 +88,9 @@
uid = android.os.Process.SYSTEM_UID;
}
try {
- res = new AttributionSource(uid,
- AppGlobals.getPackageManager().getPackagesForUid(uid)[0], null);
+ res = new AttributionSource.Builder(uid)
+ .setPackageName(AppGlobals.getPackageManager().getPackagesForUid(uid)[0])
+ .build();
} catch (RemoteException ignored) {
}
}
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index bdb7900..6ae2bb5 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -474,6 +474,18 @@
mAttributionSourceState.uid = uid;
}
+ public Builder(@NonNull AttributionSource current) {
+ if (current == null) {
+ throw new IllegalArgumentException("current AttributionSource can not be null");
+ }
+ mAttributionSourceState.uid = current.getUid();
+ mAttributionSourceState.packageName = current.getPackageName();
+ mAttributionSourceState.attributionTag = current.getAttributionTag();
+ mAttributionSourceState.token = current.getToken();
+ mAttributionSourceState.renouncedPermissions =
+ current.mAttributionSourceState.renouncedPermissions;
+ }
+
/**
* The package that is accessing the permission protected data.
*/
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3ab070f..232e220 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3001,7 +3001,7 @@
* @param receiver The BroadcastReceiver to handle the broadcast.
* @param filter Selects the Intent broadcasts to be received.
* @param flags Additional options for the receiver. As of
- * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+ * Android T, either {@link #RECEIVER_EXPORTED} or
* {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
* for protected broadcasts, and may additionally specify
* {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
@@ -3078,7 +3078,7 @@
* @param scheduler Handler identifying the thread that will receive
* the Intent. If null, the main thread of the process will be used.
* @param flags Additional options for the receiver. As of
- * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+ * Android T, either {@link #RECEIVER_EXPORTED} or
* {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
* for protected broadcasts, and may additionally specify
* {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
@@ -3142,7 +3142,7 @@
* @param scheduler Handler identifying the thread that will receive
* the Intent. If {@code null}, the main thread of the process will be used.
* @param flags Additional options for the receiver. As of
- * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+ * Android T, either {@link #RECEIVER_EXPORTED} or
* {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
* registered for protected broadcasts
*
@@ -3209,7 +3209,7 @@
* @param scheduler Handler identifying the thread that will receive
* the Intent. If null, the main thread of the process will be used.
* @param flags Additional options for the receiver. As of
- * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+ * Android T, either {@link #RECEIVER_EXPORTED} or
* {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
* registered for protected broadcasts
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f9d3a14..07151ec 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -49,6 +49,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.dex.ArtManager;
+import android.content.pm.pkg.PackageUserState;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.res.Configuration;
import android.content.res.Resources;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 1b34d9b..cbf54e6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -56,6 +56,8 @@
import android.content.IntentFilter;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.content.pm.split.SplitAssetLoader;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
@@ -647,14 +649,14 @@
ApplicationInfo appInfo) {
// Returns false if the package is hidden system app until installed.
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
- && !state.installed
+ && !state.isInstalled()
&& appInfo != null && appInfo.hiddenUntilInstalled) {
return false;
}
// If available for the target user, or trying to match uninstalled packages and it's
// a system app.
- return state.isAvailable(flags)
+ return PackageUserStateUtils.isAvailable(state, flags)
|| (appInfo != null && appInfo.isSystemApp()
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
@@ -699,7 +701,7 @@
public static PackageInfo generatePackageInfo(
PackageParser.Package pkg, ApexInfo apexInfo, int flags) {
return generatePackageInfo(pkg, apexInfo, EmptyArray.INT, flags, 0, 0,
- Collections.emptySet(), new PackageUserState(), UserHandle.getCallingUserId());
+ Collections.emptySet(), PackageUserState.DEFAULT, UserHandle.getCallingUserId());
}
private static PackageInfo generatePackageInfo(PackageParser.Package p, ApexInfo apexInfo,
@@ -764,7 +766,7 @@
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final Activity a = p.activities.get(i);
- if (state.isMatch(a.info, flags)) {
+ if (PackageUserStateUtils.isMatch(state, a.info, flags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(a.className)) {
continue;
}
@@ -781,7 +783,7 @@
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final Activity a = p.receivers.get(i);
- if (state.isMatch(a.info, flags)) {
+ if (PackageUserStateUtils.isMatch(state, a.info, flags)) {
res[num++] = generateActivityInfo(a, flags, state, userId);
}
}
@@ -795,7 +797,7 @@
final ServiceInfo[] res = new ServiceInfo[N];
for (int i = 0; i < N; i++) {
final Service s = p.services.get(i);
- if (state.isMatch(s.info, flags)) {
+ if (PackageUserStateUtils.isMatch(state, s.info, flags)) {
res[num++] = generateServiceInfo(s, flags, state, userId);
}
}
@@ -809,7 +811,7 @@
final ProviderInfo[] res = new ProviderInfo[N];
for (int i = 0; i < N; i++) {
final Provider pr = p.providers.get(i);
- if (state.isMatch(pr.info, flags)) {
+ if (PackageUserStateUtils.isMatch(state, pr.info, flags)) {
res[num++] = generateProviderInfo(pr, flags, state, userId);
}
}
@@ -7887,23 +7889,24 @@
// to fix up the uid.
return true;
}
- if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
- boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ if (state.getEnabledState() != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+ boolean enabled =
+ state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
if (p.applicationInfo.enabled != enabled) {
return true;
}
}
boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0;
- if (state.suspended != suspended) {
+ if (state.isSuspended() != suspended) {
return true;
}
- if (!state.installed || state.hidden) {
+ if (!state.isInstalled() || state.isHidden()) {
return true;
}
- if (state.stopped) {
+ if (state.isStopped()) {
return true;
}
- if (state.instantApp != p.applicationInfo.isInstantApp()) {
+ if (state.isInstantApp() != p.applicationInfo.isInstantApp()) {
return true;
}
if ((flags & PackageManager.GET_META_DATA) != 0
@@ -7936,40 +7939,42 @@
if (!sCompatibilityModeEnabled) {
ai.disableCompatibilityMode();
}
- if (state.installed) {
+ if (state.isInstalled()) {
ai.flags |= ApplicationInfo.FLAG_INSTALLED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
- if (state.suspended) {
+ if (state.isSuspended()) {
ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
}
- if (state.instantApp) {
+ if (state.isInstantApp()) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
} else {
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
}
- if (state.virtualPreload) {
+ if (state.isVirtualPreload()) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
} else {
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
}
- if (state.hidden) {
+ if (state.isHidden()) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
} else {
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
}
- if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
- } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ } else if (state.getEnabledState()
+ == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
- } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+ } else if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ || state.getEnabledState()
+ == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
ai.enabled = false;
}
- ai.enabledSetting = state.enabled;
+ ai.enabledSetting = state.getEnabledState();
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
@@ -7991,7 +7996,8 @@
}
if (!copyNeeded(flags, p, state, null, userId)
&& ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
- || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
+ || state.getEnabledState()
+ != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
// In this case it is safe to directly modify the internal ApplicationInfo state:
// - CompatibilityMode is global state, so will be the same for every call.
// - We only come in to here if the app should reported as installed; this is the
@@ -8013,7 +8019,7 @@
ai.sharedLibraryFiles = p.usesLibraryFiles;
ai.sharedLibraryInfos = p.usesLibraryInfos;
}
- if (state.stopped) {
+ if (state.isStopped()) {
ai.flags |= ApplicationInfo.FLAG_STOPPED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
@@ -8032,7 +8038,7 @@
// make a copy.
ai = new ApplicationInfo(ai);
ai.initForUser(userId);
- if (state.stopped) {
+ if (state.isStopped()) {
ai.flags |= ApplicationInfo.FLAG_STOPPED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
deleted file mode 100644
index 3fb1999..0000000
--- a/core/java/android/content/pm/PackageUserState.java
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ComponentName;
-import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.ParsingPackageRead;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.os.BaseBundle;
-import android.os.Debug;
-import android.os.PersistableBundle;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.DebugUtils;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Per-user state information about a package.
- * @hide
- */
-public class PackageUserState implements android.content.pm.pkg.PackageUserState {
- private static final boolean DEBUG = false;
- private static final String LOG_TAG = "PackageUserState";
-
- public long ceDataInode;
- public boolean installed;
- public boolean stopped;
- public boolean notLaunched;
- public boolean hidden; // Is the app restricted by owner / admin
- public int distractionFlags;
- public boolean suspended;
- public ArrayMap<String, SuspendParams> suspendParams; // Suspending package to suspend params
- public boolean instantApp;
- public boolean virtualPreload;
- public int enabled;
- public String lastDisableAppCaller;
- @PackageManager.InstallReason
- public int installReason;
- public @PackageManager.UninstallReason int uninstallReason;
- public String harmfulAppWarning;
- public String splashScreenTheme;
-
- public ArraySet<String> disabledComponents;
- public ArraySet<String> enabledComponents;
-
- private OverlayPaths overlayPaths;
- // Maps library name to overlay paths.
- private ArrayMap<String, OverlayPaths> sharedLibraryOverlayPaths;
- private OverlayPaths cachedOverlayPaths;
-
- @Nullable
- private ArrayMap<ComponentName, Pair<String, Integer>> componentLabelIconOverrideMap;
-
- @UnsupportedAppUsage
- public PackageUserState() {
- installed = true;
- hidden = false;
- suspended = false;
- enabled = COMPONENT_ENABLED_STATE_DEFAULT;
- installReason = PackageManager.INSTALL_REASON_UNKNOWN;
- uninstallReason = PackageManager.UNINSTALL_REASON_UNKNOWN;
- }
-
- @VisibleForTesting
- public PackageUserState(PackageUserState o) {
- ceDataInode = o.ceDataInode;
- installed = o.installed;
- stopped = o.stopped;
- notLaunched = o.notLaunched;
- hidden = o.hidden;
- distractionFlags = o.distractionFlags;
- suspended = o.suspended;
- suspendParams = new ArrayMap<>(o.suspendParams);
- instantApp = o.instantApp;
- virtualPreload = o.virtualPreload;
- enabled = o.enabled;
- lastDisableAppCaller = o.lastDisableAppCaller;
- installReason = o.installReason;
- uninstallReason = o.uninstallReason;
- disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
- enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
- overlayPaths = o.overlayPaths;
- if (o.sharedLibraryOverlayPaths != null) {
- sharedLibraryOverlayPaths = new ArrayMap<>(o.sharedLibraryOverlayPaths);
- }
- harmfulAppWarning = o.harmfulAppWarning;
- if (o.componentLabelIconOverrideMap != null) {
- this.componentLabelIconOverrideMap = new ArrayMap<>(o.componentLabelIconOverrideMap);
- }
- splashScreenTheme = o.splashScreenTheme;
- }
-
- /**
- * Sets the path of overlays currently enabled for this package and user combination.
- * @return true if the path contents differ than what they were previously
- */
- @Nullable
- public boolean setOverlayPaths(@Nullable OverlayPaths paths) {
- if (Objects.equals(paths, overlayPaths)) {
- return false;
- }
- if ((overlayPaths == null && paths.isEmpty())
- || (paths == null && overlayPaths.isEmpty())) {
- return false;
- }
- overlayPaths = paths;
- cachedOverlayPaths = null;
- return true;
- }
-
- /**
- * Sets the path of overlays currently enabled for a library that this package uses.
- *
- * @return true if the path contents for the library differ than what they were previously
- */
- public boolean setSharedLibraryOverlayPaths(@NonNull String library,
- @Nullable OverlayPaths paths) {
- if (sharedLibraryOverlayPaths == null) {
- sharedLibraryOverlayPaths = new ArrayMap<>();
- }
- final OverlayPaths currentPaths = sharedLibraryOverlayPaths.get(library);
- if (Objects.equals(paths, currentPaths)) {
- return false;
- }
- cachedOverlayPaths = null;
- if (paths == null || paths.isEmpty()) {
- return sharedLibraryOverlayPaths.remove(library) != null;
- } else {
- sharedLibraryOverlayPaths.put(library, paths);
- return true;
- }
- }
-
- /**
- * Overrides the non-localized label and icon of a component.
- *
- * @return true if the label or icon was changed.
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public boolean overrideLabelAndIcon(@NonNull ComponentName component,
- @Nullable String nonLocalizedLabel, @Nullable Integer icon) {
- String existingLabel = null;
- Integer existingIcon = null;
-
- if (componentLabelIconOverrideMap != null) {
- Pair<String, Integer> pair = componentLabelIconOverrideMap.get(component);
- if (pair != null) {
- existingLabel = pair.first;
- existingIcon = pair.second;
- }
- }
-
- boolean changed = !TextUtils.equals(existingLabel, nonLocalizedLabel)
- || !Objects.equals(existingIcon, icon);
-
- if (changed) {
- if (nonLocalizedLabel == null && icon == null) {
- componentLabelIconOverrideMap.remove(component);
- if (componentLabelIconOverrideMap.isEmpty()) {
- componentLabelIconOverrideMap = null;
- }
- } else {
- if (componentLabelIconOverrideMap == null) {
- componentLabelIconOverrideMap = new ArrayMap<>(1);
- }
-
- componentLabelIconOverrideMap.put(component, Pair.create(nonLocalizedLabel, icon));
- }
- }
-
- return changed;
- }
-
- /**
- * Clears all values previously set by {@link #overrideLabelAndIcon(ComponentName,
- * String, Integer)}.
- *
- * This is done when the package is updated as the components and resource IDs may have changed.
- */
- public void resetOverrideComponentLabelIcon() {
- componentLabelIconOverrideMap = null;
- }
-
- @Nullable
- public Pair<String, Integer> getOverrideLabelIconForComponent(ComponentName componentName) {
- if (ArrayUtils.isEmpty(componentLabelIconOverrideMap)) {
- return null;
- }
-
- return componentLabelIconOverrideMap.get(componentName);
- }
-
-
- /**
- * Test if this package is installed.
- */
- public boolean isAvailable(int flags) {
- // True if it is installed for this user and it is not hidden. If it is hidden,
- // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
- final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
- final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
- return matchAnyUser
- || (this.installed
- && (!this.hidden || matchUninstalled));
- }
-
- public boolean isMatch(ComponentInfo componentInfo, int flags) {
- return isMatch(componentInfo.applicationInfo.isSystemApp(),
- componentInfo.applicationInfo.enabled, componentInfo.enabled,
- componentInfo.directBootAware, componentInfo.name, flags);
- }
-
- public boolean isMatch(boolean isSystem, boolean isPackageEnabled,
- ParsedMainComponent component, int flags) {
- return isMatch(isSystem, isPackageEnabled, component.isEnabled(),
- component.isDirectBootAware(), component.getName(), flags);
- }
-
- /**
- * Test if the given component is considered installed, enabled and a match
- * for the given flags.
- *
- * <p>
- * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
- * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
- * </p>
- *
- */
- public boolean isMatch(boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled,
- boolean isComponentDirectBootAware, String componentName, int flags) {
- final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
- if (!isAvailable(flags) && !(isSystem && matchUninstalled)) {
- return reportIfDebug(false, flags);
- }
-
- if (!isEnabled(isPackageEnabled, isComponentEnabled, componentName, flags)) {
- return reportIfDebug(false, flags);
- }
-
- if ((flags & MATCH_SYSTEM_ONLY) != 0) {
- if (!isSystem) {
- return reportIfDebug(false, flags);
- }
- }
-
- final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
- && !isComponentDirectBootAware;
- final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
- && isComponentDirectBootAware;
- return reportIfDebug(matchesUnaware || matchesAware, flags);
- }
-
- public boolean reportIfDebug(boolean result, int flags) {
- if (DEBUG && !result) {
- Slog.i(LOG_TAG, "No match!; flags: "
- + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
- + Debug.getCaller());
- }
- return result;
- }
-
- public boolean isPackageEnabled(@NonNull ParsingPackageRead pkg) {
- switch (this.enabled) {
- case COMPONENT_ENABLED_STATE_ENABLED:
- return true;
- case COMPONENT_ENABLED_STATE_DISABLED:
- case COMPONENT_ENABLED_STATE_DISABLED_USER:
- case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
- return false;
- default:
- case COMPONENT_ENABLED_STATE_DEFAULT:
- return pkg.isEnabled();
- }
- }
-
- public boolean isEnabled(ComponentInfo componentInfo, int flags) {
- return isEnabled(componentInfo.applicationInfo.enabled, componentInfo.enabled,
- componentInfo.name, flags);
- }
-
- public boolean isEnabled(boolean isPackageEnabled,
- ParsedMainComponent parsedComponent, int flags) {
- return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(),
- flags);
- }
-
- /**
- * Test if the given component is considered enabled.
- */
- public boolean isEnabled(boolean isPackageEnabled, boolean isComponentEnabled,
- String componentName, int flags) {
- if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
- return true;
- }
-
- // First check if the overall package is disabled; if the package is
- // enabled then fall through to check specific component
- switch (this.enabled) {
- case COMPONENT_ENABLED_STATE_DISABLED:
- case COMPONENT_ENABLED_STATE_DISABLED_USER:
- return false;
- case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
- if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
- return false;
- }
- // fallthrough
- case COMPONENT_ENABLED_STATE_DEFAULT:
- if (!isPackageEnabled) {
- return false;
- }
- // fallthrough
- case COMPONENT_ENABLED_STATE_ENABLED:
- break;
- }
-
- // Check if component has explicit state before falling through to
- // the manifest default
- if (ArrayUtils.contains(this.enabledComponents, componentName)) {
- return true;
- }
- if (ArrayUtils.contains(this.disabledComponents, componentName)) {
- return false;
- }
-
- return isComponentEnabled;
- }
-
- public OverlayPaths getAllOverlayPaths() {
- if (overlayPaths == null && sharedLibraryOverlayPaths == null) {
- return null;
- }
- if (cachedOverlayPaths != null) {
- return cachedOverlayPaths;
- }
- final OverlayPaths.Builder newPaths = new OverlayPaths.Builder();
- newPaths.addAll(overlayPaths);
- if (sharedLibraryOverlayPaths != null) {
- for (final OverlayPaths libOverlayPaths : sharedLibraryOverlayPaths.values()) {
- newPaths.addAll(libOverlayPaths);
- }
- }
- cachedOverlayPaths = newPaths.build();
- return cachedOverlayPaths;
- }
-
- @Override
- final public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof PackageUserState)) {
- return false;
- }
- final PackageUserState oldState = (PackageUserState) obj;
- if (ceDataInode != oldState.ceDataInode) {
- return false;
- }
- if (installed != oldState.installed) {
- return false;
- }
- if (stopped != oldState.stopped) {
- return false;
- }
- if (notLaunched != oldState.notLaunched) {
- return false;
- }
- if (hidden != oldState.hidden) {
- return false;
- }
- if (distractionFlags != oldState.distractionFlags) {
- return false;
- }
- if (suspended != oldState.suspended) {
- return false;
- }
- if (suspended) {
- if (!Objects.equals(suspendParams, oldState.suspendParams)) {
- return false;
- }
- }
- if (instantApp != oldState.instantApp) {
- return false;
- }
- if (virtualPreload != oldState.virtualPreload) {
- return false;
- }
- if (enabled != oldState.enabled) {
- return false;
- }
- if ((lastDisableAppCaller == null && oldState.lastDisableAppCaller != null)
- || (lastDisableAppCaller != null
- && !lastDisableAppCaller.equals(oldState.lastDisableAppCaller))) {
- return false;
- }
- if (installReason != oldState.installReason) {
- return false;
- }
- if (uninstallReason != oldState.uninstallReason) {
- return false;
- }
- if ((disabledComponents == null && oldState.disabledComponents != null)
- || (disabledComponents != null && oldState.disabledComponents == null)) {
- return false;
- }
- if (disabledComponents != null) {
- if (disabledComponents.size() != oldState.disabledComponents.size()) {
- return false;
- }
- for (int i = disabledComponents.size() - 1; i >=0; --i) {
- if (!oldState.disabledComponents.contains(disabledComponents.valueAt(i))) {
- return false;
- }
- }
- }
- if ((enabledComponents == null && oldState.enabledComponents != null)
- || (enabledComponents != null && oldState.enabledComponents == null)) {
- return false;
- }
- if (enabledComponents != null) {
- if (enabledComponents.size() != oldState.enabledComponents.size()) {
- return false;
- }
- for (int i = enabledComponents.size() - 1; i >=0; --i) {
- if (!oldState.enabledComponents.contains(enabledComponents.valueAt(i))) {
- return false;
- }
- }
- }
- if (harmfulAppWarning == null && oldState.harmfulAppWarning != null
- || (harmfulAppWarning != null
- && !harmfulAppWarning.equals(oldState.harmfulAppWarning))) {
- return false;
- }
-
- if (!Objects.equals(splashScreenTheme, oldState.splashScreenTheme)) {
- return false;
- }
- return true;
- }
-
- @Override
- public int hashCode() {
- int hashCode = Long.hashCode(ceDataInode);
- hashCode = 31 * hashCode + Boolean.hashCode(installed);
- hashCode = 31 * hashCode + Boolean.hashCode(stopped);
- hashCode = 31 * hashCode + Boolean.hashCode(notLaunched);
- hashCode = 31 * hashCode + Boolean.hashCode(hidden);
- hashCode = 31 * hashCode + distractionFlags;
- hashCode = 31 * hashCode + Boolean.hashCode(suspended);
- hashCode = 31 * hashCode + Objects.hashCode(suspendParams);
- hashCode = 31 * hashCode + Boolean.hashCode(instantApp);
- hashCode = 31 * hashCode + Boolean.hashCode(virtualPreload);
- hashCode = 31 * hashCode + enabled;
- hashCode = 31 * hashCode + Objects.hashCode(lastDisableAppCaller);
- hashCode = 31 * hashCode + installReason;
- hashCode = 31 * hashCode + uninstallReason;
- hashCode = 31 * hashCode + Objects.hashCode(disabledComponents);
- hashCode = 31 * hashCode + Objects.hashCode(enabledComponents);
- hashCode = 31 * hashCode + Objects.hashCode(harmfulAppWarning);
- hashCode = 31 * hashCode + Objects.hashCode(splashScreenTheme);
- return hashCode;
- }
-
- @Override
- public long getCeDataInode() {
- return ceDataInode;
- }
-
- @NonNull
- @Override
- public Set<String> getDisabledComponents() {
- return disabledComponents;
- }
-
- @PackageManager.DistractionRestriction
- @Override
- public int getDistractionFlags() {
- return distractionFlags;
- }
-
- @NonNull
- @Override
- public Set<String> getEnabledComponents() {
- return enabledComponents;
- }
-
- @Override
- public int getEnabledState() {
- return enabled;
- }
-
- @Nullable
- @Override
- public String getHarmfulAppWarning() {
- return harmfulAppWarning;
- }
-
- @Override
- public int getInstallReason() {
- return installReason;
- }
-
- @Nullable
- @Override
- public String getLastDisableAppCaller() {
- return lastDisableAppCaller;
- }
-
- @Nullable
- @Override
- public OverlayPaths getOverlayPaths() {
- return overlayPaths;
- }
-
- @Nullable
- @Override
- public Map<String, OverlayPaths> getSharedLibraryOverlayPaths() {
- return sharedLibraryOverlayPaths;
- }
-
- @Override
- public int getUninstallReason() {
- return uninstallReason;
- }
-
- @Override
- public boolean isHidden() {
- return hidden;
- }
-
- @Override
- public boolean isInstalled() {
- return installed;
- }
-
- @Override
- public boolean isInstantApp() {
- return instantApp;
- }
-
- @Override
- public boolean isNotLaunched() {
- return notLaunched;
- }
-
- @Override
- public boolean isStopped() {
- return stopped;
- }
-
- @Override
- public boolean isSuspended() {
- return suspended;
- }
-
- @Override
- public boolean isVirtualPreload() {
- return virtualPreload;
- }
-
- /**
- * Container to describe suspension parameters.
- */
- public static final class SuspendParams {
- private static final String TAG_DIALOG_INFO = "dialog-info";
- private static final String TAG_APP_EXTRAS = "app-extras";
- private static final String TAG_LAUNCHER_EXTRAS = "launcher-extras";
-
- public SuspendDialogInfo dialogInfo;
- public PersistableBundle appExtras;
- public PersistableBundle launcherExtras;
-
- private SuspendParams() {
- }
-
- /**
- * Returns a {@link SuspendParams} object with the given fields. Returns {@code null} if all
- * the fields are {@code null}.
- *
- * @param dialogInfo
- * @param appExtras
- * @param launcherExtras
- * @return A {@link SuspendParams} object or {@code null}.
- */
- public static SuspendParams getInstanceOrNull(SuspendDialogInfo dialogInfo,
- PersistableBundle appExtras, PersistableBundle launcherExtras) {
- if (dialogInfo == null && appExtras == null && launcherExtras == null) {
- return null;
- }
- final SuspendParams instance = new SuspendParams();
- instance.dialogInfo = dialogInfo;
- instance.appExtras = appExtras;
- instance.launcherExtras = launcherExtras;
- return instance;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof SuspendParams)) {
- return false;
- }
- final SuspendParams other = (SuspendParams) obj;
- if (!Objects.equals(dialogInfo, other.dialogInfo)) {
- return false;
- }
- if (!BaseBundle.kindofEquals(appExtras, other.appExtras)) {
- return false;
- }
- if (!BaseBundle.kindofEquals(launcherExtras, other.launcherExtras)) {
- return false;
- }
- return true;
- }
-
- @Override
- public int hashCode() {
- int hashCode = Objects.hashCode(dialogInfo);
- hashCode = 31 * hashCode + ((appExtras != null) ? appExtras.size() : 0);
- hashCode = 31 * hashCode + ((launcherExtras != null) ? launcherExtras.size() : 0);
- return hashCode;
- }
-
- /**
- * Serializes this object into an xml format
- * @param out the {@link XmlSerializer} object
- * @throws IOException
- */
- public void saveToXml(TypedXmlSerializer out) throws IOException {
- if (dialogInfo != null) {
- out.startTag(null, TAG_DIALOG_INFO);
- dialogInfo.saveToXml(out);
- out.endTag(null, TAG_DIALOG_INFO);
- }
- if (appExtras != null) {
- out.startTag(null, TAG_APP_EXTRAS);
- try {
- appExtras.saveToXml(out);
- } catch (XmlPullParserException e) {
- Slog.e(LOG_TAG, "Exception while trying to write appExtras."
- + " Will be lost on reboot", e);
- }
- out.endTag(null, TAG_APP_EXTRAS);
- }
- if (launcherExtras != null) {
- out.startTag(null, TAG_LAUNCHER_EXTRAS);
- try {
- launcherExtras.saveToXml(out);
- } catch (XmlPullParserException e) {
- Slog.e(LOG_TAG, "Exception while trying to write launcherExtras."
- + " Will be lost on reboot", e);
- }
- out.endTag(null, TAG_LAUNCHER_EXTRAS);
- }
- }
-
- /**
- * Parses this object from the xml format. Returns {@code null} if no object related
- * information could be read.
- * @param in the reader
- * @return
- */
- public static SuspendParams restoreFromXml(TypedXmlPullParser in) throws IOException {
- SuspendDialogInfo readDialogInfo = null;
- PersistableBundle readAppExtras = null;
- PersistableBundle readLauncherExtras = null;
-
- final int currentDepth = in.getDepth();
- int type;
- try {
- while ((type = in.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || in.getDepth() > currentDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
- switch (in.getName()) {
- case TAG_DIALOG_INFO:
- readDialogInfo = SuspendDialogInfo.restoreFromXml(in);
- break;
- case TAG_APP_EXTRAS:
- readAppExtras = PersistableBundle.restoreFromXml(in);
- break;
- case TAG_LAUNCHER_EXTRAS:
- readLauncherExtras = PersistableBundle.restoreFromXml(in);
- break;
- default:
- Slog.w(LOG_TAG, "Unknown tag " + in.getName()
- + " in SuspendParams. Ignoring");
- break;
- }
- }
- } catch (XmlPullParserException e) {
- Slog.e(LOG_TAG, "Exception while trying to parse SuspendParams,"
- + " some fields may default", e);
- }
- return getInstanceOrNull(readDialogInfo, readAppExtras, readLauncherExtras);
- }
- }
-}
diff --git a/core/java/android/content/pm/SELinuxUtil.java b/core/java/android/content/pm/SELinuxUtil.java
index d8d52b7..90dcd85 100644
--- a/core/java/android/content/pm/SELinuxUtil.java
+++ b/core/java/android/content/pm/SELinuxUtil.java
@@ -16,6 +16,8 @@
package android.content.pm;
+import android.content.pm.pkg.PackageUserState;
+
/**
* Utility methods that need to be used in application space.
* @hide
@@ -30,7 +32,7 @@
/** @hide */
public static String getSeinfoUser(PackageUserState userState) {
- if (userState.instantApp) {
+ if (userState.isInstantApp()) {
return INSTANT_APP_STR + COMPLETE_STR;
}
return COMPLETE_STR;
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 747015d..cb26165 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -32,7 +32,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
@@ -53,6 +52,8 @@
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
import android.content.pm.parsing.component.ParsedUsesPermission;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.os.Environment;
import android.os.UserHandle;
@@ -65,7 +66,9 @@
import java.util.List;
import java.util.Set;
-/** @hide **/
+/**
+ * @hide
+ **/
public class PackageInfoWithoutStateUtils {
public static final String SYSTEM_DATA_PATH =
@@ -82,7 +85,7 @@
@Nullable
public static PackageInfo generate(ParsingPackageRead pkg, ApexInfo apexInfo, int flags) {
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
- new PackageUserState(), UserHandle.getCallingUserId(), apexInfo);
+ PackageUserState.DEFAULT, UserHandle.getCallingUserId(), apexInfo);
}
@Nullable
@@ -199,9 +202,9 @@
}
/**
- * This bypasses critical checks that are necessary for usage with data passed outside of
- * system server.
- *
+ * This bypasses critical checks that are necessary for usage with data passed outside of system
+ * server.
+ * <p>
* Prefer {@link #generateWithoutComponents(ParsingPackageRead, int[], int, long, long, Set,
* PackageUserState, int, ApexInfo, ApplicationInfo)}.
*/
@@ -376,16 +379,16 @@
}
/**
- * This bypasses critical checks that are necessary for usage with data passed outside of
- * system server.
- *
+ * This bypasses critical checks that are necessary for usage with data passed outside of system
+ * server.
+ * <p>
* Prefer {@link #generateApplicationInfo(ParsingPackageRead, int, PackageUserState, int)}.
*
* @param assignUserFields whether to fill the returned {@link ApplicationInfo} with user
* specific fields. This can be skipped when building from a system
* server package, as there are cached strings which can be used rather
- * than querying and concatenating the comparatively expensive
- * {@link Environment#getDataDirectory(String)}}.
+ * than querying and concatenating the comparatively expensive {@link
+ * Environment#getDataDirectory(String)}}.
*/
@NonNull
public static ApplicationInfo generateApplicationInfoUnchecked(@NonNull ParsingPackageRead pkg,
@@ -418,22 +421,24 @@
ai.disableCompatibilityMode();
}
- ai.flags |= flag(state.stopped, ApplicationInfo.FLAG_STOPPED)
- | flag(state.installed, ApplicationInfo.FLAG_INSTALLED)
- | flag(state.suspended, ApplicationInfo.FLAG_SUSPENDED);
- ai.privateFlags |= flag(state.instantApp, ApplicationInfo.PRIVATE_FLAG_INSTANT)
- | flag(state.virtualPreload, ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD)
- | flag(state.hidden, ApplicationInfo.PRIVATE_FLAG_HIDDEN);
+ ai.flags |= flag(state.isStopped(), ApplicationInfo.FLAG_STOPPED)
+ | flag(state.isInstalled(), ApplicationInfo.FLAG_INSTALLED)
+ | flag(state.isSuspended(), ApplicationInfo.FLAG_SUSPENDED);
+ ai.privateFlags |= flag(state.isInstantApp(), ApplicationInfo.PRIVATE_FLAG_INSTANT)
+ | flag(state.isVirtualPreload(), ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD)
+ | flag(state.isHidden(), ApplicationInfo.PRIVATE_FLAG_HIDDEN);
- if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
- } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ } else if (state.getEnabledState()
+ == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
- } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+ } else if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ || state.getEnabledState()
+ == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
ai.enabled = false;
}
- ai.enabledSetting = state.enabled;
+ ai.enabledSetting = state.getEnabledState();
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
@@ -496,9 +501,9 @@
}
/**
- * This bypasses critical checks that are necessary for usage with data passed outside of
- * system server.
- *
+ * This bypasses critical checks that are necessary for usage with data passed outside of system
+ * server.
+ * <p>
* Prefer {@link #generateActivityInfo(ParsingPackageRead, ParsedActivity, int,
* PackageUserState, ApplicationInfo, int)}.
*/
@@ -568,9 +573,9 @@
}
/**
- * This bypasses critical checks that are necessary for usage with data passed outside of
- * system server.
- *
+ * This bypasses critical checks that are necessary for usage with data passed outside of system
+ * server.
+ * <p>
* Prefer {@link #generateServiceInfo(ParsingPackageRead, ParsedService, int, PackageUserState,
* ApplicationInfo, int)}.
*/
@@ -618,9 +623,9 @@
}
/**
- * This bypasses critical checks that are necessary for usage with data passed outside of
- * system server.
- *
+ * This bypasses critical checks that are necessary for usage with data passed outside of system
+ * server.
+ * <p>
* Prefer {@link #generateProviderInfo(ParsingPackageRead, ParsedProvider, int,
* PackageUserState, ApplicationInfo, int)}.
*/
@@ -752,14 +757,14 @@
@Nullable ApplicationInfo appInfo) {
// Returns false if the package is hidden system app until installed.
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
- && !state.installed
+ && !state.isInstalled()
&& appInfo != null && appInfo.hiddenUntilInstalled) {
return false;
}
// If available for the target user, or trying to match uninstalled packages and it's
// a system app.
- return state.isAvailable(flags)
+ return PackageUserStateUtils.isAvailable(state, flags)
|| (appInfo != null && appInfo.isSystemApp()
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
@@ -796,7 +801,9 @@
}
}
- /** @see ApplicationInfo#flags */
+ /**
+ * @see ApplicationInfo#flags
+ */
public static int appInfoFlags(ParsingPackageRead pkg) {
// @formatter:off
return flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
@@ -878,7 +885,7 @@
private static boolean checkUseInstalled(ParsingPackageRead pkg, PackageUserState state,
@PackageManager.PackageInfoFlags int flags) {
// If available for the target user
- return state.isAvailable(flags);
+ return PackageUserStateUtils.isAvailable(state, flags);
}
@NonNull
diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
index e5d030c..ae6181d 100644
--- a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
@@ -22,12 +22,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
-import android.content.pm.PackageUserState;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -38,7 +39,9 @@
import java.io.IOException;
-/** @hide */
+/**
+ * @hide
+ */
public class ComponentParseUtils {
public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) {
@@ -157,7 +160,7 @@
/**
* This is not state aware. Avoid and access through PackageInfoUtils in the system server.
- *
+ * <p>
* This is a method of the utility class to discourage use.
*/
public static int getIcon(ParsedComponent component) {
@@ -166,13 +169,13 @@
public static boolean isMatch(PackageUserState state, boolean isSystem,
boolean isPackageEnabled, ParsedMainComponent component, int flags) {
- return state.isMatch(isSystem, isPackageEnabled, component.isEnabled(),
- component.isDirectBootAware(), component.getName(), flags);
+ return PackageUserStateUtils.isMatch(state, isSystem, isPackageEnabled,
+ component.isEnabled(), component.isDirectBootAware(), component.getName(), flags);
}
public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled,
ParsedMainComponent parsedComponent, int flags) {
- return state.isEnabled(isPackageEnabled, parsedComponent.isEnabled(),
+ return PackageUserStateUtils.isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
parsedComponent.getName(), flags);
}
}
diff --git a/core/java/android/content/pm/pkg/PackageUserState.java b/core/java/android/content/pm/pkg/PackageUserState.java
index e5853f0..e0d1eea 100644
--- a/core/java/android/content/pm/pkg/PackageUserState.java
+++ b/core/java/android/content/pm/pkg/PackageUserState.java
@@ -16,19 +16,30 @@
package android.content.pm.pkg;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.pm.PackageManager;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.overlay.OverlayPaths;
+import android.os.BaseBundle;
+import android.os.PersistableBundle;
+import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
-import java.util.List;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Collections;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
- * The API surface for a {@link android.content.pm.PackageUserState}. Methods are expected to return
+ * The API surface for a {@link PackageUserStateImpl}. Methods are expected to return
* immutable objects. This may mean copying data on each invocation until related classes are
* refactored to be immutable.
* <p>
@@ -40,6 +51,15 @@
// TODO(b/173807334): Expose API
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface PackageUserState {
+
+ PackageUserState DEFAULT = new PackageUserStateDefault();
+
+ /**
+ * {@link #getOverlayPaths()} but also include shared library overlay paths.
+ */
+ @Nullable
+ OverlayPaths getAllOverlayPaths();
+
/**
* Credential encrypted /data partition inode.
*/
@@ -74,6 +94,10 @@
@PackageManager.UninstallReason
int getUninstallReason();
+ boolean isComponentEnabled(@NonNull String componentName);
+
+ boolean isComponentDisabled(@NonNull String componentName);
+
boolean isHidden();
boolean isInstalled();
@@ -87,4 +111,152 @@
boolean isSuspended();
boolean isVirtualPreload();
+
+ @Nullable
+ String getSplashScreenTheme();
+
+ /**
+ * Container to describe suspension parameters.
+ */
+ final class SuspendParams {
+
+ private static final String LOG_TAG = "PackageUserState";
+ private static final String TAG_DIALOG_INFO = "dialog-info";
+ private static final String TAG_APP_EXTRAS = "app-extras";
+ private static final String TAG_LAUNCHER_EXTRAS = "launcher-extras";
+
+ public SuspendDialogInfo dialogInfo;
+ public PersistableBundle appExtras;
+ public PersistableBundle launcherExtras;
+
+ private SuspendParams() {
+ }
+
+ /**
+ * Returns a {@link SuspendParams} object with the given fields. Returns {@code null} if all
+ * the fields are {@code null}.
+ *
+ * @param dialogInfo
+ * @param appExtras
+ * @param launcherExtras
+ * @return A {@link SuspendParams} object or {@code null}.
+ */
+ public static SuspendParams getInstanceOrNull(SuspendDialogInfo dialogInfo,
+ PersistableBundle appExtras, PersistableBundle launcherExtras) {
+ if (dialogInfo == null && appExtras == null && launcherExtras == null) {
+ return null;
+ }
+ final SuspendParams instance = new SuspendParams();
+ instance.dialogInfo = dialogInfo;
+ instance.appExtras = appExtras;
+ instance.launcherExtras = launcherExtras;
+ return instance;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof SuspendParams)) {
+ return false;
+ }
+ final SuspendParams other = (SuspendParams) obj;
+ if (!Objects.equals(dialogInfo, other.dialogInfo)) {
+ return false;
+ }
+ if (!BaseBundle.kindofEquals(appExtras, other.appExtras)) {
+ return false;
+ }
+ if (!BaseBundle.kindofEquals(launcherExtras, other.launcherExtras)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = Objects.hashCode(dialogInfo);
+ hashCode = 31 * hashCode + ((appExtras != null) ? appExtras.size() : 0);
+ hashCode = 31 * hashCode + ((launcherExtras != null) ? launcherExtras.size() : 0);
+ return hashCode;
+ }
+
+ /**
+ * Serializes this object into an xml format
+ * @param out the {@link XmlSerializer} object
+ * @throws IOException
+ */
+ public void saveToXml(TypedXmlSerializer out) throws IOException {
+ if (dialogInfo != null) {
+ out.startTag(null, TAG_DIALOG_INFO);
+ dialogInfo.saveToXml(out);
+ out.endTag(null, TAG_DIALOG_INFO);
+ }
+ if (appExtras != null) {
+ out.startTag(null, TAG_APP_EXTRAS);
+ try {
+ appExtras.saveToXml(out);
+ } catch (XmlPullParserException e) {
+ Slog.e(LOG_TAG, "Exception while trying to write appExtras."
+ + " Will be lost on reboot", e);
+ }
+ out.endTag(null, TAG_APP_EXTRAS);
+ }
+ if (launcherExtras != null) {
+ out.startTag(null, TAG_LAUNCHER_EXTRAS);
+ try {
+ launcherExtras.saveToXml(out);
+ } catch (XmlPullParserException e) {
+ Slog.e(LOG_TAG, "Exception while trying to write launcherExtras."
+ + " Will be lost on reboot", e);
+ }
+ out.endTag(null, TAG_LAUNCHER_EXTRAS);
+ }
+ }
+
+ /**
+ * Parses this object from the xml format. Returns {@code null} if no object related
+ * information could be read.
+ * @param in the reader
+ * @return
+ */
+ public static SuspendParams restoreFromXml(TypedXmlPullParser in) throws IOException {
+ SuspendDialogInfo readDialogInfo = null;
+ PersistableBundle readAppExtras = null;
+ PersistableBundle readLauncherExtras = null;
+
+ final int currentDepth = in.getDepth();
+ int type;
+ try {
+ while ((type = in.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || in.getDepth() > currentDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ switch (in.getName()) {
+ case TAG_DIALOG_INFO:
+ readDialogInfo = SuspendDialogInfo.restoreFromXml(in);
+ break;
+ case TAG_APP_EXTRAS:
+ readAppExtras = PersistableBundle.restoreFromXml(in);
+ break;
+ case TAG_LAUNCHER_EXTRAS:
+ readLauncherExtras = PersistableBundle.restoreFromXml(in);
+ break;
+ default:
+ Slog.w(LOG_TAG, "Unknown tag " + in.getName()
+ + " in SuspendParams. Ignoring");
+ break;
+ }
+ }
+ } catch (XmlPullParserException e) {
+ Slog.e(LOG_TAG, "Exception while trying to parse SuspendParams,"
+ + " some fields may default", e);
+ }
+ return getInstanceOrNull(readDialogInfo, readAppExtras, readLauncherExtras);
+ }
+ }
}
diff --git a/core/java/android/content/pm/pkg/PackageUserStateDefault.java b/core/java/android/content/pm/pkg/PackageUserStateDefault.java
new file mode 100644
index 0000000..6bee8c8
--- /dev/null
+++ b/core/java/android/content/pm/pkg/PackageUserStateDefault.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+class PackageUserStateDefault implements PackageUserState {
+
+ @Override
+ public int getEnabledState() {
+ return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+
+ @Override
+ public int getInstallReason() {
+ return PackageManager.INSTALL_REASON_UNKNOWN;
+ }
+
+ @NonNull
+ @Override
+ public Map<String, OverlayPaths> getSharedLibraryOverlayPaths() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public int getUninstallReason() {
+ return PackageManager.UNINSTALL_REASON_UNKNOWN;
+ }
+
+ @Override
+ public boolean isInstalled() {
+ return true;
+ }
+
+ @NonNull
+ @Override
+ public Set<String> getDisabledComponents() {
+ return Collections.emptySet();
+ }
+
+ @NonNull
+ @Override
+ public Set<String> getEnabledComponents() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public long getCeDataInode() {
+ return 0;
+ }
+
+ @Override
+ public int getDistractionFlags() {
+ return 0;
+ }
+
+ @Nullable
+ @Override
+ public String getHarmfulAppWarning() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getLastDisableAppCaller() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public OverlayPaths getOverlayPaths() {
+ return null;
+ }
+
+ @Override
+ public boolean isHidden() {
+ return false;
+ }
+
+ @Override
+ public boolean isInstantApp() {
+ return false;
+ }
+
+ @Override
+ public boolean isNotLaunched() {
+ return false;
+ }
+
+ @Override
+ public boolean isStopped() {
+ return false;
+ }
+
+ @Override
+ public boolean isSuspended() {
+ return false;
+ }
+
+ @Override
+ public boolean isVirtualPreload() {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public String getSplashScreenTheme() {
+ return null;
+ }
+
+ @Override
+ public boolean isComponentEnabled(String componentName) {
+ return false;
+ }
+
+ @Override
+ public boolean isComponentDisabled(String componentName) {
+ return false;
+ }
+
+ @Override
+ public OverlayPaths getAllOverlayPaths() {
+ return null;
+ }
+}
diff --git a/core/java/android/content/pm/pkg/PackageUserStateImpl.java b/core/java/android/content/pm/pkg/PackageUserStateImpl.java
new file mode 100644
index 0000000..4d1b236
--- /dev/null
+++ b/core/java/android/content/pm/pkg/PackageUserStateImpl.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DataClass;
+
+import java.util.Map;
+import java.util.Set;
+
+/** @hide */
+@DataClass(genConstructor = false, genBuilder = false, genEqualsHashCode = true)
+@DataClass.Suppress({"mOverlayPathsLock", "mOverlayPaths", "mSharedLibraryOverlayPathsLock",
+ "mSharedLibraryOverlayPaths", "setOverlayPaths"})
+public class PackageUserStateImpl implements PackageUserState {
+
+ @Nullable
+ protected ArraySet<String> mDisabledComponents;
+ @Nullable
+ protected ArraySet<String> mEnabledComponents;
+
+ private long mCeDataInode;
+ private boolean mInstalled = true;
+ private boolean mStopped;
+ private boolean mNotLaunched;
+ private boolean mHidden; // Is the app restricted by owner / admin
+ private int mDistractionFlags;
+ private boolean mSuspended;
+ private boolean mInstantApp;
+ private boolean mVirtualPreload;
+ private int mEnabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ @PackageManager.InstallReason
+ private int mInstallReason = PackageManager.INSTALL_REASON_UNKNOWN;
+ @PackageManager.UninstallReason
+ private int mUninstallReason = PackageManager.UNINSTALL_REASON_UNKNOWN;
+ @Nullable
+ private String mHarmfulAppWarning;
+ @Nullable
+ private String mLastDisableAppCaller;
+
+ @Nullable
+ protected OverlayPaths mOverlayPaths;
+
+ // Lib name to overlay paths
+ @Nullable
+ protected ArrayMap<String, OverlayPaths> mSharedLibraryOverlayPaths;
+
+ @Nullable
+ private String mSplashScreenTheme;
+
+ public PackageUserStateImpl() {
+ }
+
+ @VisibleForTesting
+ public PackageUserStateImpl(PackageUserStateImpl other) {
+ mDisabledComponents = ArrayUtils.cloneOrNull(other.mDisabledComponents);
+ mEnabledComponents = ArrayUtils.cloneOrNull(other.mEnabledComponents);
+ mOverlayPaths = other.mOverlayPaths;
+ if (other.mSharedLibraryOverlayPaths != null) {
+ mSharedLibraryOverlayPaths = new ArrayMap<>(other.mSharedLibraryOverlayPaths);
+ }
+ this.mDisabledComponents = other.mDisabledComponents;
+ this.mEnabledComponents = other.mEnabledComponents;
+ this.mCeDataInode = other.mCeDataInode;
+ this.mInstalled = other.mInstalled;
+ this.mStopped = other.mStopped;
+ this.mNotLaunched = other.mNotLaunched;
+ this.mHidden = other.mHidden;
+ this.mDistractionFlags = other.mDistractionFlags;
+ this.mSuspended = other.mSuspended;
+ this.mInstantApp = other.mInstantApp;
+ this.mVirtualPreload = other.mVirtualPreload;
+ this.mEnabledState = other.mEnabledState;
+ this.mInstallReason = other.mInstallReason;
+ this.mUninstallReason = other.mUninstallReason;
+ this.mHarmfulAppWarning = other.mHarmfulAppWarning;
+ this.mLastDisableAppCaller = other.mLastDisableAppCaller;
+ this.mOverlayPaths = other.mOverlayPaths;
+ this.mSharedLibraryOverlayPaths = other.mSharedLibraryOverlayPaths;
+ this.mSplashScreenTheme = other.mSplashScreenTheme;
+ }
+
+ @Override
+ public boolean isComponentEnabled(String componentName) {
+ // TODO: Not locked
+ return ArrayUtils.contains(mEnabledComponents, componentName);
+ }
+
+ @Override
+ public boolean isComponentDisabled(String componentName) {
+ // TODO: Not locked
+ return ArrayUtils.contains(mDisabledComponents, componentName);
+ }
+
+ @Override
+ public OverlayPaths getAllOverlayPaths() {
+ if (mOverlayPaths == null && mSharedLibraryOverlayPaths == null) {
+ return null;
+ }
+ final OverlayPaths.Builder newPaths = new OverlayPaths.Builder();
+ newPaths.addAll(mOverlayPaths);
+ if (mSharedLibraryOverlayPaths != null) {
+ for (final OverlayPaths libOverlayPaths : mSharedLibraryOverlayPaths.values()) {
+ newPaths.addAll(libOverlayPaths);
+ }
+ }
+ return newPaths.build();
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/pkg/PackageUserStateImpl.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ public @Nullable ArraySet<String> getDisabledComponents() {
+ return mDisabledComponents;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable ArraySet<String> getEnabledComponents() {
+ return mEnabledComponents;
+ }
+
+ @DataClass.Generated.Member
+ public long getCeDataInode() {
+ return mCeDataInode;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isInstalled() {
+ return mInstalled;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isStopped() {
+ return mStopped;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isNotLaunched() {
+ return mNotLaunched;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isHidden() {
+ return mHidden;
+ }
+
+ @DataClass.Generated.Member
+ public int getDistractionFlags() {
+ return mDistractionFlags;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isSuspended() {
+ return mSuspended;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isInstantApp() {
+ return mInstantApp;
+ }
+
+ @DataClass.Generated.Member
+ public boolean isVirtualPreload() {
+ return mVirtualPreload;
+ }
+
+ @DataClass.Generated.Member
+ public int getEnabledState() {
+ return mEnabledState;
+ }
+
+ @DataClass.Generated.Member
+ public @PackageManager.InstallReason int getInstallReason() {
+ return mInstallReason;
+ }
+
+ @DataClass.Generated.Member
+ public @PackageManager.UninstallReason int getUninstallReason() {
+ return mUninstallReason;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable String getHarmfulAppWarning() {
+ return mHarmfulAppWarning;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable String getLastDisableAppCaller() {
+ return mLastDisableAppCaller;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable OverlayPaths getOverlayPaths() {
+ return mOverlayPaths;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable ArrayMap<String,OverlayPaths> getSharedLibraryOverlayPaths() {
+ return mSharedLibraryOverlayPaths;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable String getSplashScreenTheme() {
+ return mSplashScreenTheme;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setDisabledComponents(@NonNull ArraySet<String> value) {
+ mDisabledComponents = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setEnabledComponents(@NonNull ArraySet<String> value) {
+ mEnabledComponents = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setCeDataInode( long value) {
+ mCeDataInode = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setInstalled( boolean value) {
+ mInstalled = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setStopped( boolean value) {
+ mStopped = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setNotLaunched( boolean value) {
+ mNotLaunched = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setHidden( boolean value) {
+ mHidden = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setDistractionFlags( int value) {
+ mDistractionFlags = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setSuspended( boolean value) {
+ mSuspended = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setInstantApp( boolean value) {
+ mInstantApp = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setVirtualPreload( boolean value) {
+ mVirtualPreload = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setEnabledState( int value) {
+ mEnabledState = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setInstallReason(@PackageManager.InstallReason int value) {
+ mInstallReason = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ PackageManager.InstallReason.class, null, mInstallReason);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setUninstallReason(@PackageManager.UninstallReason int value) {
+ mUninstallReason = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ PackageManager.UninstallReason.class, null, mUninstallReason);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setHarmfulAppWarning(@NonNull String value) {
+ mHarmfulAppWarning = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setLastDisableAppCaller(@NonNull String value) {
+ mLastDisableAppCaller = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setSharedLibraryOverlayPaths(@NonNull ArrayMap<String,OverlayPaths> value) {
+ mSharedLibraryOverlayPaths = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setSplashScreenTheme(@NonNull String value) {
+ mSplashScreenTheme = value;
+ return this;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(PackageUserStateImpl other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ PackageUserStateImpl that = (PackageUserStateImpl) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && java.util.Objects.equals(mDisabledComponents, that.mDisabledComponents)
+ && java.util.Objects.equals(mEnabledComponents, that.mEnabledComponents)
+ && mCeDataInode == that.mCeDataInode
+ && mInstalled == that.mInstalled
+ && mStopped == that.mStopped
+ && mNotLaunched == that.mNotLaunched
+ && mHidden == that.mHidden
+ && mDistractionFlags == that.mDistractionFlags
+ && mSuspended == that.mSuspended
+ && mInstantApp == that.mInstantApp
+ && mVirtualPreload == that.mVirtualPreload
+ && mEnabledState == that.mEnabledState
+ && mInstallReason == that.mInstallReason
+ && mUninstallReason == that.mUninstallReason
+ && java.util.Objects.equals(mHarmfulAppWarning, that.mHarmfulAppWarning)
+ && java.util.Objects.equals(mLastDisableAppCaller, that.mLastDisableAppCaller)
+ && java.util.Objects.equals(mOverlayPaths, that.mOverlayPaths)
+ && java.util.Objects.equals(mSharedLibraryOverlayPaths, that.mSharedLibraryOverlayPaths)
+ && java.util.Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mDisabledComponents);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mEnabledComponents);
+ _hash = 31 * _hash + Long.hashCode(mCeDataInode);
+ _hash = 31 * _hash + Boolean.hashCode(mInstalled);
+ _hash = 31 * _hash + Boolean.hashCode(mStopped);
+ _hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
+ _hash = 31 * _hash + Boolean.hashCode(mHidden);
+ _hash = 31 * _hash + mDistractionFlags;
+ _hash = 31 * _hash + Boolean.hashCode(mSuspended);
+ _hash = 31 * _hash + Boolean.hashCode(mInstantApp);
+ _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
+ _hash = 31 * _hash + mEnabledState;
+ _hash = 31 * _hash + mInstallReason;
+ _hash = 31 * _hash + mUninstallReason;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mHarmfulAppWarning);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mLastDisableAppCaller);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mOverlayPaths);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mSharedLibraryOverlayPaths);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mSplashScreenTheme);
+ return _hash;
+ }
+
+ @DataClass.Generated(
+ time = 1633391914126L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/content/pm/pkg/PackageUserStateImpl.java",
+ inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mSuspended\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\nclass PackageUserStateImpl extends java.lang.Object implements [android.content.pm.pkg.PackageUserState]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/pkg/PackageUserStateInternal.java b/core/java/android/content/pm/pkg/PackageUserStateInternal.java
new file mode 100644
index 0000000..b3f849b
--- /dev/null
+++ b/core/java/android/content/pm/pkg/PackageUserStateInternal.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+
+/** @hide */
+public interface PackageUserStateInternal extends PackageUserState {
+
+ PackageUserStateInternal DEFAULT = new PackageUserStateInternalDefault();
+
+ @Nullable
+ ArrayMap<String, SuspendParams> getSuspendParams();
+
+ @Nullable
+ ArraySet<String> getDisabledComponentsNoCopy();
+
+ @Nullable
+ ArraySet<String> getEnabledComponentsNoCopy();
+
+ @Nullable
+ Pair<String, Integer> getOverrideLabelIconForComponent(@NonNull ComponentName componentName);
+}
diff --git a/core/java/android/content/pm/pkg/PackageUserStateInternalDefault.java b/core/java/android/content/pm/pkg/PackageUserStateInternalDefault.java
new file mode 100644
index 0000000..b72ed13
--- /dev/null
+++ b/core/java/android/content/pm/pkg/PackageUserStateInternalDefault.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+
+class PackageUserStateInternalDefault extends PackageUserStateDefault implements
+ PackageUserStateInternal {
+
+ @Nullable
+ @Override
+ public ArrayMap<String, SuspendParams> getSuspendParams() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public ArraySet<String> getDisabledComponentsNoCopy() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public ArraySet<String> getEnabledComponentsNoCopy() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Pair<String, Integer> getOverrideLabelIconForComponent(
+ @NonNull ComponentName componentName) {
+ return null;
+ }
+}
diff --git a/core/java/android/content/pm/pkg/PackageUserStateUtils.java b/core/java/android/content/pm/pkg/PackageUserStateUtils.java
new file mode 100644
index 0000000..e46a10c
--- /dev/null
+++ b/core/java/android/content/pm/pkg/PackageUserStateUtils.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.pkg;
+
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+
+import android.annotation.NonNull;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.parsing.ParsingPackageRead;
+import android.content.pm.parsing.component.ParsedMainComponent;
+import android.os.Debug;
+import android.util.DebugUtils;
+import android.util.Slog;
+
+/** @hide */
+public class PackageUserStateUtils {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "PackageUserStateUtils";
+
+ public static boolean isMatch(@NonNull PackageUserState state, ComponentInfo componentInfo,
+ int flags) {
+ return isMatch(state, componentInfo.applicationInfo.isSystemApp(),
+ componentInfo.applicationInfo.enabled, componentInfo.enabled,
+ componentInfo.directBootAware, componentInfo.name, flags);
+ }
+
+ public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem,
+ boolean isPackageEnabled, ParsedMainComponent component, int flags) {
+ return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(),
+ component.isDirectBootAware(), component.getName(), flags);
+ }
+
+ /**
+ * Test if the given component is considered installed, enabled and a match for the given
+ * flags.
+ *
+ * <p>
+ * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link
+ * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
+ * </p>
+ */
+ public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem,
+ boolean isPackageEnabled, boolean isComponentEnabled,
+ boolean isComponentDirectBootAware, String componentName, int flags) {
+ final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
+ if (!isAvailable(state, flags) && !(isSystem && matchUninstalled)) {
+ return reportIfDebug(false, flags);
+ }
+
+ if (!isEnabled(state, isPackageEnabled, isComponentEnabled, componentName, flags)) {
+ return reportIfDebug(false, flags);
+ }
+
+ if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+ if (!isSystem) {
+ return reportIfDebug(false, flags);
+ }
+ }
+
+ final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0)
+ && !isComponentDirectBootAware;
+ final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0)
+ && isComponentDirectBootAware;
+ return reportIfDebug(matchesUnaware || matchesAware, flags);
+ }
+
+ public static boolean isAvailable(@NonNull PackageUserState state, int flags) {
+ // True if it is installed for this user and it is not hidden. If it is hidden,
+ // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
+ final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
+ final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
+ return matchAnyUser
+ || (state.isInstalled()
+ && (!state.isHidden() || matchUninstalled));
+ }
+
+ public static boolean reportIfDebug(boolean result, int flags) {
+ if (DEBUG && !result) {
+ Slog.i(TAG, "No match!; flags: "
+ + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
+ + Debug.getCaller());
+ }
+ return result;
+ }
+
+ public static boolean isEnabled(@NonNull PackageUserState state, ComponentInfo componentInfo,
+ int flags) {
+ return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled,
+ componentInfo.name, flags);
+ }
+
+ public static boolean isEnabled(@NonNull PackageUserState state, boolean isPackageEnabled,
+ ParsedMainComponent parsedComponent, int flags) {
+ return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
+ parsedComponent.getName(), flags);
+ }
+
+ /**
+ * Test if the given component is considered enabled.
+ */
+ public static boolean isEnabled(@NonNull PackageUserState state, boolean isPackageEnabled,
+ boolean isComponentEnabled, String componentName, int flags) {
+ if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
+ return true;
+ }
+
+ // First check if the overall package is disabled; if the package is
+ // enabled then fall through to check specific component
+ switch (state.getEnabledState()) {
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
+ return false;
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
+ if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
+ return false;
+ }
+ // fallthrough
+ case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+ if (!isPackageEnabled) {
+ return false;
+ }
+ // fallthrough
+ case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+ break;
+ }
+
+ // Check if component has explicit state before falling through to
+ // the manifest default
+ if (state.isComponentEnabled(componentName)) {
+ return true;
+ } else if (state.isComponentDisabled(componentName)) {
+ return false;
+ }
+
+ return isComponentEnabled;
+ }
+
+ public static boolean isPackageEnabled(@NonNull PackageUserState state,
+ @NonNull ParsingPackageRead pkg) {
+ switch (state.getEnabledState()) {
+ case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+ return true;
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
+ return false;
+ default:
+ case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+ return pkg.isEnabled();
+ }
+ }
+}
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 518b22b..f5b2ac5 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -24,6 +24,8 @@
import android.text.TextUtils;
import android.util.Log;
+import java.util.Arrays;
+
import com.android.internal.R;
/**
@@ -258,10 +260,11 @@
String defaultValue,
int posture) {
String sensorType = defaultValue;
- if (posture < postureMapping.length) {
+ if (postureMapping != null && posture < postureMapping.length) {
sensorType = postureMapping[posture];
} else {
- Log.e(TAG, "Unsupported doze posture " + posture);
+ Log.e(TAG, "Unsupported doze posture " + posture
+ + " postureMapping=" + Arrays.toString(postureMapping));
}
return TextUtils.isEmpty(sensorType) ? defaultValue : sensorType;
diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java
index c5d37c2..0dc8f92 100644
--- a/core/java/android/hardware/display/BrightnessInfo.java
+++ b/core/java/android/hardware/display/BrightnessInfo.java
@@ -60,12 +60,18 @@
/** Brightness */
public final float brightness;
+ /** Brightness after {@link DisplayPowerController} adjustments */
+ public final float adjustedBrightness;
+
/** Current minimum supported brightness. */
public final float brightnessMinimum;
/** Current maximum supported brightness. */
public final float brightnessMaximum;
+ /** Brightness values greater than this point are only used in High Brightness Mode. */
+ public final float highBrightnessTransitionPoint;
+
/**
* Current state of high brightness mode.
* Can be any of HIGH_BRIGHTNESS_MODE_* values.
@@ -73,11 +79,20 @@
public final int highBrightnessMode;
public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum,
- @HighBrightnessMode int highBrightnessMode) {
+ @HighBrightnessMode int highBrightnessMode, float highBrightnessTransitionPoint) {
+ this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode,
+ highBrightnessTransitionPoint);
+ }
+
+ public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum,
+ float brightnessMaximum, @HighBrightnessMode int highBrightnessMode,
+ float highBrightnessTransitionPoint) {
this.brightness = brightness;
+ this.adjustedBrightness = adjustedBrightness;
this.brightnessMinimum = brightnessMinimum;
this.brightnessMaximum = brightnessMaximum;
this.highBrightnessMode = highBrightnessMode;
+ this.highBrightnessTransitionPoint = highBrightnessTransitionPoint;
}
/**
@@ -103,9 +118,11 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeFloat(brightness);
+ dest.writeFloat(adjustedBrightness);
dest.writeFloat(brightnessMinimum);
dest.writeFloat(brightnessMaximum);
dest.writeInt(highBrightnessMode);
+ dest.writeFloat(highBrightnessTransitionPoint);
}
public static final @android.annotation.NonNull Creator<BrightnessInfo> CREATOR =
@@ -123,9 +140,11 @@
private BrightnessInfo(Parcel source) {
brightness = source.readFloat();
+ adjustedBrightness = source.readFloat();
brightnessMinimum = source.readFloat();
brightnessMaximum = source.readFloat();
highBrightnessMode = source.readInt();
+ highBrightnessTransitionPoint = source.readFloat();
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fb99118..dd387da 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1908,6 +1908,10 @@
public final HistoryTag localWakeReasonTag = new HistoryTag();
public final HistoryTag localEventTag = new HistoryTag();
+ // Includes a tag's first occurrence in the parcel, so the value of the tag is written
+ // rather than just its index in the history tag pool.
+ public boolean tagsFirstOccurrence;
+
@UnsupportedAppUsage
public HistoryItem() {
}
@@ -2014,6 +2018,7 @@
wakeReasonTag = null;
eventCode = EVENT_NONE;
eventTag = null;
+ tagsFirstOccurrence = false;
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -2061,6 +2066,7 @@
} else {
eventTag = null;
}
+ tagsFirstOccurrence = o.tagsFirstOccurrence;
currentTime = o.currentTime;
}
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 591b665..d37c0eb 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -133,7 +133,6 @@
private final List<UserBatteryConsumer> mUserBatteryConsumers;
private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;
private final Parcel mHistoryBuffer;
- private final List<BatteryStats.HistoryTag> mHistoryTagPool;
private CursorWindow mBatteryConsumersCursorWindow;
private BatteryUsageStats(@NonNull Builder builder) {
@@ -145,7 +144,6 @@
mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
mHistoryBuffer = builder.mHistoryBuffer;
- mHistoryTagPool = builder.mHistoryTagPool;
mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
@@ -283,7 +281,7 @@
/**
* Returns the names of custom power components in order, so the first name in the array
* corresponds to the custom componentId
- * {@link BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID}.
+ * {@link BatteryConsumer#FIRST_CUSTOM_POWER_COMPONENT_ID}.
*/
@NonNull
public String[] getCustomPowerComponentNames() {
@@ -299,8 +297,7 @@
throw new IllegalStateException(
"Battery history was not requested in the BatteryUsageStatsQuery");
}
- return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer),
- mHistoryTagPool);
+ return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer));
}
@Override
@@ -361,19 +358,8 @@
mHistoryBuffer = Parcel.obtain();
mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);
-
- int historyTagCount = source.readInt();
- mHistoryTagPool = new ArrayList<>(historyTagCount);
- for (int i = 0; i < historyTagCount; i++) {
- BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag();
- tag.string = source.readString();
- tag.uid = source.readInt();
- tag.poolIdx = source.readInt();
- mHistoryTagPool.add(tag);
- }
} else {
mHistoryBuffer = null;
- mHistoryTagPool = null;
}
}
@@ -395,13 +381,6 @@
if (mHistoryBuffer != null) {
dest.writeBoolean(true);
dest.writeBlob(mHistoryBuffer.marshall());
- dest.writeInt(mHistoryTagPool.size());
- for (int i = mHistoryTagPool.size() - 1; i >= 0; i--) {
- final BatteryStats.HistoryTag tag = mHistoryTagPool.get(i);
- dest.writeString(tag.string);
- dest.writeInt(tag.uid);
- dest.writeInt(tag.poolIdx);
- }
} else {
dest.writeBoolean(false);
}
@@ -769,7 +748,6 @@
private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
new SparseArray<>();
private Parcel mHistoryBuffer;
- private List<BatteryStats.HistoryTag> mHistoryTagPool;
public Builder(@NonNull String[] customPowerComponentNames) {
this(customPowerComponentNames, false);
@@ -888,10 +866,8 @@
* Sets the parceled recent history.
*/
@NonNull
- public Builder setBatteryHistory(Parcel historyBuffer,
- List<BatteryStats.HistoryTag> historyTagPool) {
+ public Builder setBatteryHistory(Parcel historyBuffer) {
mHistoryBuffer = historyBuffer;
- mHistoryTagPool = historyTagPool;
return this;
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d120264..5e66bff 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -2952,10 +2952,7 @@
*/
@Nullable
public static String getLocalAccountName(@NonNull Context context) {
- // config_rawContactsLocalAccountName is defined in
- // platform/frameworks/base/core/res/res/values/config.xml
- return TextUtils.nullIfEmpty(context.getString(
- com.android.internal.R.string.config_rawContactsLocalAccountName));
+ return null;
}
/**
@@ -2971,10 +2968,7 @@
*/
@Nullable
public static String getLocalAccountType(@NonNull Context context) {
- // config_rawContactsLocalAccountType is defined in
- // platform/frameworks/base/core/res/res/values/config.xml
- return TextUtils.nullIfEmpty(context.getString(
- com.android.internal.R.string.config_rawContactsLocalAccountType));
+ return null;
}
/**
@@ -8698,6 +8692,56 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SET_DEFAULT_ACCOUNT =
"android.provider.action.SET_DEFAULT_ACCOUNT";
+
+ /**
+ * The method to invoke in order to set the default account for new contacts.
+ *
+ * @hide
+ */
+ public static final String SET_DEFAULT_ACCOUNT_METHOD = "setDefaultAccount";
+
+ /**
+ * The method to invoke in order to query the default account for new contacts.
+ *
+ * @hide
+ */
+ public static final String QUERY_DEFAULT_ACCOUNT_METHOD = "queryDefaultAccount";
+
+ /**
+ * Key in the incoming Bundle for the default account.
+ *
+ * @hide
+ */
+ public static final String KEY_DEFAULT_ACCOUNT = "key_default_account";
+
+ /**
+ * Return the account that was set to default account for new contacts.
+ */
+ @Nullable
+ public static Account getDefaultAccount(@NonNull ContentResolver resolver) {
+ Bundle response = resolver.call(ContactsContract.AUTHORITY_URI,
+ QUERY_DEFAULT_ACCOUNT_METHOD, null, null);
+ return response.getParcelable(KEY_DEFAULT_ACCOUNT);
+ }
+
+ /**
+ * Set the account to be the default account for new contacts.
+ *
+ * @param account the account to be set to default.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
+ public static void setDefaultAccount(@NonNull ContentResolver resolver,
+ @Nullable Account account) {
+ Bundle extras = new Bundle();
+ if (account != null) {
+ extras.putString(ACCOUNT_NAME, account.name);
+ extras.putString(ACCOUNT_TYPE, account.type);
+ }
+
+ resolver.call(ContactsContract.AUTHORITY_URI, SET_DEFAULT_ACCOUNT_METHOD, null, extras);
+ }
}
/**
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 91b4b7f..b8dbfb3 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -314,6 +314,15 @@
return intent;
}
+ /**
+ * Call {@link Activity#onCreate} without initializing anything further. This should
+ * only be used when the activity is about to be immediately finished to avoid wasting
+ * initializing steps and leaking resources.
+ */
+ protected void super_onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
// Use a specialized prompt when we're handling the 'Home' app startActivity()
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index 1871ac5..c5f1848 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -21,8 +21,7 @@
import android.os.BatteryStats;
import android.os.Parcel;
import android.util.Slog;
-
-import java.util.List;
+import android.util.SparseArray;
/**
* An iterator for {@link BatteryStats.HistoryItem}'s.
@@ -33,23 +32,11 @@
private final BatteryStatsHistory mBatteryStatsHistory;
private final BatteryStats.HistoryStepDetails mReadHistoryStepDetails =
new BatteryStats.HistoryStepDetails();
- private final String[] mReadHistoryStrings;
- private final int[] mReadHistoryUids;
+ private final SparseArray<BatteryStats.HistoryTag> mHistoryTags = new SparseArray<>();
- public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
- @NonNull List<BatteryStats.HistoryTag> historyTagPool) {
+ public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history) {
mBatteryStatsHistory = history;
-
mBatteryStatsHistory.startIteratingHistory();
-
- mReadHistoryStrings = new String[historyTagPool.size()];
- mReadHistoryUids = new int[historyTagPool.size()];
- for (int i = historyTagPool.size() - 1; i >= 0; i--) {
- BatteryStats.HistoryTag tag = historyTagPool.get(i);
- final int idx = tag.poolIdx;
- mReadHistoryStrings[idx] = tag.string;
- mReadHistoryUids[idx] = tag.uid;
- }
}
/**
@@ -161,26 +148,16 @@
}
if ((firstToken & BatteryStatsImpl.DELTA_WAKELOCK_FLAG) != 0) {
- int indexes = src.readInt();
- int wakeLockIndex = indexes & 0xffff;
- int wakeReasonIndex = (indexes >> 16) & 0xffff;
- if (wakeLockIndex != 0xffff) {
+ final int indexes = src.readInt();
+ final int wakeLockIndex = indexes & 0xffff;
+ final int wakeReasonIndex = (indexes >> 16) & 0xffff;
+ if (readHistoryTag(src, wakeLockIndex, cur.localWakelockTag)) {
cur.wakelockTag = cur.localWakelockTag;
- readHistoryTag(wakeLockIndex, cur.wakelockTag);
- if (DEBUG) {
- Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
- + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
- }
} else {
cur.wakelockTag = null;
}
- if (wakeReasonIndex != 0xffff) {
+ if (readHistoryTag(src, wakeReasonIndex, cur.localWakeReasonTag)) {
cur.wakeReasonTag = cur.localWakeReasonTag;
- readHistoryTag(wakeReasonIndex, cur.wakeReasonTag);
- if (DEBUG) {
- Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
- + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
- }
} else {
cur.wakeReasonTag = null;
}
@@ -195,7 +172,11 @@
final int codeAndIndex = src.readInt();
cur.eventCode = (codeAndIndex & 0xffff);
final int index = ((codeAndIndex >> 16) & 0xffff);
- readHistoryTag(index, cur.eventTag);
+ if (readHistoryTag(src, index, cur.localEventTag)) {
+ cur.eventTag = cur.localEventTag;
+ } else {
+ cur.eventTag = null;
+ }
cur.numReadInts += 1;
if (DEBUG) {
Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
@@ -220,40 +201,29 @@
cur.wifiRailChargeMah = src.readDouble();
}
- int getHistoryStringPoolSize() {
- return mReadHistoryStrings.length;
- }
-
- int getHistoryStringPoolBytes() {
- int totalChars = 0;
- for (int i = mReadHistoryStrings.length - 1; i >= 0; i--) {
- if (mReadHistoryStrings[i] != null) {
- totalChars += mReadHistoryStrings[i].length() + 1;
- }
+ private boolean readHistoryTag(Parcel src, int index, BatteryStats.HistoryTag outTag) {
+ if (index == 0xffff) {
+ return false;
}
- // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
- // Each string character is 2 bytes.
- return (mReadHistoryStrings.length * 12) + (totalChars * 2);
- }
+ if ((index & BatteryStatsImpl.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
+ BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag();
+ tag.readFromParcel(src);
+ tag.poolIdx = index & ~BatteryStatsImpl.TAG_FIRST_OCCURRENCE_FLAG;
+ mHistoryTags.put(tag.poolIdx, tag);
- String getHistoryTagPoolString(int index) {
- return mReadHistoryStrings[index];
- }
-
- int getHistoryTagPoolUid(int index) {
- return mReadHistoryUids[index];
- }
-
- private void readHistoryTag(int index, BatteryStats.HistoryTag tag) {
- if (index < mReadHistoryStrings.length) {
- tag.string = mReadHistoryStrings[index];
- tag.uid = mReadHistoryUids[index];
+ outTag.setTo(tag);
} else {
- tag.string = null;
- tag.uid = 0;
+ BatteryStats.HistoryTag historyTag = mHistoryTags.get(index);
+ if (historyTag != null) {
+ outTag.setTo(historyTag);
+ } else {
+ outTag.string = null;
+ outTag.uid = 0;
+ }
+ outTag.poolIdx = index;
}
- tag.poolIdx = index;
+ return true;
}
private static void readBatteryLevelInt(int batteryLevelInt, BatteryStats.HistoryItem out) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 94a1efe..63cce0a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -160,7 +160,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 201;
+ static final int VERSION = 202;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -757,7 +757,11 @@
protected boolean mRecordingHistory = false;
int mNumHistoryItems;
+ private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe;
+ private static final int MAX_HISTORY_TAG_STRING_LENGTH = 256;
+
final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
+ private SparseArray<HistoryTag> mHistoryTags;
final Parcel mHistoryBuffer = Parcel.obtain();
final HistoryItem mHistoryLastWritten = new HistoryItem();
final HistoryItem mHistoryLastLastWritten = new HistoryItem();
@@ -816,7 +820,6 @@
private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator;
private HistoryItem mHistoryIterator;
- private boolean mReadOverflow;
int mStartCount;
@@ -1191,12 +1194,21 @@
}
public BatteryStatsImpl(Clock clock) {
+ this(clock, (File) null);
+ }
+
+ public BatteryStatsImpl(Clock clock, File historyDirectory) {
init(clock);
mStartClockTimeMs = clock.currentTimeMillis();
- mStatsFile = null;
mCheckinFile = null;
mDailyFile = null;
- mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
+ if (historyDirectory == null) {
+ mStatsFile = null;
+ mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
+ } else {
+ mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin"));
+ mBatteryStatsHistory = new BatteryStatsHistory(this, historyDirectory, mHistoryBuffer);
+ }
mHandler = null;
mPlatformIdleStateCallback = null;
mMeasuredEnergyRetriever = null;
@@ -3321,21 +3333,43 @@
return kmt;
}
+ /**
+ * Returns the index for the specified tag. If this is the first time the tag is encountered
+ * while writing the current history buffer, the method returns
+ * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code>
+ */
private int writeHistoryTag(HistoryTag tag) {
Integer idxObj = mHistoryTagPool.get(tag);
int idx;
if (idxObj != null) {
idx = idxObj;
- } else {
+ if ((idx & TAG_FIRST_OCCURRENCE_FLAG) != 0) {
+ idx &= ~TAG_FIRST_OCCURRENCE_FLAG;
+ mHistoryTagPool.put(tag, idx);
+ }
+ return idx;
+ } else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) {
idx = mNextHistoryTagIdx;
HistoryTag key = new HistoryTag();
key.setTo(tag);
tag.poolIdx = idx;
mHistoryTagPool.put(key, idx);
mNextHistoryTagIdx++;
- mNumHistoryTagChars += key.string.length() + 1;
+ final int stringLength = key.string.length();
+
+ if (stringLength > MAX_HISTORY_TAG_STRING_LENGTH) {
+ Slog.wtf(TAG, "Long battery history tag: " + key.string);
+ }
+
+ mNumHistoryTagChars += stringLength + 1;
+ if (mHistoryTags != null) {
+ mHistoryTags.put(idx, key);
+ }
+ return idx | TAG_FIRST_OCCURRENCE_FLAG;
+ } else {
+ // Tag pool overflow: include the tag itself in the parcel
+ return HISTORY_TAG_INDEX_LIMIT | TAG_FIRST_OCCURRENCE_FLAG;
}
- return idx;
}
/*
@@ -3439,6 +3473,10 @@
// These upper bits are the frequently changing state bits.
static final int DELTA_STATE_MASK = 0xfe000000;
+ // Flag in history tag index: indicates that this is the first occurrence of this tag,
+ // therefore the tag value is written in the parcel
+ static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000;
+
// These are the pieces of battery state that are packed in to the upper bits of
// the state int that have been packed in to the first delta int. They must fit
// in STATE_BATTERY_MASK.
@@ -3556,11 +3594,23 @@
wakeReasonIndex = 0xffff;
}
dest.writeInt((wakeReasonIndex<<16) | wakeLockIndex);
+ if (cur.wakelockTag != null && (wakeLockIndex & TAG_FIRST_OCCURRENCE_FLAG) != 0) {
+ cur.wakelockTag.writeToParcel(dest, 0);
+ cur.tagsFirstOccurrence = true;
+ }
+ if (cur.wakeReasonTag != null && (wakeReasonIndex & TAG_FIRST_OCCURRENCE_FLAG) != 0) {
+ cur.wakeReasonTag.writeToParcel(dest, 0);
+ cur.tagsFirstOccurrence = true;
+ }
}
if (cur.eventCode != HistoryItem.EVENT_NONE) {
- int index = writeHistoryTag(cur.eventTag);
- int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
+ final int index = writeHistoryTag(cur.eventTag);
+ final int codeAndIndex = (cur.eventCode & 0xffff) | (index << 16);
dest.writeInt(codeAndIndex);
+ if ((index & TAG_FIRST_OCCURRENCE_FLAG) != 0) {
+ cur.eventTag.writeToParcel(dest, 0);
+ cur.tagsFirstOccurrence = true;
+ }
if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#"
+ cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+ cur.eventTag.string);
@@ -3750,6 +3800,7 @@
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
&& timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
&& (diffStates2&lastDiffStates2) == 0
+ && (!mHistoryLastWritten.tagsFirstOccurrence && !cur.tagsFirstOccurrence)
&& (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
&& (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
&& mHistoryLastWritten.stepDetails == null
@@ -3809,9 +3860,17 @@
mHistoryBuffer.setDataPosition(0);
mHistoryBuffer.setDataCapacity(mConstants.MAX_HISTORY_BUFFER / 2);
mHistoryBufferLastPos = -1;
+ mHistoryLastWritten.clear();
+ mHistoryLastLastWritten.clear();
+
+ // Mark every entry in the pool with a flag indicating that the tag
+ // has not yet been encountered while writing the current history buffer.
+ for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) {
+ entry.setValue(entry.getValue() | TAG_FIRST_OCCURRENCE_FLAG);
+ }
+ startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
HistoryItem newItem = new HistoryItem();
newItem.setTo(cur);
- startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, newItem);
return;
}
@@ -3830,7 +3889,9 @@
}
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
mHistoryLastLastWritten.setTo(mHistoryLastWritten);
+ final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence;
mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur);
+ mHistoryLastWritten.tagsFirstOccurrence = hasTags;
mHistoryLastWritten.states &= mActiveHistoryStates;
mHistoryLastWritten.states2 &= mActiveHistoryStates2;
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
@@ -3839,6 +3900,7 @@
cur.wakeReasonTag = null;
cur.eventCode = HistoryItem.EVENT_NONE;
cur.eventTag = null;
+ cur.tagsFirstOccurrence = false;
if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+ " now " + mHistoryBuffer.dataPosition()
+ " size is now " + mHistoryBuffer.dataSize());
@@ -11281,7 +11343,6 @@
@Override
@UnsupportedAppUsage
public boolean startIteratingHistoryLocked() {
- mReadOverflow = false;
mBatteryStatsHistoryIterator = createBatteryStatsHistoryIterator();
return true;
}
@@ -11291,34 +11352,42 @@
*/
@VisibleForTesting
public BatteryStatsHistoryIterator createBatteryStatsHistoryIterator() {
- ArrayList<HistoryTag> tags = new ArrayList<>(mHistoryTagPool.size());
- for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) {
- final HistoryTag tag = entry.getKey();
- tag.poolIdx = entry.getValue();
- tags.add(tag);
- }
-
- return new BatteryStatsHistoryIterator(mBatteryStatsHistory, tags);
+ return new BatteryStatsHistoryIterator(mBatteryStatsHistory);
}
@Override
public int getHistoryStringPoolSize() {
- return mBatteryStatsHistoryIterator.getHistoryStringPoolSize();
+ return mHistoryTagPool.size();
}
@Override
public int getHistoryStringPoolBytes() {
- return mBatteryStatsHistoryIterator.getHistoryStringPoolBytes();
+ return mNumHistoryTagChars;
}
@Override
public String getHistoryTagPoolString(int index) {
- return mBatteryStatsHistoryIterator.getHistoryTagPoolString(index);
+ ensureHistoryTagArray();
+ HistoryTag historyTag = mHistoryTags.get(index);
+ return historyTag != null ? historyTag.string : null;
}
@Override
public int getHistoryTagPoolUid(int index) {
- return mBatteryStatsHistoryIterator.getHistoryTagPoolUid(index);
+ ensureHistoryTagArray();
+ HistoryTag historyTag = mHistoryTags.get(index);
+ return historyTag != null ? historyTag.uid : Process.INVALID_UID;
+ }
+
+ private void ensureHistoryTagArray() {
+ if (mHistoryTags != null) {
+ return;
+ }
+
+ mHistoryTags = new SparseArray<>(mHistoryTagPool.size());
+ for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) {
+ mHistoryTags.put(entry.getValue(), entry.getKey());
+ }
}
@Override
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index e9e489d..615ab63 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -31,7 +31,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Map;
/**
* Uses accumulated battery stats data and PowerCalculators to produce power
@@ -186,16 +185,7 @@
}
BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats;
- ArrayList<BatteryStats.HistoryTag> tags = new ArrayList<>(
- batteryStatsImpl.mHistoryTagPool.size());
- for (Map.Entry<BatteryStats.HistoryTag, Integer> entry :
- batteryStatsImpl.mHistoryTagPool.entrySet()) {
- final BatteryStats.HistoryTag tag = entry.getKey();
- tag.poolIdx = entry.getValue();
- tags.add(tag);
- }
-
- batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.mHistoryBuffer, tags);
+ batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.mHistoryBuffer);
}
return batteryUsageStatsBuilder.build();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c8d70a8..4f8b317 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -254,6 +254,8 @@
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.action.TETHERING_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
@@ -751,7 +753,16 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_writeContacts"
android:description="@string/permdesc_writeContacts"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows an application to set default account for new contacts.
+ <p> This permission is only granted to system applications fulfilling the Contacts app role.
+ <p>Protection level: internal|role
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"
+ android:protectionLevel="internal|role" />
<!-- ====================================================================== -->
<!-- Permissions for accessing user's calendar -->
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
index 263daf0..9c641e6 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
@@ -18,46 +18,65 @@
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Process;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Rule;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.File;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class BatteryStatsHistoryIteratorTest {
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
- @Rule
- public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+ private MockClock mMockClock = new MockClock();
+ private MockBatteryStatsImpl mBatteryStats;
+
+ @Before
+ public void setup() {
+ Context context = InstrumentationRegistry.getContext();
+
+ File historyDir = new File(context.getDataDir(), BatteryStatsHistory.HISTORY_DIR);
+ String[] files = historyDir.list();
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ new File(historyDir, files[i]).delete();
+ }
+ }
+ historyDir.delete();
+ mBatteryStats = new MockBatteryStatsImpl(mMockClock, historyDir);
+ }
@Test
public void testIterator() {
- MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
- batteryStats.setRecordAllHistoryLocked(true);
- batteryStats.forceRecordAllHistory();
+ mBatteryStats.setRecordAllHistoryLocked(true);
+ mBatteryStats.forceRecordAllHistory();
- mStatsRule.setTime(1000, 1000);
- batteryStats.setNoAutoReset(true);
+ mMockClock.realtime = 1000;
+ mMockClock.uptime = 1000;
+ mBatteryStats.setNoAutoReset(true);
- batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
/* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
1_000_000, 1_000_000);
- batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
/* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000,
2_000_000, 2_000_000);
- batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
- batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
+ mBatteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
+ mBatteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
final BatteryStatsHistoryIterator iterator =
- batteryStats.createBatteryStatsHistoryIterator();
+ mBatteryStats.createBatteryStatsHistoryIterator();
BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
@@ -96,6 +115,57 @@
assertThat(iterator.next(item)).isFalse();
}
+ // Test history that spans multiple buffers and uses more than 32k different strings.
+ @Test
+ public void tagsLongHistory() {
+ mBatteryStats.setRecordAllHistoryLocked(true);
+ mBatteryStats.forceRecordAllHistory();
+
+ mMockClock.realtime = 1000;
+ mMockClock.uptime = 1000;
+ mBatteryStats.setNoAutoReset(true);
+
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
+ 1_000_000, 1_000_000);
+
+ // More than 32k strings
+ final int eventCount = 0x7FFF + 100;
+ for (int i = 0; i < eventCount; i++) {
+ mBatteryStats.noteAlarmStartLocked("a" + i, null, APP_UID, 3_000_000, 2_000_000);
+ }
+
+ final BatteryStatsHistoryIterator iterator =
+ mBatteryStats.createBatteryStatsHistoryIterator();
+
+ BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+ assertThat(iterator.next(item)).isTrue();
+ assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_RESET);
+ assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_NONE);
+ assertThat(item.eventTag).isNull();
+
+ assertThat(iterator.next(item)).isTrue();
+ assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_UPDATE);
+ assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_NONE);
+ assertThat(item.eventTag).isNull();
+ assertThat(item.time).isEqualTo(1_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_UPDATE);
+ assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_NONE);
+ assertThat(item.eventTag).isNull();
+ assertThat(item.time).isEqualTo(2_000_000);
+
+ for (int i = 0; i < eventCount; i++) {
+ assertThat(iterator.next(item)).isTrue();
+ assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_ALARM
+ | BatteryStats.HistoryItem.EVENT_FLAG_START);
+ assertThat(item.eventTag.string).isEqualTo("a" + i);
+ }
+
+ assertThat(iterator.next(item)).isFalse();
+ }
+
private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
String tag, int uid, int batteryChargeUah, int batteryLevel,
long elapsedTimeMs) {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
index 74b6dbe..7db31fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -163,6 +163,73 @@
assertThat(iterator.next(item)).isFalse();
}
+ @Test
+ public void testWriteAndReadHistoryTags() {
+ MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+ batteryStats.setRecordAllHistoryLocked(true);
+ batteryStats.forceRecordAllHistory();
+
+ batteryStats.setNoAutoReset(true);
+
+ mStatsRule.setTime(1_000_000, 1_000_000);
+
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
+ 1_000_000, 1_000_000);
+
+ // Add a large number of different history tags with strings of increasing length.
+ // These long strings will overflow the history buffer, at which point
+ // history will be written to disk and a new buffer started.
+ // As a result, we will only see a tail end of the sequence of events included
+ // in history.
+ for (int i = 1; i < 200; i++) {
+ StringBuilder sb = new StringBuilder().append(i).append(" ");
+ for (int j = 0; j <= i; j++) {
+ sb.append("word ");
+ }
+ batteryStats.noteJobStartLocked(sb.toString(), i);
+ }
+
+ Context context = InstrumentationRegistry.getContext();
+ BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, batteryStats);
+
+ final BatteryUsageStats batteryUsageStats =
+ provider.getBatteryUsageStats(
+ new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
+
+ Parcel parcel = Parcel.obtain();
+ batteryUsageStats.writeToParcel(parcel, 0);
+
+ assertThat(parcel.dataSize()).isAtMost(128_000);
+
+ parcel.setDataPosition(0);
+ BatteryUsageStats unparceled = BatteryUsageStats.CREATOR.createFromParcel(parcel);
+
+ BatteryStatsHistoryIterator iterator = unparceled.iterateBatteryStatsHistory();
+ BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+
+ assertThat(iterator.next(item)).isTrue();
+ assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_CURRENT_TIME);
+
+ int lastUid = 0;
+ while (iterator.next(item)) {
+ int uid = item.eventTag.uid;
+ // We expect the history buffer to have been reset in the middle of the run because
+ // there were many different history tags written, exceeding the limit of 128k.
+ assertThat(uid).isGreaterThan(150);
+ assertThat(item.eventCode).isEqualTo(
+ BatteryStats.HistoryItem.EVENT_JOB | BatteryStats.HistoryItem.EVENT_FLAG_START);
+ assertThat(item.eventTag.string).startsWith(uid + " ");
+ assertThat(item.batteryChargeUah).isEqualTo(3_600_000);
+ assertThat(item.batteryLevel).isEqualTo(90);
+ assertThat(item.time).isEqualTo((long) 1_000_000);
+
+ lastUid = uid;
+ }
+
+ assertThat(lastUid).isEqualTo(199);
+ }
+
private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) {
assertThat(item.cmd).isEqualTo(command);
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index d57eb65a..b31587b 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -27,6 +27,7 @@
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
import com.android.internal.power.MeasuredEnergyStats;
+import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
@@ -36,13 +37,19 @@
* Mocks a BatteryStatsImpl object.
*/
public class MockBatteryStatsImpl extends BatteryStatsImpl {
- public Clock mClock;
public boolean mForceOnBattery;
private NetworkStats mNetworkStats;
+ MockBatteryStatsImpl() {
+ this(new MockClock());
+ }
+
MockBatteryStatsImpl(Clock clock) {
- super(clock);
- this.mClock = mClock;
+ this(clock, null);
+ }
+
+ MockBatteryStatsImpl(Clock clock, File historyDirectory) {
+ super(clock, historyDirectory);
initTimersAndCounters();
setExternalStatsSyncLocked(new DummyExternalStatsSync());
@@ -53,10 +60,6 @@
};
}
- MockBatteryStatsImpl() {
- this(new MockClock());
- }
-
public void initMeasuredEnergyStats(String[] customBucketNames) {
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 5858e39..b77865f 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -312,7 +312,10 @@
}
/**
- * Offsets the Outline by (dx,dy)
+ * Offsets the Outline by (dx,dy). Offsetting is cumulative, so additional calls to
+ * offset() will add to previous offset values. Offset only applies to the current
+ * geometry (setRect(), setPath(), etc.); setting new geometry resets any existing
+ * offset.
*/
public void offset(int dx, int dy) {
if (mMode == MODE_ROUND_RECT) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 990d7b6..bdf703c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -39,11 +39,12 @@
return 1;
}
- @Override
- public boolean isWindowLayoutComponentAvailable() {
- return true;
- }
-
+ /**
+ * Returns a reference implementation of {@link WindowLayoutComponent} if available,
+ * {@code null} otherwise. The implementation must match the API level reported in
+ * {@link WindowExtensions#getWindowLayoutComponent()}.
+ * @return {@link WindowLayoutComponent} OEM implementation
+ */
@Override
public WindowLayoutComponent getWindowLayoutComponent() {
if (mWindowLayoutComponent == null) {
@@ -58,24 +59,10 @@
}
/**
- * Returns {@code true} if {@link ActivityEmbeddingComponent} is present on the device,
- * {@code false} otherwise. If the component is not available the developer will receive a
- * single callback with empty data or default values where possible.
- */
- @Override
- public boolean isEmbeddingComponentAvailable() {
- return true;
- }
-
- /**
- * Returns the OEM implementation of {@link ActivityEmbeddingComponent} if it is supported on
- * the device. The implementation must match the API level reported in
- * {@link androidx.window.extensions.WindowExtensions}. An
- * {@link UnsupportedOperationException} will be thrown if the device does not support
- * Activity Embedding. Use
- * {@link WindowExtensions#isEmbeddingComponentAvailable()} to determine if
- * {@link ActivityEmbeddingComponent} is present.
- * @return the OEM implementation of {@link ActivityEmbeddingComponent}
+ * Returns a reference implementation of {@link ActivityEmbeddingComponent} if available,
+ * {@code null} otherwise. The implementation must match the API level reported in
+ * {@link WindowExtensions#getWindowLayoutComponent()}.
+ * @return {@link ActivityEmbeddingComponent} OEM implementation.
*/
@NonNull
public ActivityEmbeddingComponent getActivityEmbeddingComponent() {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 25292b9..81be21c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -252,7 +252,8 @@
// Getting the parent bounds using the updated container - it will have the recent value.
final Rect parentBounds = getParentContainerBounds(updatedContainer);
final SplitRule rule = splitContainer.getSplitRule();
- final Activity activity = splitContainer.getPrimaryContainer().getTopNonFinishingActivity();
+ final TaskFragmentContainer primaryContainer = splitContainer.getPrimaryContainer();
+ final Activity activity = primaryContainer.getTopNonFinishingActivity();
if (activity == null) {
return;
}
@@ -264,10 +265,12 @@
// If the task fragments are not registered yet, the positions will be updated after they
// are created again.
- resizeTaskFragmentIfRegistered(wct, splitContainer.getPrimaryContainer(),
- primaryRectBounds);
- resizeTaskFragmentIfRegistered(wct, splitContainer.getSecondaryContainer(),
- secondaryRectBounds);
+ resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
+ final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
+ resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
+
+ setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
+ secondaryContainer.getTaskFragmentToken(), rule);
}
/**
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 42e829e..4f36c9c 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/res/color/unfold_transition_background.xml b/libs/WindowManager/Shell/res/color/unfold_transition_background.xml
new file mode 100644
index 0000000..63289a3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/unfold_transition_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Matches taskbar color -->
+ <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+</selector>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
deleted file mode 100644
index 006730d..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2020 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.wm.shell;
-
-import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
-import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
-
-import android.app.ActivityManager;
-import android.graphics.Point;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.SurfaceControl;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.transition.Transitions;
-
-import java.io.PrintWriter;
-
-/**
- * Organizes tasks presented in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN}.
- */
-public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
- private static final String TAG = "FullscreenTaskListener";
-
- private final SyncTransactionQueue mSyncQueue;
-
- private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>();
-
- public FullscreenTaskListener(SyncTransactionQueue syncQueue) {
- mSyncQueue = syncQueue;
- }
-
- @Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mDataByTaskId.get(taskInfo.taskId) != null) {
- throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
- }
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
- taskInfo.taskId);
- final Point positionInParent = taskInfo.positionInParent;
- mDataByTaskId.put(taskInfo.taskId, new TaskData(leash, positionInParent));
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- mSyncQueue.runInSync(t -> {
- // Reset several properties back to fullscreen (PiP, for example, leaves all these
- // properties in a bad state).
- t.setWindowCrop(leash, null);
- t.setPosition(leash, positionInParent.x, positionInParent.y);
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
- });
- }
-
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
- final TaskData data = mDataByTaskId.get(taskInfo.taskId);
- final Point positionInParent = taskInfo.positionInParent;
- if (!positionInParent.equals(data.positionInParent)) {
- data.positionInParent.set(positionInParent.x, positionInParent.y);
- mSyncQueue.runInSync(t -> {
- t.setPosition(data.surface, positionInParent.x, positionInParent.y);
- });
- }
- }
-
- @Override
- public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- if (mDataByTaskId.get(taskInfo.taskId) == null) {
- Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
- return;
- }
- mDataByTaskId.remove(taskInfo.taskId);
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
- taskInfo.taskId);
- }
-
- @Override
- public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- if (!mDataByTaskId.contains(taskId)) {
- throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
- }
- b.setParent(mDataByTaskId.get(taskId).surface);
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- pw.println(prefix + this);
- pw.println(innerPrefix + mDataByTaskId.size() + " Tasks");
- }
-
- @Override
- public String toString() {
- return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
- }
-
- /**
- * Per-task data for each managed task.
- */
- private static class TaskData {
- public final SurfaceControl surface;
- public final Point positionInParent;
-
- public TaskData(SurfaceControl surface, Point positionInParent) {
- this.surface = surface;
- this.positionInParent = positionInParent;
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index df4f238..fa58fcd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -27,6 +27,8 @@
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
+import com.android.wm.shell.fullscreen.FullscreenTaskListener;
+import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -52,6 +54,7 @@
private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
+ private final Optional<FullscreenUnfoldController> mFullscreenUnfoldController;
private final Optional<FreeformTaskListener> mFreeformTaskListenerOptional;
private final ShellExecutor mMainExecutor;
private final Transitions mTransitions;
@@ -71,6 +74,7 @@
Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
+ Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
Transitions transitions,
StartingWindowController startingWindow,
@@ -86,6 +90,7 @@
mAppPairsOptional = appPairsOptional;
mFullscreenTaskListener = fullscreenTaskListener;
mPipTouchHandlerOptional = pipTouchHandlerOptional;
+ mFullscreenUnfoldController = fullscreenUnfoldTransitionController;
mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
mTransitions = transitions;
mMainExecutor = mainExecutor;
@@ -128,6 +133,8 @@
mFreeformTaskListenerOptional.ifPresent(f ->
mShellTaskOrganizer.addListenerForType(
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
+
+ mFullscreenUnfoldController.ifPresent(FullscreenUnfoldController::init);
}
@ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
new file mode 100644
index 0000000..3f17f2b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2020 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.wm.shell.fullscreen;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+
+import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
+import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.TaskInfo;
+import android.graphics.Point;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.view.SurfaceControl;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.transition.Transitions;
+
+import java.io.PrintWriter;
+import java.util.Optional;
+
+/**
+ * Organizes tasks presented in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN}.
+ */
+public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
+ private static final String TAG = "FullscreenTaskListener";
+
+ private final SyncTransactionQueue mSyncQueue;
+
+ private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>();
+ private final AnimatableTasksListener mAnimatableTasksListener = new AnimatableTasksListener();
+ private final FullscreenUnfoldController mFullscreenUnfoldController;
+
+ public FullscreenTaskListener(SyncTransactionQueue syncQueue,
+ Optional<FullscreenUnfoldController> unfoldController) {
+ mSyncQueue = syncQueue;
+ mFullscreenUnfoldController = unfoldController.orElse(null);
+ }
+
+ @Override
+ public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (mDataByTaskId.get(taskInfo.taskId) != null) {
+ throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
+ }
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
+ taskInfo.taskId);
+ final Point positionInParent = taskInfo.positionInParent;
+ mDataByTaskId.put(taskInfo.taskId, new TaskData(leash, positionInParent));
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
+ mSyncQueue.runInSync(t -> {
+ // Reset several properties back to fullscreen (PiP, for example, leaves all these
+ // properties in a bad state).
+ t.setWindowCrop(leash, null);
+ t.setPosition(leash, positionInParent.x, positionInParent.y);
+ t.setAlpha(leash, 1f);
+ t.setMatrix(leash, 1, 0, 0, 1);
+ t.show(leash);
+ });
+
+ mAnimatableTasksListener.onTaskAppeared(taskInfo);
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
+
+ mAnimatableTasksListener.onTaskInfoChanged(taskInfo);
+
+ final TaskData data = mDataByTaskId.get(taskInfo.taskId);
+ final Point positionInParent = taskInfo.positionInParent;
+ if (!positionInParent.equals(data.positionInParent)) {
+ data.positionInParent.set(positionInParent.x, positionInParent.y);
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(data.surface, positionInParent.x, positionInParent.y);
+ });
+ }
+ }
+
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ if (mDataByTaskId.get(taskInfo.taskId) == null) {
+ Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
+ return;
+ }
+
+ mAnimatableTasksListener.onTaskVanished(taskInfo);
+ mDataByTaskId.remove(taskInfo.taskId);
+
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
+ taskInfo.taskId);
+ }
+
+ @Override
+ public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ if (!mDataByTaskId.contains(taskId)) {
+ throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
+ }
+ b.setParent(mDataByTaskId.get(taskId).surface);
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + this);
+ pw.println(innerPrefix + mDataByTaskId.size() + " Tasks");
+ }
+
+ @Override
+ public String toString() {
+ return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
+ }
+
+ /**
+ * Per-task data for each managed task.
+ */
+ private static class TaskData {
+ public final SurfaceControl surface;
+ public final Point positionInParent;
+
+ public TaskData(SurfaceControl surface, Point positionInParent) {
+ this.surface = surface;
+ this.positionInParent = positionInParent;
+ }
+ }
+
+ class AnimatableTasksListener {
+ private final SparseBooleanArray mTaskIds = new SparseBooleanArray();
+
+ public void onTaskAppeared(RunningTaskInfo taskInfo) {
+ final boolean isApplicable = isAnimatable(taskInfo);
+ if (isApplicable) {
+ mTaskIds.put(taskInfo.taskId, true);
+
+ if (mFullscreenUnfoldController != null) {
+ SurfaceControl leash = mDataByTaskId.get(taskInfo.taskId).surface;
+ mFullscreenUnfoldController.onTaskAppeared(taskInfo, leash);
+ }
+ }
+ }
+
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ final boolean isCurrentlyApplicable = mTaskIds.get(taskInfo.taskId);
+ final boolean isApplicable = isAnimatable(taskInfo);
+
+ if (isCurrentlyApplicable) {
+ if (isApplicable) {
+ // Still applicable, send update
+ if (mFullscreenUnfoldController != null) {
+ mFullscreenUnfoldController.onTaskInfoChanged(taskInfo);
+ }
+ } else {
+ // Became inapplicable
+ if (mFullscreenUnfoldController != null) {
+ mFullscreenUnfoldController.onTaskVanished(taskInfo);
+ }
+ mTaskIds.put(taskInfo.taskId, false);
+ }
+ } else {
+ if (isApplicable) {
+ // Became applicable
+ mTaskIds.put(taskInfo.taskId, true);
+
+ if (mFullscreenUnfoldController != null) {
+ SurfaceControl leash = mDataByTaskId.get(taskInfo.taskId).surface;
+ mFullscreenUnfoldController.onTaskAppeared(taskInfo, leash);
+ }
+ }
+ }
+ }
+
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ final boolean isCurrentlyApplicable = mTaskIds.get(taskInfo.taskId);
+ if (isCurrentlyApplicable && mFullscreenUnfoldController != null) {
+ mFullscreenUnfoldController.onTaskVanished(taskInfo);
+ }
+ mTaskIds.put(taskInfo.taskId, false);
+ }
+
+ private boolean isAnimatable(TaskInfo taskInfo) {
+ // Filter all visible tasks that are not launcher tasks
+ // We do not animate launcher as it handles the animation by itself
+ return taskInfo != null && taskInfo.isVisible && taskInfo.getConfiguration()
+ .windowConfiguration.getActivityType() != ACTIVITY_TYPE_HOME;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
new file mode 100644
index 0000000..08ab85c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.fullscreen;
+
+import static android.graphics.Color.blue;
+import static android.graphics.Color.green;
+import static android.graphics.Color.red;
+import static android.util.MathUtils.lerp;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.animation.RectEvaluator;
+import android.animation.TypeEvaluator;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.util.SparseArray;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+
+import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.wm.shell.R;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
+import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
+import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Controls full screen app unfold transition: animating cropping window and scaling when
+ * folding or unfolding a foldable device.
+ */
+public final class FullscreenUnfoldController implements UnfoldListener,
+ OnInsetsChangedListener {
+
+ private static final float[] FLOAT_9 = new float[9];
+ private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect());
+
+ private static final float HORIZONTAL_START_MARGIN = 0.08f;
+ private static final float VERTICAL_START_MARGIN = 0.03f;
+ private static final float END_SCALE = 1f;
+ private static final float START_SCALE = END_SCALE - VERTICAL_START_MARGIN * 2;
+ private static final int BACKGROUND_LAYER_Z_INDEX = -1;
+
+ private final Context mContext;
+ private final Executor mExecutor;
+ private final ShellUnfoldProgressProvider mProgressProvider;
+ private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
+ private final DisplayInsetsController mDisplayInsetsController;
+
+ private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>();
+
+ private SurfaceControl mBackgroundLayer;
+ private InsetsSource mTaskbarInsetsSource;
+
+ private final float mWindowCornerRadiusPx;
+ private final float[] mBackgroundColor;
+ private final float mExpandedTaskBarHeight;
+
+ private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+
+ public FullscreenUnfoldController(
+ @NonNull Context context,
+ @NonNull Executor executor,
+ @NonNull ShellUnfoldProgressProvider progressProvider,
+ @NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ @NonNull DisplayInsetsController displayInsetsController
+ ) {
+ mContext = context;
+ mExecutor = executor;
+ mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
+ mProgressProvider = progressProvider;
+ mDisplayInsetsController = displayInsetsController;
+ mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context);
+ mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.taskbar_frame_height);
+ mBackgroundColor = getBackgroundColor();
+ }
+
+ /**
+ * Initializes the controller
+ */
+ public void init() {
+ mProgressProvider.addListener(mExecutor, this);
+ mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this);
+ }
+
+ @Override
+ public void onStateChangeProgress(float progress) {
+ if (mAnimationContextByTaskId.size() == 0) return;
+
+ ensureBackground();
+
+ for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
+ final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
+
+ context.mCurrentCropRect.set(RECT_EVALUATOR
+ .evaluate(progress, context.mStartCropRect, context.mEndCropRect));
+
+ float scale = lerp(START_SCALE, END_SCALE, progress);
+ context.mMatrix.setScale(scale, scale, context.mCurrentCropRect.exactCenterX(),
+ context.mCurrentCropRect.exactCenterY());
+
+ mTransaction.setWindowCrop(context.mLeash, context.mCurrentCropRect)
+ .setMatrix(context.mLeash, context.mMatrix, FLOAT_9)
+ .setCornerRadius(context.mLeash, mWindowCornerRadiusPx);
+ }
+
+ mTransaction.apply();
+ }
+
+ @Override
+ public void onStateChangeFinished() {
+ for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
+ final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
+ resetSurface(context);
+ }
+
+ removeBackground();
+ mTransaction.apply();
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ mTaskbarInsetsSource = insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
+ AnimationContext context = mAnimationContextByTaskId.valueAt(i);
+ context.update(mTaskbarInsetsSource, context.mTaskInfo);
+ }
+ }
+
+ /**
+ * Called when a new matching task appeared
+ */
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+ AnimationContext animationContext = new AnimationContext(leash, mTaskbarInsetsSource,
+ taskInfo);
+ mAnimationContextByTaskId.put(taskInfo.taskId, animationContext);
+ }
+
+ /**
+ * Called when matching task changed
+ */
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
+ if (animationContext != null) {
+ animationContext.update(mTaskbarInsetsSource, taskInfo);
+ }
+ }
+
+ /**
+ * Called when matching task vanished
+ */
+ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
+ if (animationContext != null) {
+ resetSurface(animationContext);
+ mAnimationContextByTaskId.remove(taskInfo.taskId);
+ }
+
+ if (mAnimationContextByTaskId.size() == 0) {
+ removeBackground();
+ }
+
+ mTransaction.apply();
+ }
+
+ private void resetSurface(AnimationContext context) {
+ mTransaction
+ .setWindowCrop(context.mLeash, null)
+ .setCornerRadius(context.mLeash, 0.0F)
+ .setMatrix(context.mLeash, 1.0F, 0.0F, 0.0F, 1.0F)
+ .setPosition(context.mLeash,
+ (float) context.mTaskInfo.positionInParent.x,
+ (float) context.mTaskInfo.positionInParent.y);
+ }
+
+ private void ensureBackground() {
+ if (mBackgroundLayer != null) return;
+
+ SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder()
+ .setName("app-unfold-background")
+ .setCallsite("AppUnfoldTransitionController")
+ .setColorLayer();
+ mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder);
+ mBackgroundLayer = colorLayerBuilder.build();
+
+ mTransaction
+ .setColor(mBackgroundLayer, mBackgroundColor)
+ .show(mBackgroundLayer)
+ .setLayer(mBackgroundLayer, BACKGROUND_LAYER_Z_INDEX);
+ }
+
+ private void removeBackground() {
+ if (mBackgroundLayer == null) return;
+ if (mBackgroundLayer.isValid()) {
+ mTransaction.remove(mBackgroundLayer);
+ }
+ mBackgroundLayer = null;
+ }
+
+ private float[] getBackgroundColor() {
+ int colorInt = mContext.getResources().getColor(R.color.unfold_transition_background);
+ return new float[]{
+ (float) red(colorInt) / 255.0F,
+ (float) green(colorInt) / 255.0F,
+ (float) blue(colorInt) / 255.0F
+ };
+ }
+
+ private class AnimationContext {
+ final SurfaceControl mLeash;
+ final Rect mStartCropRect = new Rect();
+ final Rect mEndCropRect = new Rect();
+ final Rect mCurrentCropRect = new Rect();
+ final Matrix mMatrix = new Matrix();
+
+ TaskInfo mTaskInfo;
+
+ private AnimationContext(SurfaceControl leash,
+ InsetsSource taskBarInsetsSource,
+ TaskInfo taskInfo) {
+ this.mLeash = leash;
+ update(taskBarInsetsSource, taskInfo);
+ }
+
+ private void update(InsetsSource taskBarInsetsSource, TaskInfo taskInfo) {
+ mTaskInfo = taskInfo;
+ mStartCropRect.set(mTaskInfo.getConfiguration().windowConfiguration.getBounds());
+
+ if (taskBarInsetsSource != null) {
+ // Only insets the cropping window with task bar when it's expanded
+ if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
+ mStartCropRect.inset(taskBarInsetsSource
+ .calculateVisibleInsets(mStartCropRect));
+ }
+ }
+
+ mEndCropRect.set(mStartCropRect);
+
+ int horizontalMargin = (int) (mEndCropRect.width() * HORIZONTAL_START_MARGIN);
+ mStartCropRect.left = mEndCropRect.left + horizontalMargin;
+ mStartCropRect.right = mEndCropRect.right - horizontalMargin;
+ int verticalMargin = (int) (mEndCropRect.height() * VERTICAL_START_MARGIN);
+ mStartCropRect.top = mEndCropRect.top + verticalMargin;
+ mStartCropRect.bottom = mEndCropRect.bottom - verticalMargin;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java
new file mode 100644
index 0000000..74e4812
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.unfold;
+
+import android.annotation.FloatRange;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Wrapper interface for unfold transition progress provider for the Shell
+ * @see com.android.systemui.unfold.UnfoldTransitionProgressProvider
+ */
+public interface ShellUnfoldProgressProvider {
+
+ /**
+ * Adds a transition listener
+ */
+ void addListener(Executor executor, UnfoldListener listener);
+
+ /**
+ * Listener for receiving unfold updates
+ */
+ interface UnfoldListener {
+ default void onStateChangeStarted() {}
+
+ default void onStateChangeProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
+
+ default void onStateChangeFinished() {}
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
new file mode 100644
index 0000000..d6f7e54
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.fullscreen;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.WindowConfiguration;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+@SmallTest
+public class FullscreenTaskListenerTest {
+
+ @Mock
+ private SyncTransactionQueue mSyncQueue;
+ @Mock
+ private FullscreenUnfoldController mUnfoldController;
+ @Mock
+ private SurfaceControl mSurfaceControl;
+
+ private Optional<FullscreenUnfoldController> mFullscreenUnfoldController;
+
+ private FullscreenTaskListener mListener;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mFullscreenUnfoldController = Optional.of(mUnfoldController);
+ mListener = new FullscreenTaskListener(mSyncQueue, mFullscreenUnfoldController);
+ }
+
+ @Test
+ public void testAnimatableTaskAppeared_notifiesUnfoldController() {
+ RunningTaskInfo info = createTaskInfo(/* visible */ true, /* taskId */ 0);
+
+ mListener.onTaskAppeared(info, mSurfaceControl);
+
+ verify(mUnfoldController).onTaskAppeared(eq(info), any());
+ }
+
+ @Test
+ public void testMultipleAnimatableTasksAppeared_notifiesUnfoldController() {
+ RunningTaskInfo animatable1 = createTaskInfo(/* visible */ true, /* taskId */ 0);
+ RunningTaskInfo animatable2 = createTaskInfo(/* visible */ true, /* taskId */ 1);
+
+ mListener.onTaskAppeared(animatable1, mSurfaceControl);
+ mListener.onTaskAppeared(animatable2, mSurfaceControl);
+
+ InOrder order = inOrder(mUnfoldController);
+ order.verify(mUnfoldController).onTaskAppeared(eq(animatable1), any());
+ order.verify(mUnfoldController).onTaskAppeared(eq(animatable2), any());
+ }
+
+ @Test
+ public void testNonAnimatableTaskAppeared_doesNotNotifyUnfoldController() {
+ RunningTaskInfo info = createTaskInfo(/* visible */ false, /* taskId */ 0);
+
+ mListener.onTaskAppeared(info, mSurfaceControl);
+
+ verifyNoMoreInteractions(mUnfoldController);
+ }
+
+ @Test
+ public void testNonAnimatableTaskChanged_doesNotNotifyUnfoldController() {
+ RunningTaskInfo info = createTaskInfo(/* visible */ false, /* taskId */ 0);
+ mListener.onTaskAppeared(info, mSurfaceControl);
+
+ mListener.onTaskInfoChanged(info);
+
+ verifyNoMoreInteractions(mUnfoldController);
+ }
+
+ @Test
+ public void testNonAnimatableTaskVanished_doesNotNotifyUnfoldController() {
+ RunningTaskInfo info = createTaskInfo(/* visible */ false, /* taskId */ 0);
+ mListener.onTaskAppeared(info, mSurfaceControl);
+
+ mListener.onTaskVanished(info);
+
+ verifyNoMoreInteractions(mUnfoldController);
+ }
+
+ @Test
+ public void testAnimatableTaskBecameInactive_notifiesUnfoldController() {
+ RunningTaskInfo animatableTask = createTaskInfo(/* visible */ true, /* taskId */ 0);
+ mListener.onTaskAppeared(animatableTask, mSurfaceControl);
+ RunningTaskInfo notAnimatableTask = createTaskInfo(/* visible */ false, /* taskId */ 0);
+
+ mListener.onTaskInfoChanged(notAnimatableTask);
+
+ verify(mUnfoldController).onTaskVanished(eq(notAnimatableTask));
+ }
+
+ @Test
+ public void testAnimatableTaskVanished_notifiesUnfoldController() {
+ RunningTaskInfo taskInfo = createTaskInfo(/* visible */ true, /* taskId */ 0);
+ mListener.onTaskAppeared(taskInfo, mSurfaceControl);
+
+ mListener.onTaskVanished(taskInfo);
+
+ verify(mUnfoldController).onTaskVanished(eq(taskInfo));
+ }
+
+ private RunningTaskInfo createTaskInfo(boolean visible, int taskId) {
+ final RunningTaskInfo info = spy(new RunningTaskInfo());
+ info.isVisible = visible;
+ info.positionInParent = new Point();
+ when(info.getWindowingMode()).thenReturn(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+ final Configuration configuration = new Configuration();
+ configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+ when(info.getConfiguration()).thenReturn(configuration);
+ info.taskId = taskId;
+ return info;
+ }
+}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 9a82ab1..49477b9 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -28,6 +28,7 @@
import android.os.Build;
import android.os.Process;
import android.os.SystemProperties;
+import android.sysprop.MediaProperties;
import android.util.Log;
import android.util.Pair;
import android.util.Range;
@@ -196,13 +197,20 @@
private static final Range<Rational> POSITIVE_RATIONALS =
Range.create(new Rational(1, Integer.MAX_VALUE),
new Rational(Integer.MAX_VALUE, 1));
- private static final Range<Integer> SIZE_RANGE =
- Process.is64Bit() ? Range.create(1, 32768) : Range.create(1, 4096);
private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000);
private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256;
+ private static final class LazyHolder {
+ private static final Range<Integer> SIZE_RANGE = Process.is64Bit()
+ ? Range.create(1, 32768)
+ : Range.create(1, MediaProperties.resolution_limit_32bit().orElse(4096));
+ }
+ private static Range<Integer> getSizeRange() {
+ return LazyHolder.SIZE_RANGE;
+ }
+
// found stuff that is not supported by framework (=> this should not happen)
private static final int ERROR_UNRECOGNIZED = (1 << 0);
// found profile/level for which we don't have capability estimates
@@ -2234,12 +2242,12 @@
private void initWithPlatformLimits() {
mBitrateRange = BITRATE_RANGE;
- mWidthRange = SIZE_RANGE;
- mHeightRange = SIZE_RANGE;
+ mWidthRange = getSizeRange();
+ mHeightRange = getSizeRange();
mFrameRateRange = FRAME_RATE_RANGE;
- mHorizontalBlockRange = SIZE_RANGE;
- mVerticalBlockRange = SIZE_RANGE;
+ mHorizontalBlockRange = getSizeRange();
+ mVerticalBlockRange = getSizeRange();
// full positive ranges are supported as these get calculated
mBlockCountRange = POSITIVE_INTEGERS;
@@ -2253,7 +2261,7 @@
mHeightAlignment = 2;
mBlockWidth = 2;
mBlockHeight = 2;
- mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
+ mSmallerDimensionUpperLimit = getSizeRange().getUpper();
}
private @Nullable List<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
@@ -2494,10 +2502,10 @@
// codec supports profiles that we don't know.
// Use supplied values clipped to platform limits
if (widths != null) {
- mWidthRange = SIZE_RANGE.intersect(widths);
+ mWidthRange = getSizeRange().intersect(widths);
}
if (heights != null) {
- mHeightRange = SIZE_RANGE.intersect(heights);
+ mHeightRange = getSizeRange().intersect(heights);
}
if (counts != null) {
mBlockCountRange = POSITIVE_INTEGERS.intersect(
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 458821e..60d21c0 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -1073,16 +1073,24 @@
@UnsupportedAppUsage
private native byte[] getEmbeddedPicture(int pictureType);
+ /**
+ * Releases any acquired resources. Call it when done with the object.
+ *
+ * @throws IOException When an {@link IOException} is thrown while closing a {@link
+ * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}.
+ */
@Override
- public void close() {
+ public void close() throws IOException {
release();
}
/**
- * Call it when one is done with the object. This method releases the memory
- * allocated internally.
+ * Releases any acquired resources. Call it when done with the object.
+ *
+ * @throws IOException When an {@link IOException} is thrown while closing a {@link
+ * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}.
*/
- public native void release();
+ public native void release() throws IOException;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private native void native_setup();
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
index 380de9c..da106be 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
@@ -19,120 +19,138 @@
import android.media.MediaMetadataRetriever;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import com.android.mediaframeworktest.MediaNames;
import com.android.mediaframeworktest.MediaProfileReader;
-/**
- * This metadata test suite test the basic functionality of the
- * MediaMetadataRetriever
- *
- */
+
+import java.io.IOException;
+
+/** This metadata test suite test the basic functionality of the MediaMetadataRetriever */
public class MediaMetadataTest extends AndroidTestCase {
-
+
private static final String TAG = "MediaMetadataTest";
- public static enum METADATA_EXPECTEDRESULT{
- FILE_PATH,CD_TRACK, ALBUM,
- ARTIST, AUTHOR, COMPOSER,
- DATE, GENRE, TITLE,
- YEAR, DURATION, NUM_TRACKS, WRITER
+ public enum METADATA_EXPECTEDRESULT {
+ FILE_PATH,
+ CD_TRACK,
+ ALBUM,
+ ARTIST,
+ AUTHOR,
+ COMPOSER,
+ DATE,
+ GENRE,
+ TITLE,
+ YEAR,
+ DURATION,
+ NUM_TRACKS,
+ WRITER
}
-
- public static enum MP3_TEST_FILE{
- ID3V1V2, ID3V2, ID3V1
+
+ public enum MP3_TEST_FILE {
+ ID3V1V2,
+ ID3V2,
+ ID3V1
}
-
+
public static METADATA_EXPECTEDRESULT meta;
public static MP3_TEST_FILE mp3_test_file;
-
+
@MediumTest
public static void testID3V1V2Metadata() throws Exception {
validateMetatData(mp3_test_file.ID3V1V2.ordinal(), MediaNames.META_DATA_MP3);
}
-
+
@MediumTest
public static void testID3V2Metadata() throws Exception {
validateMetatData(mp3_test_file.ID3V2.ordinal(), MediaNames.META_DATA_MP3);
}
-
+
@MediumTest
public static void testID3V1Metadata() throws Exception {
validateMetatData(mp3_test_file.ID3V1.ordinal(), MediaNames.META_DATA_MP3);
}
- private static void validateMetatData(int fileIndex, String meta_data_file[][]) {
- Log.v(TAG, "filePath = "+ meta_data_file[fileIndex][0]);
- if ((meta_data_file[fileIndex][0].endsWith("wma") && !MediaProfileReader.getWMAEnable()) ||
- (meta_data_file[fileIndex][0].endsWith("wmv") && !MediaProfileReader.getWMVEnable())) {
+ private static void validateMetatData(int fileIndex, String[][] metadataFile)
+ throws IOException {
+ Log.v(TAG, "filePath = " + metadataFile[fileIndex][0]);
+ if ((metadataFile[fileIndex][0].endsWith("wma") && !MediaProfileReader.getWMAEnable())
+ || (metadataFile[fileIndex][0].endsWith("wmv")
+ && !MediaProfileReader.getWMVEnable())) {
return;
}
String value = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
- retriever.setDataSource(meta_data_file[fileIndex][0]);
- } catch(Exception e) {
- Log.v(TAG, "Failed: "+meta_data_file[fileIndex][0] + " " + e.toString());
- //Set the test case failure whenever it failed to setDataSource
+ retriever.setDataSource(metadataFile[fileIndex][0]);
+ } catch (Exception e) {
+ Log.v(TAG, "Failed: " + metadataFile[fileIndex][0] + " " + e.toString());
+ // Set the test case failure whenever it failed to setDataSource
assertTrue("Failed to setDataSource ", false);
}
-
- //METADATA_KEY_CD_TRACK_NUMBER should return the TCRK value
+
+ // METADATA_KEY_CD_TRACK_NUMBER should return the TCRK value
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER);
Log.v(TAG, "CD_TRACK_NUMBER : " + value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.CD_TRACK.ordinal()], value);
-
+ assertEquals(TAG, metadataFile[fileIndex][meta.CD_TRACK.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
- Log.v(TAG, "Album : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.ALBUM.ordinal()], value);
-
+ Log.v(TAG, "Album : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.ALBUM.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
- Log.v(TAG, "Artist : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.ARTIST.ordinal()], value);
-
+ Log.v(TAG, "Artist : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.ARTIST.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_AUTHOR);
- Log.v(TAG, "Author : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.AUTHOR.ordinal()], value);
-
+ Log.v(TAG, "Author : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.AUTHOR.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER);
- Log.v(TAG, "Composer : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.COMPOSER.ordinal()], value);
-
+ Log.v(TAG, "Composer : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.COMPOSER.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE);
- Log.v(TAG, "Date : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.DATE.ordinal()], value);
-
+ Log.v(TAG, "Date : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.DATE.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
- Log.v(TAG, "Genre : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.GENRE.ordinal()], value);
-
+ Log.v(TAG, "Genre : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.GENRE.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
- Log.v(TAG, "Title : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.TITLE.ordinal()], value);
-
+ Log.v(TAG, "Title : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.TITLE.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
- Log.v(TAG, "Year : "+ value);
- assertEquals(TAG, meta_data_file[fileIndex][meta.YEAR.ordinal()], value);
-
+ Log.v(TAG, "Year : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.YEAR.ordinal()], value);
+
value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
- Log.v(TAG, "Expected = " + meta_data_file[fileIndex][meta.DURATION.ordinal()] + "reult = " + value);
+ Log.v(
+ TAG,
+ "Expected = "
+ + metadataFile[fileIndex][meta.DURATION.ordinal()]
+ + "reult = "
+ + value);
// Only require that the returned duration is within 100ms of the expected
// one as PV and stagefright differ slightly in their implementation.
- assertTrue(TAG, Math.abs(Integer.parseInt(
- meta_data_file[fileIndex][meta.DURATION.ordinal()])
- - Integer.parseInt(value)) < 100);
-
- //METADATA_KEY_NUM_TRACKS should return the total number of tracks in the media
- //include the video and audio
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS);
- Log.v(TAG, "Track : "+ value);
- assertEquals(TAG,meta_data_file[fileIndex][meta.NUM_TRACKS.ordinal()], value);
-
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER);
- Log.v(TAG, "Writer : "+ value);
- assertEquals(TAG,meta_data_file[fileIndex][meta.WRITER.ordinal()], value);
+ int durationDifferenceMs =
+ Math.abs(
+ Integer.parseInt(metadataFile[fileIndex][meta.DURATION.ordinal()])
+ - Integer.parseInt(value));
+ assertTrue(TAG, durationDifferenceMs < 100);
- retriever.release();
+ // METADATA_KEY_NUM_TRACKS should return the total number of tracks in the media
+ // include the video and audio
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS);
+ Log.v(TAG, "Track : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.NUM_TRACKS.ordinal()], value);
+
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER);
+ Log.v(TAG, "Writer : " + value);
+ assertEquals(TAG, metadataFile[fileIndex][meta.WRITER.ordinal()], value);
+
+ retriever.release();
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index 8eb75f3..bdca474 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -16,19 +16,23 @@
package com.android.mediaframeworktest.unit;
-import android.util.Log;
-import android.media.MediaMetadataRetriever;
import android.graphics.Bitmap;
-import java.io.FileOutputStream;
+import android.media.MediaMetadataRetriever;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+
import com.android.mediaframeworktest.MediaNames;
import com.android.mediaframeworktest.MediaProfileReader;
-import android.test.suitebuilder.annotation.*;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
public class MediaMetadataRetrieverTest extends AndroidTestCase {
-
- private static final String TAG = "MediaMetadataRetrieverTest";
-
+
+ private static final String TAG = "MediaMetadataRetrieverTest";
+
// Test album art extraction.
@MediumTest
public static void testGetEmbeddedPicture() throws Exception {
@@ -40,10 +44,12 @@
for (int i = 0, n = MediaNames.ALBUMART_TEST_FILES.length; i < n; ++i) {
try {
Log.v(TAG, "File " + i + ": " + MediaNames.ALBUMART_TEST_FILES[i]);
- if ((MediaNames.ALBUMART_TEST_FILES[i].endsWith(".wma") && !supportWMA) ||
- (MediaNames.ALBUMART_TEST_FILES[i].endsWith(".wmv") && !supportWMV)
- ) {
- Log.v(TAG, "windows media is not supported and thus we will skip the test for this file");
+ if ((MediaNames.ALBUMART_TEST_FILES[i].endsWith(".wma") && !supportWMA)
+ || (MediaNames.ALBUMART_TEST_FILES[i].endsWith(".wmv") && !supportWMV)) {
+ Log.v(
+ TAG,
+ "windows media is not supported and thus we will skip the test for this"
+ + " file");
continue;
}
retriever.setDataSource(MediaNames.ALBUMART_TEST_FILES[i]);
@@ -52,15 +58,18 @@
// TODO:
// A better test would be to compare the retrieved album art with the
// known result.
- if (albumArt == null) { // Do we have expect in JUnit?
- Log.e(TAG, "Fails to get embedded picture for " + MediaNames.ALBUMART_TEST_FILES[i]);
+ if (albumArt == null) { // Do we have expect in JUnit?
+ Log.e(
+ TAG,
+ "Fails to get embedded picture for "
+ + MediaNames.ALBUMART_TEST_FILES[i]);
hasFailed = true;
}
- } catch(Exception e) {
+ } catch (Exception e) {
Log.e(TAG, "Fails to setDataSource for " + MediaNames.ALBUMART_TEST_FILES[i]);
hasFailed = true;
}
- Thread.yield(); // Don't be evil
+ Thread.yield(); // Don't be evil
}
retriever.release();
Log.v(TAG, "testGetEmbeddedPicture completes.");
@@ -76,61 +85,82 @@
boolean hasFailed = false;
Log.v(TAG, "Thumbnail processing starts");
long startedAt = System.currentTimeMillis();
- for(int i = 0, n = MediaNames.THUMBNAIL_METADATA_TEST_FILES.length; i < n; ++i) {
+ for (int i = 0, n = MediaNames.THUMBNAIL_METADATA_TEST_FILES.length; i < n; ++i) {
try {
Log.v(TAG, "File " + i + ": " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
- if ((MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wma") && !supportWMA) ||
- (MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wmv") && !supportWMV)
- ) {
- Log.v(TAG, "windows media is not supported and thus we will skip the test for this file");
+ if ((MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wma") && !supportWMA)
+ || (MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wmv")
+ && !supportWMV)) {
+ Log.v(
+ TAG,
+ "windows media is not supported and thus we will skip the test for this"
+ + " file");
continue;
}
retriever.setDataSource(MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
Bitmap bitmap = retriever.getFrameAtTime(-1);
assertTrue(bitmap != null);
try {
- java.io.OutputStream stream = new FileOutputStream(MediaNames.THUMBNAIL_METADATA_TEST_FILES[i] + ".jpg");
+ java.io.OutputStream stream =
+ new FileOutputStream(
+ MediaNames.THUMBNAIL_METADATA_TEST_FILES[i] + ".jpg");
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, stream);
stream.close();
} catch (Exception e) {
- Log.e(TAG, "Fails to convert the bitmap to a JPEG file for " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
+ Log.e(
+ TAG,
+ "Fails to convert the bitmap to a JPEG file for "
+ + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
hasFailed = true;
Log.e(TAG, e.toString());
}
- } catch(Exception e) {
- Log.e(TAG, "Fails to setDataSource for file " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
+ } catch (Exception e) {
+ Log.e(
+ TAG,
+ "Fails to setDataSource for file "
+ + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
hasFailed = true;
}
- Thread.yield(); // Don't be evil
+ Thread.yield(); // Don't be evil
}
long endedAt = System.currentTimeMillis();
retriever.release();
assertTrue(!hasFailed);
- Log.v(TAG, "Average processing time per thumbnail: " + (endedAt - startedAt)/MediaNames.THUMBNAIL_METADATA_TEST_FILES.length + " ms");
+ Log.v(
+ TAG,
+ "Average processing time per thumbnail: "
+ + (endedAt - startedAt) / MediaNames.THUMBNAIL_METADATA_TEST_FILES.length
+ + " ms");
}
-
+
@LargeTest
public static void testMetadataRetrieval() throws Exception {
boolean supportWMA = MediaProfileReader.getWMAEnable();
boolean supportWMV = MediaProfileReader.getWMVEnable();
boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- for(int i = 0, n = MediaNames.THUMBNAIL_METADATA_TEST_FILES.length; i < n; ++i) {
+ for (int i = 0, n = MediaNames.THUMBNAIL_METADATA_TEST_FILES.length; i < n; ++i) {
try {
Log.v(TAG, "File " + i + ": " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
- if ((MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wma") && !supportWMA) ||
- (MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wmv") && !supportWMV)
- ) {
- Log.v(TAG, "windows media is not supported and thus we will skip the test for this file");
+ if ((MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wma") && !supportWMA)
+ || (MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wmv")
+ && !supportWMV)) {
+ Log.v(
+ TAG,
+ "windows media is not supported and thus we will skip the test for this"
+ + " file");
continue;
}
retriever.setDataSource(MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
extractAllSupportedMetadataValues(retriever);
- } catch(Exception e) {
- Log.e(TAG, "Fails to setDataSource for file " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
+ } catch (Exception e) {
+ Log.e(
+ TAG,
+ "Fails to setDataSource for file "
+ + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
hasFailed = true;
}
- Thread.yield(); // Don't be evil
+ Thread.yield(); // Don't be evil
}
retriever.release();
assertTrue(!hasFailed);
@@ -151,10 +181,12 @@
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, stream);
stream.close();
} catch (Exception e) {
- throw new Exception("Fails to convert the bitmap to a JPEG file for " + MediaNames.TEST_PATH_1, e);
+ throw new Exception(
+ "Fails to convert the bitmap to a JPEG file for " + MediaNames.TEST_PATH_1,
+ e);
}
extractAllSupportedMetadataValues(retriever);
- } catch(Exception e) {
+ } catch (Exception e) {
Log.e(TAG, "Fails to setDataSource for " + MediaNames.TEST_PATH_1, e);
hasFailed = true;
}
@@ -181,7 +213,7 @@
// Test setDataSource()
@MediumTest
- public static void testSetDataSource() {
+ public static void testSetDataSource() throws IOException {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
boolean hasFailed = false;
@@ -191,7 +223,7 @@
retriever.setDataSource(path);
Log.e(TAG, "IllegalArgumentException failed to be thrown.");
hasFailed = true;
- } catch(Exception e) {
+ } catch (Exception e) {
if (!(e instanceof IllegalArgumentException)) {
Log.e(TAG, "Expected a IllegalArgumentException, but got a different exception");
hasFailed = true;
@@ -203,7 +235,7 @@
retriever.setDataSource(MediaNames.TEST_PATH_5);
Log.e(TAG, "IllegalArgumentException failed to be thrown.");
hasFailed = true;
- } catch(Exception e) {
+ } catch (Exception e) {
if (!(e instanceof IllegalArgumentException)) {
Log.e(TAG, "Expected a IllegalArgumentException, but got a different exception");
hasFailed = true;
@@ -215,7 +247,7 @@
retriever.setDataSource(MediaNames.TEST_PATH_4);
Log.e(TAG, "RuntimeException failed to be thrown.");
hasFailed = true;
- } catch(Exception e) {
+ } catch (Exception e) {
if (!(e instanceof RuntimeException)) {
Log.e(TAG, "Expected a RuntimeException, but got a different exception");
hasFailed = true;
@@ -228,13 +260,13 @@
retriever.setDataSource(MediaNames.TEST_PATH_3);
Log.e(TAG, "RuntimeException failed to be thrown.");
hasFailed = true;
- } catch(Exception e) {
+ } catch (Exception e) {
if (!(e instanceof RuntimeException)) {
Log.e(TAG, "Expected a RuntimeException, but got a different exception");
hasFailed = true;
}
}
-
+
retriever.release();
assertTrue(!hasFailed);
}
@@ -244,17 +276,23 @@
// We should be able to compare the actual returned metadata with the expected metadata
// with each given sample test file.
private static void extractAllSupportedMetadataValues(MediaMetadataRetriever retriever) {
- String value = null;
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_AUTHOR)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE)) == null? "not found": value);
- Log.v(TAG, (value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR)) == null? "not found": value);
+ int[] metadataRetrieverKeys =
+ new int[] {
+ MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+ MediaMetadataRetriever.METADATA_KEY_DURATION,
+ MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
+ MediaMetadataRetriever.METADATA_KEY_ALBUM,
+ MediaMetadataRetriever.METADATA_KEY_ARTIST,
+ MediaMetadataRetriever.METADATA_KEY_AUTHOR,
+ MediaMetadataRetriever.METADATA_KEY_COMPOSER,
+ MediaMetadataRetriever.METADATA_KEY_DATE,
+ MediaMetadataRetriever.METADATA_KEY_GENRE,
+ MediaMetadataRetriever.METADATA_KEY_TITLE,
+ MediaMetadataRetriever.METADATA_KEY_YEAR
+ };
+ for (int metadataRetrieverKey : metadataRetrieverKeys) {
+ String value = retriever.extractMetadata(metadataRetrieverKey);
+ Log.v(TAG, value == null ? "not found" : value);
+ }
}
}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index 8f3e4bd..220cf6b 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -18,6 +18,7 @@
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_NEW_TASK;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
@@ -329,6 +330,18 @@
}
/**
+ * Whether the {@link Activity} should be launched in a separate task.
+ */
+ public boolean isNewTask(Context context) {
+ ensureMetadataNotStale(context);
+ if (mMetaData != null
+ && mMetaData.containsKey(META_DATA_NEW_TASK)) {
+ return mMetaData.getBoolean(META_DATA_NEW_TASK);
+ }
+ return false;
+ }
+
+ /**
* Ensures metadata is not stale for this tile.
*/
private void ensureMetadataNotStale(Context context) {
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index a2bec33..acc0087 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -230,6 +230,13 @@
public static final String META_DATA_KEY_PROFILE = "com.android.settings.profile";
/**
+ * Name of the meta-data item that should be set in the AndroidManifest.xml
+ * to specify whether the {@link android.app.Activity} should be launched in a separate task.
+ * This should be a boolean value {@code true} or {@code false}, set using {@code android:value}
+ */
+ public static final String META_DATA_NEW_TASK = "com.android.settings.new_task";
+
+ /**
* Build a list of DashboardCategory.
*/
public static List<DashboardCategory> getCategories(Context context,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 0256615..1f75ae3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -139,14 +139,14 @@
*/
public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
- if (memberDevices != null) {
+ // TODO: check the CSIP group size instead of the real member device set size, and adjust
+ // the size restriction.
+ if (memberDevices.size() == 1) {
for (CachedBluetoothDevice memberDevice : memberDevices) {
- if (!memberDevice.isConnected()) {
- return null;
+ if (memberDevice.isConnected()) {
+ return memberDevice.getConnectionSummary();
}
}
-
- return device.getConnectionSummary();
}
CachedBluetoothDevice subDevice = device.getSubDevice();
if (subDevice != null && subDevice.isConnected()) {
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 786b371..c2901a5 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -224,15 +224,23 @@
display brightness, suitable to listen to while the device is asleep (e.g. during
always-on display) -->
<string-array name="doze_brightness_sensor_name_posture_mapping" translatable="false">
- <item></item> <!-- UNKNOWN -->
- <item></item> <!-- CLOSED -->
- <item></item> <!-- HALF_OPENED -->
- <item></item> <!-- OPENED -->
+ <!-- UNKNOWN -->
+ <!-- CLOSED -->
+ <!-- HALF_OPENED -->
+ <!-- OPENED -->
</string-array>
<!-- Override value to use for proximity sensor. -->
<string name="proximity_sensor_type" translatable="false"></string>
+ <!-- Sensor type per posture state to use for proximity sensor -->
+ <string-array name="proximity_sensor_posture_mapping" translatable="false">
+ <!-- UNKNOWN -->
+ <!-- CLOSED -->
+ <!-- HALF_OPENED -->
+ <!-- OPENED -->
+ </string-array>
+
<!-- If using proximity_sensor_type, specifies a threshold value to distinguish near and
far break points. A sensor value less than this is considered "near". -->
<item name="proximity_sensor_threshold" translatable="false" format="float" type="dimen"></item>
@@ -246,6 +254,15 @@
<!-- Override value to use for proximity sensor as confirmation for proximity_sensor_type. -->
<string name="proximity_sensor_secondary_type" translatable="false"></string>
+ <!-- Sensor type per posture state to use for proximity sensor as a confirmation for
+ proximity_sensor_type. -->
+ <string-array name="proximity_sensor_secondary_posture_mapping" translatable="false">
+ <!-- UNKNOWN -->
+ <!-- CLOSED -->
+ <!-- HALF_OPENED -->
+ <!-- OPENED -->
+ </string-array>
+
<!-- If using proximity_sensor_secondary_type, specifies a threshold value to distinguish
near and far break points. A sensor value less than this is considered "near". -->
<item name="proximity_sensor_secondary_threshold" translatable="false" format="float"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 62411db..11eeac2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -153,6 +153,10 @@
colorState = mNextMessageColorState;
mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
}
+ if (mAltBouncerShowing) {
+ // alt bouncer has a black scrim, so always show the text in white
+ colorState = ColorStateList.valueOf(Color.WHITE);
+ }
setTextColor(colorState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 14e5991..be326da 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -37,6 +37,7 @@
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.sensors.ThresholdSensor;
+import com.android.systemui.util.sensors.ThresholdSensorEvent;
import com.android.systemui.util.time.SystemClock;
import java.util.Collections;
@@ -405,7 +406,7 @@
mProximitySensor.unregister(mSensorEventListener);
}
- private void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+ private void onProximityEvent(ThresholdSensorEvent proximityEvent) {
// TODO: some of these classifiers might allow us to abort early, meaning we don't have to
// make these calls.
mFalsingManager.onProximityEvent(new ProximityEventImpl(proximityEvent));
@@ -423,9 +424,9 @@
}
private static class ProximityEventImpl implements FalsingManager.ProximityEvent {
- private ThresholdSensor.ThresholdSensorEvent mThresholdSensorEvent;
+ private ThresholdSensorEvent mThresholdSensorEvent;
- ProximityEventImpl(ThresholdSensor.ThresholdSensorEvent thresholdSensorEvent) {
+ ProximityEventImpl(ThresholdSensorEvent thresholdSensorEvent) {
mThresholdSensorEvent = thresholdSensorEvent;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index e117405..fa23842 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -24,8 +24,6 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.om.OverlayManager;
-import android.hardware.SensorManager;
-import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.ColorDisplayManager;
import android.os.Handler;
@@ -56,7 +54,6 @@
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.keyguard.LifecycleScreenStatusProvider;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -69,9 +66,6 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.theme.ThemeOverlayApplier;
-import com.android.systemui.unfold.UnfoldTransitionFactory;
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
-import com.android.systemui.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.settings.SecureSettings;
@@ -287,37 +281,6 @@
/** */
@Provides
@SysUISingleton
- public UnfoldTransitionProgressProvider provideUnfoldTransitionProgressProvider(
- Context context,
- UnfoldTransitionConfig config,
- LifecycleScreenStatusProvider screenStatusProvider,
- DeviceStateManager deviceStateManager,
- SensorManager sensorManager,
- @Main Executor executor,
- @Main Handler handler
- ) {
- return UnfoldTransitionFactory
- .createUnfoldTransitionProgressProvider(
- context,
- config,
- screenStatusProvider,
- deviceStateManager,
- sensorManager,
- handler,
- executor
- );
- }
-
- /** */
- @Provides
- @SysUISingleton
- public UnfoldTransitionConfig provideUnfoldTransitionConfig(Context context) {
- return UnfoldTransitionFactory.createConfig(context);
- }
-
- /** */
- @Provides
- @SysUISingleton
public Choreographer providesChoreographer() {
return Choreographer.getInstance();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 648f345..18f8519 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -24,6 +24,7 @@
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.plugins.PluginsModule;
+import com.android.systemui.unfold.UnfoldTransitionModule;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
import javax.inject.Singleton;
@@ -49,6 +50,7 @@
@Module(includes = {
FrameworkServicesModule.class,
GlobalConcurrencyModule.class,
+ UnfoldTransitionModule.class,
PluginsModule.class,
})
public class GlobalModule {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1e7f0d9..b17f078 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -46,6 +46,7 @@
import com.android.systemui.util.Assert;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.util.sensors.ProximityCheck;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.wakelock.WakeLock;
@@ -90,7 +91,7 @@
private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver();
private final DockEventListener mDockEventListener = new DockEventListener();
private final DockManager mDockManager;
- private final ProximitySensor.ProximityCheck mProxCheck;
+ private final ProximityCheck mProxCheck;
private final BroadcastDispatcher mBroadcastDispatcher;
private final AuthController mAuthController;
private final DelayableExecutor mMainExecutor;
@@ -181,7 +182,8 @@
AmbientDisplayConfiguration config,
DozeParameters dozeParameters, AsyncSensorManager sensorManager,
WakeLock wakeLock, DockManager dockManager,
- ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proxCheck,
+ ProximitySensor proximitySensor,
+ ProximityCheck proxCheck,
DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher,
SecureSettings secureSettings, AuthController authController,
@Main DelayableExecutor mainExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index b0f3959..21a1b75 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -18,11 +18,11 @@
import android.util.ArrayMap
import com.android.systemui.Dumpable
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import java.io.FileDescriptor
import java.io.PrintWriter
import javax.inject.Inject
+import javax.inject.Singleton
/**
* Maintains a registry of things that should be dumped when a bug report is taken
@@ -33,7 +33,7 @@
*
* See [DumpHandler] for more information on how and when this information is dumped.
*/
-@SysUISingleton
+@Singleton
open class DumpManager @Inject constructor() {
private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap()
private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
index f25ec55..044a57c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
@@ -15,12 +15,12 @@
*/
package com.android.systemui.keyguard
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
import javax.inject.Inject
+import javax.inject.Singleton
-@SysUISingleton
+@Singleton
class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenLifecycle) :
ScreenStatusProvider, ScreenLifecycle.Observer {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java
index 30983aa..d17c39a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ScreenLifecycle.java
@@ -19,18 +19,18 @@
import android.os.Trace;
import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import javax.inject.Inject;
+import javax.inject.Singleton;
/**
* Tracks the screen lifecycle.
*/
-@SysUISingleton
+@Singleton
public class ScreenLifecycle extends Lifecycle<ScreenLifecycle.Observer> implements Dumpable {
public static final int SCREEN_OFF = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index a1a630a..7622d66 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -195,7 +195,8 @@
mNavigationModeController.addListener(this);
mTaskbarDelegate = taskbarDelegate;
mTaskbarDelegate.setOverviewProxyService(commandQueue, overviewProxyService,
- navigationBarA11yHelper, navigationModeController, sysUiFlagsContainer);
+ navigationBarA11yHelper, navigationModeController, sysUiFlagsContainer,
+ dumpManager);
mIsTablet = isTablet(mContext);
mUserTracker = userTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index fa616921..4d29612 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -46,8 +46,12 @@
import android.view.View;
import android.view.WindowInsetsController.Behavior;
+import androidx.annotation.NonNull;
+
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.OverviewProxyService;
@@ -55,13 +59,16 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class TaskbarDelegate implements CommandQueue.Callbacks,
OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
- ComponentCallbacks {
+ ComponentCallbacks, Dumpable {
private final EdgeBackGestureHandler mEdgeBackGestureHandler;
@@ -93,13 +100,14 @@
OverviewProxyService overviewProxyService,
NavigationBarA11yHelper navigationBarA11yHelper,
NavigationModeController navigationModeController,
- SysUiState sysUiState) {
+ SysUiState sysUiState, DumpManager dumpManager) {
// TODO: adding this in the ctor results in a dagger dependency cycle :(
mCommandQueue = commandQueue;
mOverviewProxyService = overviewProxyService;
mNavigationBarA11yHelper = navigationBarA11yHelper;
mNavigationModeController = navigationModeController;
mSysUiState = sysUiState;
+ dumpManager.registerDumpable(this);
}
public void destroy() {
@@ -220,4 +228,14 @@
@Override
public void onLowMemory() {}
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("TaskbarDelegate (displayId=" + mDisplayId + "):");
+ pw.println(" mNavigationIconHints=" + mNavigationIconHints);
+ pw.println(" mDisabledFlags=" + mDisabledFlags);
+ pw.println(" mTaskBarWindowState=" + mTaskBarWindowState);
+ pw.println(" mBehavior=" + mBehavior);
+ mEdgeBackGestureHandler.dump(pw);
+ }
}
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 5c5dd6b..562d7ea 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
@@ -253,6 +253,7 @@
private boolean mExpandedInThisMotion;
private boolean mShouldShowShelfOnly;
protected boolean mScrollingEnabled;
+ private boolean mIsCurrentUserSetup;
protected FooterView mFooterView;
protected EmptyShadeView mEmptyShadeView;
private boolean mDismissAllInProgress;
@@ -682,6 +683,7 @@
boolean showDismissView = mClearAllEnabled &&
mController.hasActiveClearableNotifications(ROWS_ALL);
boolean showFooterView = (showDismissView || getVisibleNotificationCount() > 0)
+ && mIsCurrentUserSetup // see: b/193149550
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
&& !mIsRemoteInputActive;
@@ -5608,6 +5610,16 @@
}
/**
+ * Sets whether the current user is set up, which is required to show the footer (b/193149550)
+ */
+ public void setCurrentUserSetup(boolean isCurrentUserSetup) {
+ if (mIsCurrentUserSetup != isCurrentUserSetup) {
+ mIsCurrentUserSetup = isCurrentUserSetup;
+ updateFooter();
+ }
+ }
+
+ /**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index c9033b9..216115e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -119,6 +119,8 @@
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -146,6 +148,7 @@
private final HeadsUpManagerPhone mHeadsUpManager;
private final NotificationRoundnessManager mNotificationRoundnessManager;
private final TunerService mTunerService;
+ private final DeviceProvisionedController mDeviceProvisionedController;
private final DynamicPrivacyController mDynamicPrivacyController;
private final ConfigurationController mConfigurationController;
private final ZenModeController mZenModeController;
@@ -226,6 +229,28 @@
}
};
+ private final DeviceProvisionedListener mDeviceProvisionedListener =
+ new DeviceProvisionedListener() {
+ @Override
+ public void onDeviceProvisionedChanged() {
+ updateCurrentUserIsSetup();
+ }
+
+ @Override
+ public void onUserSwitched() {
+ updateCurrentUserIsSetup();
+ }
+
+ @Override
+ public void onUserSetupChanged() {
+ updateCurrentUserIsSetup();
+ }
+
+ private void updateCurrentUserIsSetup() {
+ mView.setCurrentUserSetup(mDeviceProvisionedController.isCurrentUserSetup());
+ }
+ };
+
private final DynamicPrivacyController.Listener mDynamicPrivacyControllerListener = () -> {
if (mView.isExpanded()) {
// The bottom might change because we're using the final actual height of the view
@@ -600,6 +625,7 @@
HeadsUpManagerPhone headsUpManager,
NotificationRoundnessManager notificationRoundnessManager,
TunerService tunerService,
+ DeviceProvisionedController deviceProvisionedController,
DynamicPrivacyController dynamicPrivacyController,
ConfigurationController configurationController,
SysuiStatusBarStateController statusBarStateController,
@@ -636,6 +662,7 @@
mHeadsUpManager = headsUpManager;
mNotificationRoundnessManager = notificationRoundnessManager;
mTunerService = tunerService;
+ mDeviceProvisionedController = deviceProvisionedController;
mDynamicPrivacyController = dynamicPrivacyController;
mConfigurationController = configurationController;
mStatusBarStateController = statusBarStateController;
@@ -788,6 +815,9 @@
return Unit.INSTANCE;
});
+ // callback is invoked synchronously, updating mView immediately
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5bc97a5..18fd9d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1149,7 +1149,6 @@
public void showBouncerMessage(String message, ColorStateList colorState) {
if (isShowingAlternateAuth()) {
if (mKeyguardMessageAreaController != null) {
- mKeyguardMessageAreaController.setNextMessageColor(colorState);
mKeyguardMessageAreaController.setMessage(message);
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
index 8596875..bbba19d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
@@ -46,6 +46,7 @@
int DEVICE_POSTURE_HALF_OPENED = 2;
int DEVICE_POSTURE_OPENED = 3;
int DEVICE_POSTURE_FLIPPED = 4;
+ int SUPPORTED_POSTURES_SIZE = DEVICE_POSTURE_FLIPPED + 1;
/** Return the current device posture. */
@DevicePostureInt int getDevicePosture();
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/ShellUnfoldProgressProvider.kt b/packages/SystemUI/src/com/android/systemui/unfold/ShellUnfoldProgressProvider.kt
new file mode 100644
index 0000000..4a88435
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/ShellUnfoldProgressProvider.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.unfold
+
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
+import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener
+import java.util.concurrent.Executor
+
+class ShellUnfoldProgressProvider(
+ private val unfoldProgressProvider: UnfoldTransitionProgressProvider
+) : ShellUnfoldProgressProvider {
+
+ override fun addListener(executor: Executor, listener: UnfoldListener) {
+ unfoldProgressProvider.addCallback(object : TransitionProgressListener {
+ override fun onTransitionStarted() {
+ executor.execute {
+ listener.onStateChangeStarted()
+ }
+ }
+
+ override fun onTransitionProgress(progress: Float) {
+ executor.execute {
+ listener.onStateChangeProgress(progress)
+ }
+ }
+
+ override fun onTransitionFinished() {
+ executor.execute {
+ listener.onStateChangeFinished()
+ }
+ }
+ })
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
new file mode 100644
index 0000000..b23aa20
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.unfold
+
+import android.content.Context
+import android.hardware.SensorManager
+import android.hardware.devicestate.DeviceStateManager
+import android.os.Handler
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.LifecycleScreenStatusProvider
+import com.android.systemui.unfold.config.UnfoldTransitionConfig
+import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
+import dagger.Lazy
+import dagger.Module
+import dagger.Provides
+import java.util.Optional
+import java.util.concurrent.Executor
+import javax.inject.Singleton
+
+@Module
+class UnfoldTransitionModule {
+
+ @Provides
+ @Singleton
+ fun provideUnfoldTransitionProgressProvider(
+ context: Context,
+ config: UnfoldTransitionConfig,
+ screenStatusProvider: LifecycleScreenStatusProvider,
+ deviceStateManager: DeviceStateManager,
+ sensorManager: SensorManager,
+ @Main executor: Executor,
+ @Main handler: Handler
+ ): UnfoldTransitionProgressProvider =
+ createUnfoldTransitionProgressProvider(
+ context,
+ config,
+ screenStatusProvider,
+ deviceStateManager,
+ sensorManager,
+ handler,
+ executor
+ )
+
+ @Provides
+ @Singleton
+ fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
+ createConfig(context)
+
+ @Provides
+ @Singleton
+ fun provideShellProgressProvider(
+ config: UnfoldTransitionConfig,
+ provider: Lazy<UnfoldTransitionProgressProvider>
+ ): Optional<ShellUnfoldProgressProvider> =
+ if (config.isEnabled) {
+ Optional.ofNullable(ShellUnfoldProgressProvider(provider.get()))
+ } else {
+ Optional.empty()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index 6c35433..da4ccd0 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -63,8 +63,7 @@
Intent intent = getIntent();
Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);
if (!(targetParcelable instanceof Intent)) {
- super.onCreate(savedInstanceState);
- onStop(); // unregister receiver registered in onCreate (PackageMonitor)
+ super_onCreate(savedInstanceState);
Log.w("UsbResolverActivity", "Target is not an intent: " + targetParcelable);
finish();
return;
@@ -97,8 +96,7 @@
} else {
mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (mAccessory == null) {
- super.onCreate(savedInstanceState);
- onStop(); // unregister receiver registered in onCreate (PackageMonitor)
+ super_onCreate(savedInstanceState);
Log.e(TAG, "no device or accessory");
finish();
return;
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
new file mode 100644
index 0000000..28cba8e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.sensors;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.concurrency.Execution;
+
+import javax.inject.Inject;
+
+/**
+ * Proximity sensor that changes proximity sensor usage based on the current posture.
+ * Posture -> prox sensor mapping can be found in SystemUI config overlays at:
+ * - proximity_sensor_posture_mapping
+ * - proximity_sensor_secondary_posture_mapping.
+ * where the array indices correspond to the following postures:
+ * [UNKNOWN, CLOSED, HALF_OPENED, OPENED]
+ */
+class PostureDependentProximitySensor extends ProximitySensorImpl {
+ private final ThresholdSensor[] mPostureToPrimaryProxSensorMap;
+ private final ThresholdSensor[] mPostureToSecondaryProxSensorMap;
+
+ @Inject
+ PostureDependentProximitySensor(
+ @PrimaryProxSensor ThresholdSensor[] postureToPrimaryProxSensorMap,
+ @SecondaryProxSensor ThresholdSensor[] postureToSecondaryProxSensorMap,
+ @NonNull DelayableExecutor delayableExecutor,
+ @NonNull Execution execution,
+ @NonNull DevicePostureController devicePostureController
+ ) {
+ super(
+ postureToPrimaryProxSensorMap[0],
+ postureToSecondaryProxSensorMap[0],
+ delayableExecutor,
+ execution
+ );
+ mPostureToPrimaryProxSensorMap = postureToPrimaryProxSensorMap;
+ mPostureToSecondaryProxSensorMap = postureToSecondaryProxSensorMap;
+ mDevicePosture = devicePostureController.getDevicePosture();
+ devicePostureController.addCallback(mDevicePostureCallback);
+
+ chooseSensors();
+ }
+ private void chooseSensors() {
+ if (mDevicePosture >= mPostureToPrimaryProxSensorMap.length
+ || mDevicePosture >= mPostureToSecondaryProxSensorMap.length) {
+ Log.e("PostureDependentProxSensor",
+ "unsupported devicePosture=" + mDevicePosture);
+ return;
+ }
+
+ ThresholdSensor newPrimaryProx = mPostureToPrimaryProxSensorMap[mDevicePosture];
+ ThresholdSensor newSecondaryProx = mPostureToSecondaryProxSensorMap[mDevicePosture];
+
+ if (newPrimaryProx != mPrimaryThresholdSensor
+ || newSecondaryProx != mSecondaryThresholdSensor) {
+ logDebug("Register new proximity sensors newPosture="
+ + DevicePostureController.devicePostureToString(mDevicePosture));
+ unregisterInternal();
+
+ if (mPrimaryThresholdSensor != null) {
+ mPrimaryThresholdSensor.unregister(mPrimaryEventListener);
+ }
+ if (mSecondaryThresholdSensor != null) {
+ mSecondaryThresholdSensor.unregister(mSecondaryEventListener);
+ }
+
+ mPrimaryThresholdSensor = newPrimaryProx;
+ mSecondaryThresholdSensor = newSecondaryProx;
+
+ mInitializedListeners = false;
+ registerInternal();
+ }
+ }
+
+ private final DevicePostureController.Callback mDevicePostureCallback =
+ posture -> {
+ if (mDevicePosture == posture) {
+ return;
+ }
+
+ mDevicePosture = posture;
+ chooseSensors();
+ };
+
+ @Override
+ public String toString() {
+ return String.format("{posture=%s, proximitySensor=%s}",
+ DevicePostureController.devicePostureToString(mDevicePosture), super.toString());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
new file mode 100644
index 0000000..a8a6341
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.sensors;
+
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+import javax.inject.Inject;
+
+/**
+ * Convenience class allowing for briefly checking the proximity sensor.
+ */
+public class ProximityCheck implements Runnable {
+
+ private final ProximitySensor mSensor;
+ private final DelayableExecutor mDelayableExecutor;
+ private List<Consumer<Boolean>> mCallbacks = new ArrayList<>();
+ private final ThresholdSensor.Listener mListener;
+ private final AtomicBoolean mRegistered = new AtomicBoolean();
+
+ @Inject
+ public ProximityCheck(
+ ProximitySensor sensor,
+ @Main DelayableExecutor delayableExecutor) {
+ mSensor = sensor;
+ mSensor.setTag("prox_check");
+ mDelayableExecutor = delayableExecutor;
+ mListener = this::onProximityEvent;
+ }
+
+ /** Set a descriptive tag for the sensors registration. */
+ public void setTag(String tag) {
+ mSensor.setTag(tag);
+ }
+
+ @Override
+ public void run() {
+ unregister();
+ onProximityEvent(null);
+ }
+
+ /**
+ * Query the proximity sensor, timing out if no result.
+ */
+ public void check(long timeoutMs, Consumer<Boolean> callback) {
+ if (!mSensor.isLoaded()) {
+ callback.accept(null);
+ return;
+ }
+ mCallbacks.add(callback);
+ if (!mRegistered.getAndSet(true)) {
+ mSensor.register(mListener);
+ mDelayableExecutor.executeDelayed(this, timeoutMs);
+ }
+ }
+
+ private void unregister() {
+ mSensor.unregister(mListener);
+ mRegistered.set(false);
+ }
+
+ private void onProximityEvent(ThresholdSensorEvent proximityEvent) {
+ mCallbacks.forEach(
+ booleanConsumer ->
+ booleanConsumer.accept(
+ proximityEvent == null ? null : proximityEvent.getBelow()));
+ mCallbacks.clear();
+ unregister();
+ mRegistered.set(false);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index bd11039..d3f1c93 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,149 +16,24 @@
package com.android.systemui.util.sensors;
-import android.hardware.SensorManager;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.android.systemui.util.concurrency.Execution;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Consumer;
-
-import javax.inject.Inject;
-
/**
- * Wrapper around SensorManager customized for the Proximity sensor.
- *
- * The ProximitySensor supports the concept of a primary and a
- * secondary hardware sensor. The primary sensor is used for a first
- * pass check if the phone covered. When triggered, it then checks
- * the secondary sensor for confirmation (if there is one). It does
- * not send a proximity event until the secondary sensor confirms (or
- * rejects) the reading. The secondary sensor is, in fact, the source
- * of truth.
- *
- * This is necessary as sometimes keeping the secondary sensor on for
- * extends periods is undesirable. It may, however, result in increased
- * latency for proximity readings.
- *
- * Phones should configure this via a config.xml overlay. If no
- * proximity sensor is set (primary or secondary) we fall back to the
- * default Sensor.TYPE_PROXIMITY. If proximity_sensor_type is set in
- * config.xml, that will be used as the primary sensor. If
- * proximity_sensor_secondary_type is set, that will function as the
- * secondary sensor. If no secondary is set, only the primary will be
- * used.
+ * Wrapper class for a dual ProximitySensor which supports a secondary sensor gated upon the
+ * primary).
*/
-public class ProximitySensor implements ThresholdSensor {
- private static final String TAG = "ProxSensor";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final long SECONDARY_PING_INTERVAL_MS = 5000;
-
- private final ThresholdSensor mPrimaryThresholdSensor;
- private final ThresholdSensor mSecondaryThresholdSensor;
- private final DelayableExecutor mDelayableExecutor;
- private final Execution mExecution;
- private final List<ThresholdSensor.Listener> mListeners = new ArrayList<>();
- private String mTag = null;
- @VisibleForTesting protected boolean mPaused;
- private ThresholdSensorEvent mLastPrimaryEvent;
- @VisibleForTesting
- ThresholdSensorEvent mLastEvent;
- private boolean mRegistered;
- private final AtomicBoolean mAlerting = new AtomicBoolean();
- private Runnable mCancelSecondaryRunnable;
- private boolean mInitializedListeners = false;
- private boolean mSecondarySafe = false;
-
- private final ThresholdSensor.Listener mPrimaryEventListener = this::onPrimarySensorEvent;
-
- private final ThresholdSensor.Listener mSecondaryEventListener =
- new ThresholdSensor.Listener() {
- @Override
- public void onThresholdCrossed(ThresholdSensorEvent event) {
- // If we no longer have a "below" signal and the secondary sensor is not
- // considered "safe", then we need to turn it off.
- if (!mSecondarySafe
- && (mLastPrimaryEvent == null
- || !mLastPrimaryEvent.getBelow()
- || !event.getBelow())) {
- chooseSensor();
- if (mLastPrimaryEvent == null || !mLastPrimaryEvent.getBelow()) {
- // Only check the secondary as long as the primary thinks we're near.
- if (mCancelSecondaryRunnable != null) {
- mCancelSecondaryRunnable.run();
- mCancelSecondaryRunnable = null;
- }
- return;
- } else {
- // Check this sensor again in a moment.
- mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(() -> {
- // This is safe because we know that mSecondaryThresholdSensor
- // is loaded, otherwise we wouldn't be here.
- mPrimaryThresholdSensor.pause();
- mSecondaryThresholdSensor.resume();
- },
- SECONDARY_PING_INTERVAL_MS);
- }
- }
- logDebug("Secondary sensor event: " + event.getBelow() + ".");
-
- if (!mPaused) {
- onSensorEvent(event);
- }
- }
- };
-
- @Inject
- public ProximitySensor(
- @PrimaryProxSensor ThresholdSensor primary,
- @SecondaryProxSensor ThresholdSensor secondary,
- @Main DelayableExecutor delayableExecutor,
- Execution execution) {
- mPrimaryThresholdSensor = primary;
- mSecondaryThresholdSensor = secondary;
- mDelayableExecutor = delayableExecutor;
- mExecution = execution;
- }
-
- @Override
- public void setTag(String tag) {
- mTag = tag;
- mPrimaryThresholdSensor.setTag(tag + ":primary");
- mSecondaryThresholdSensor.setTag(tag + ":secondary");
- }
-
- @Override
- public void setDelay(int delay) {
- mExecution.assertIsMainThread();
- mPrimaryThresholdSensor.setDelay(delay);
- mSecondaryThresholdSensor.setDelay(delay);
- }
+public interface ProximitySensor extends ThresholdSensor {
+ /**
+ * Returns true if we are registered with the SensorManager.
+ */
+ boolean isRegistered();
/**
- * Unregister with the {@link SensorManager} without unsetting listeners on this object.
+ * Whether the proximity sensor reports near. Can return null if no information has been
+ * received yet.
*/
- @Override
- public void pause() {
- mExecution.assertIsMainThread();
- mPaused = true;
- unregisterInternal();
- }
+ Boolean isNear();
- /**
- * Register with the {@link SensorManager}. No-op if no listeners are registered on this object.
- */
- @Override
- public void resume() {
- mExecution.assertIsMainThread();
- mPaused = false;
- registerInternal();
- }
+ /** Update all listeners with the last value this class received from the sensor. */
+ void alertListeners();
/**
* Sets that it is safe to leave the secondary sensor on indefinitely.
@@ -166,249 +41,5 @@
* The secondary sensor will be turned on if there are any registered listeners, regardless
* of what is reported by the primary sensor.
*/
- public void setSecondarySafe(boolean safe) {
- mSecondarySafe = mSecondaryThresholdSensor.isLoaded() && safe;
- chooseSensor();
- }
-
- /**
- * Returns true if we are registered with the SensorManager.
- */
- public boolean isRegistered() {
- return mRegistered;
- }
-
- /**
- * Returns {@code false} if a Proximity sensor is not available.
- */
- @Override
- public boolean isLoaded() {
- return mPrimaryThresholdSensor.isLoaded();
- }
-
- /**
- * Add a listener.
- *
- * Registers itself with the {@link SensorManager} if this is the first listener
- * added. If the ProximitySensor is paused, it will be registered when resumed.
- */
- @Override
- public void register(ThresholdSensor.Listener listener) {
- mExecution.assertIsMainThread();
- if (!isLoaded()) {
- return;
- }
-
- if (mListeners.contains(listener)) {
- logDebug("ProxListener registered multiple times: " + listener);
- } else {
- mListeners.add(listener);
- }
- registerInternal();
- }
-
- protected void registerInternal() {
- mExecution.assertIsMainThread();
- if (mRegistered || mPaused || mListeners.isEmpty()) {
- return;
- }
- if (!mInitializedListeners) {
- mPrimaryThresholdSensor.pause();
- mSecondaryThresholdSensor.pause();
- mPrimaryThresholdSensor.register(mPrimaryEventListener);
- mSecondaryThresholdSensor.register(mSecondaryEventListener);
- mInitializedListeners = true;
- }
- logDebug("Registering sensor listener");
-
- mRegistered = true;
- chooseSensor();
- }
-
- private void chooseSensor() {
- mExecution.assertIsMainThread();
- if (!mRegistered || mPaused || mListeners.isEmpty()) {
- return;
- }
- if (mSecondarySafe) {
- mSecondaryThresholdSensor.resume();
- mPrimaryThresholdSensor.pause();
- } else {
- mPrimaryThresholdSensor.resume();
- mSecondaryThresholdSensor.pause();
- }
- }
-
- /**
- * Remove a listener.
- *
- * If all listeners are removed from an instance of this class,
- * it will unregister itself with the SensorManager.
- */
- @Override
- public void unregister(ThresholdSensor.Listener listener) {
- mExecution.assertIsMainThread();
- mListeners.remove(listener);
- if (mListeners.size() == 0) {
- unregisterInternal();
- }
- }
-
- protected void unregisterInternal() {
- mExecution.assertIsMainThread();
- if (!mRegistered) {
- return;
- }
- logDebug("unregistering sensor listener");
- mPrimaryThresholdSensor.pause();
- mSecondaryThresholdSensor.pause();
- if (mCancelSecondaryRunnable != null) {
- mCancelSecondaryRunnable.run();
- mCancelSecondaryRunnable = null;
- }
- mLastPrimaryEvent = null; // Forget what we know.
- mLastEvent = null;
- mRegistered = false;
- }
-
- public Boolean isNear() {
- return isLoaded() && mLastEvent != null ? mLastEvent.getBelow() : null;
- }
-
- /** Update all listeners with the last value this class received from the sensor. */
- public void alertListeners() {
- mExecution.assertIsMainThread();
- if (mAlerting.getAndSet(true)) {
- return;
- }
- if (mLastEvent != null) {
- ThresholdSensorEvent lastEvent = mLastEvent; // Listeners can null out mLastEvent.
- List<ThresholdSensor.Listener> listeners = new ArrayList<>(mListeners);
- listeners.forEach(proximitySensorListener ->
- proximitySensorListener.onThresholdCrossed(lastEvent));
- }
-
- mAlerting.set(false);
- }
-
- private void onPrimarySensorEvent(ThresholdSensorEvent event) {
- mExecution.assertIsMainThread();
- if (mLastPrimaryEvent != null && event.getBelow() == mLastPrimaryEvent.getBelow()) {
- return;
- }
-
- mLastPrimaryEvent = event;
-
- if (mSecondarySafe && mSecondaryThresholdSensor.isLoaded()) {
- logDebug("Primary sensor reported " + (event.getBelow() ? "near" : "far")
- + ". Checking secondary.");
- if (mCancelSecondaryRunnable == null) {
- mSecondaryThresholdSensor.resume();
- }
- return;
- }
-
-
- if (!mSecondaryThresholdSensor.isLoaded()) { // No secondary
- logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
- onSensorEvent(event);
- } else if (event.getBelow()) { // Covered? Check secondary.
- logDebug("Primary sensor event: " + event.getBelow() + ". Checking secondary.");
- if (mCancelSecondaryRunnable != null) {
- mCancelSecondaryRunnable.run();
- }
- mSecondaryThresholdSensor.resume();
- } else { // Uncovered. Report immediately.
- onSensorEvent(event);
- }
- }
-
- private void onSensorEvent(ThresholdSensorEvent event) {
- mExecution.assertIsMainThread();
- if (mLastEvent != null && event.getBelow() == mLastEvent.getBelow()) {
- return;
- }
-
- if (!mSecondarySafe && !event.getBelow()) {
- chooseSensor();
- }
-
- mLastEvent = event;
- alertListeners();
- }
-
- @Override
- public String toString() {
- return String.format("{registered=%s, paused=%s, near=%s, primarySensor=%s, "
- + "secondarySensor=%s secondarySafe=%s}",
- isRegistered(), mPaused, isNear(), mPrimaryThresholdSensor,
- mSecondaryThresholdSensor, mSecondarySafe);
- }
-
- /**
- * Convenience class allowing for briefly checking the proximity sensor.
- */
- public static class ProximityCheck implements Runnable {
-
- private final ProximitySensor mSensor;
- private final DelayableExecutor mDelayableExecutor;
- private List<Consumer<Boolean>> mCallbacks = new ArrayList<>();
- private final ThresholdSensor.Listener mListener;
- private final AtomicBoolean mRegistered = new AtomicBoolean();
-
- @Inject
- public ProximityCheck(ProximitySensor sensor, @Main DelayableExecutor delayableExecutor) {
- mSensor = sensor;
- mSensor.setTag("prox_check");
- mDelayableExecutor = delayableExecutor;
- mListener = this::onProximityEvent;
- }
-
- /** Set a descriptive tag for the sensors registration. */
- public void setTag(String tag) {
- mSensor.setTag(tag);
- }
-
- @Override
- public void run() {
- unregister();
- onProximityEvent(null);
- }
-
- /**
- * Query the proximity sensor, timing out if no result.
- */
- public void check(long timeoutMs, Consumer<Boolean> callback) {
- if (!mSensor.isLoaded()) {
- callback.accept(null);
- return;
- }
- mCallbacks.add(callback);
- if (!mRegistered.getAndSet(true)) {
- mSensor.register(mListener);
- mDelayableExecutor.executeDelayed(this, timeoutMs);
- }
- }
-
- private void unregister() {
- mSensor.unregister(mListener);
- mRegistered.set(false);
- }
-
- private void onProximityEvent(ThresholdSensorEvent proximityEvent) {
- mCallbacks.forEach(
- booleanConsumer ->
- booleanConsumer.accept(
- proximityEvent == null ? null : proximityEvent.getBelow()));
- mCallbacks.clear();
- unregister();
- mRegistered.set(false);
- }
- }
-
- private void logDebug(String msg) {
- if (DEBUG) {
- Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg);
- }
- }
+ void setSecondarySafe(boolean safe);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
new file mode 100644
index 0000000..e639313a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
@@ -0,0 +1,360 @@
+/*
+ * 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.util.sensors;
+
+import android.hardware.SensorManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.concurrency.Execution;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.inject.Inject;
+
+/**
+ * Wrapper around SensorManager customized for the Proximity sensor.
+ *
+ * The ProximitySensor supports the concept of a primary and a
+ * secondary hardware sensor. The primary sensor is used for a first
+ * pass check if the phone covered. When triggered, it then checks
+ * the secondary sensor for confirmation (if there is one). It does
+ * not send a proximity event until the secondary sensor confirms (or
+ * rejects) the reading. The secondary sensor is, in fact, the source
+ * of truth.
+ *
+ * This is necessary as sometimes keeping the secondary sensor on for
+ * extends periods is undesirable. It may, however, result in increased
+ * latency for proximity readings.
+ *
+ * Phones should configure this via a config.xml overlay. If no
+ * proximity sensor is set (primary or secondary) we fall back to the
+ * default Sensor.TYPE_PROXIMITY. If proximity_sensor_type is set in
+ * config.xml, that will be used as the primary sensor. If
+ * proximity_sensor_secondary_type is set, that will function as the
+ * secondary sensor. If no secondary is set, only the primary will be
+ * used.
+ */
+class ProximitySensorImpl implements ProximitySensor {
+ private static final String TAG = "ProxSensor";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final long SECONDARY_PING_INTERVAL_MS = 5000;
+
+ ThresholdSensor mPrimaryThresholdSensor;
+ ThresholdSensor mSecondaryThresholdSensor;
+ private final DelayableExecutor mDelayableExecutor;
+ private final Execution mExecution;
+ private final List<ThresholdSensor.Listener> mListeners = new ArrayList<>();
+ private String mTag = null;
+ @VisibleForTesting protected boolean mPaused;
+ private ThresholdSensorEvent mLastPrimaryEvent;
+ @VisibleForTesting
+ ThresholdSensorEvent mLastEvent;
+ private boolean mRegistered;
+ private final AtomicBoolean mAlerting = new AtomicBoolean();
+ private Runnable mCancelSecondaryRunnable;
+ boolean mInitializedListeners = false;
+ private boolean mSecondarySafe = false; // safe to skip primary sensor check and use secondary
+ protected @DevicePostureController.DevicePostureInt int mDevicePosture;
+
+ final ThresholdSensor.Listener mPrimaryEventListener = this::onPrimarySensorEvent;
+
+ final ThresholdSensor.Listener mSecondaryEventListener =
+ new ThresholdSensor.Listener() {
+ @Override
+ public void onThresholdCrossed(ThresholdSensorEvent event) {
+ // If we no longer have a "below" signal and the secondary sensor is not
+ // considered "safe", then we need to turn it off.
+ if (!mSecondarySafe
+ && (mLastPrimaryEvent == null
+ || !mLastPrimaryEvent.getBelow()
+ || !event.getBelow())) {
+ chooseSensor();
+ if (mLastPrimaryEvent == null || !mLastPrimaryEvent.getBelow()) {
+ // Only check the secondary as long as the primary thinks we're near.
+ if (mCancelSecondaryRunnable != null) {
+ mCancelSecondaryRunnable.run();
+ mCancelSecondaryRunnable = null;
+ }
+ return;
+ } else {
+ // Check this sensor again in a moment.
+ mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(() -> {
+ // This is safe because we know that mSecondaryThresholdSensor
+ // is loaded, otherwise we wouldn't be here.
+ mPrimaryThresholdSensor.pause();
+ mSecondaryThresholdSensor.resume();
+ },
+ SECONDARY_PING_INTERVAL_MS);
+ }
+ }
+ logDebug("Secondary sensor event: " + event.getBelow() + ".");
+
+ if (!mPaused) {
+ onSensorEvent(event);
+ }
+ }
+ };
+
+ @Inject
+ ProximitySensorImpl(
+ @PrimaryProxSensor ThresholdSensor primary,
+ @SecondaryProxSensor ThresholdSensor secondary,
+ @Main DelayableExecutor delayableExecutor,
+ Execution execution) {
+ mPrimaryThresholdSensor = primary;
+ mSecondaryThresholdSensor = secondary;
+ mDelayableExecutor = delayableExecutor;
+ mExecution = execution;
+ }
+
+ @Override
+ public void setTag(String tag) {
+ mTag = tag;
+ mPrimaryThresholdSensor.setTag(tag + ":primary");
+ mSecondaryThresholdSensor.setTag(tag + ":secondary");
+ }
+
+ @Override
+ public void setDelay(int delay) {
+ mExecution.assertIsMainThread();
+ mPrimaryThresholdSensor.setDelay(delay);
+ mSecondaryThresholdSensor.setDelay(delay);
+ }
+
+ /**
+ * Unregister with the {@link SensorManager} without unsetting listeners on this object.
+ */
+ @Override
+ public void pause() {
+ mExecution.assertIsMainThread();
+ mPaused = true;
+ unregisterInternal();
+ }
+
+ /**
+ * Register with the {@link SensorManager}. No-op if no listeners are registered on this object.
+ */
+ @Override
+ public void resume() {
+ mExecution.assertIsMainThread();
+ mPaused = false;
+ registerInternal();
+ }
+
+ @Override
+ public void setSecondarySafe(boolean safe) {
+ mSecondarySafe = mSecondaryThresholdSensor.isLoaded() && safe;
+ chooseSensor();
+ }
+
+ /**
+ * Returns true if we are registered with the SensorManager.
+ */
+ @Override
+ public boolean isRegistered() {
+ return mRegistered;
+ }
+
+ /**
+ * Returns {@code false} if a Proximity sensor is not available.
+ */
+ @Override
+ public boolean isLoaded() {
+ return mPrimaryThresholdSensor.isLoaded();
+ }
+
+ /**
+ * Add a listener.
+ *
+ * Registers itself with the {@link SensorManager} if this is the first listener
+ * added. If the ProximitySensor is paused, it will be registered when resumed.
+ */
+ @Override
+ public void register(ThresholdSensor.Listener listener) {
+ mExecution.assertIsMainThread();
+ if (!isLoaded()) {
+ return;
+ }
+
+ if (mListeners.contains(listener)) {
+ logDebug("ProxListener registered multiple times: " + listener);
+ } else {
+ mListeners.add(listener);
+ }
+ registerInternal();
+ }
+
+ protected void registerInternal() {
+ mExecution.assertIsMainThread();
+ if (mRegistered || mPaused || mListeners.isEmpty()) {
+ return;
+ }
+ if (!mInitializedListeners) {
+ mPrimaryThresholdSensor.pause();
+ mSecondaryThresholdSensor.pause();
+ mPrimaryThresholdSensor.register(mPrimaryEventListener);
+ mSecondaryThresholdSensor.register(mSecondaryEventListener);
+ mInitializedListeners = true;
+ }
+
+ mRegistered = true;
+ chooseSensor();
+ }
+
+ private void chooseSensor() {
+ mExecution.assertIsMainThread();
+ if (!mRegistered || mPaused || mListeners.isEmpty()) {
+ return;
+ }
+ if (mSecondarySafe) {
+ mSecondaryThresholdSensor.resume();
+ mPrimaryThresholdSensor.pause();
+ } else {
+ mPrimaryThresholdSensor.resume();
+ mSecondaryThresholdSensor.pause();
+ }
+ }
+
+ /**
+ * Remove a listener.
+ *
+ * If all listeners are removed from an instance of this class,
+ * it will unregister itself with the SensorManager.
+ */
+ @Override
+ public void unregister(ThresholdSensor.Listener listener) {
+ mExecution.assertIsMainThread();
+ mListeners.remove(listener);
+ if (mListeners.size() == 0) {
+ unregisterInternal();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return mPrimaryThresholdSensor.getName();
+ }
+
+ @Override
+ public String getType() {
+ return mPrimaryThresholdSensor.getType();
+ }
+
+ protected void unregisterInternal() {
+ mExecution.assertIsMainThread();
+ if (!mRegistered) {
+ return;
+ }
+ logDebug("unregistering sensor listener");
+ mPrimaryThresholdSensor.pause();
+ mSecondaryThresholdSensor.pause();
+ if (mCancelSecondaryRunnable != null) {
+ mCancelSecondaryRunnable.run();
+ mCancelSecondaryRunnable = null;
+ }
+ mLastPrimaryEvent = null; // Forget what we know.
+ mLastEvent = null;
+ mRegistered = false;
+ }
+
+ @Override
+ public Boolean isNear() {
+ return isLoaded() && mLastEvent != null ? mLastEvent.getBelow() : null;
+ }
+
+ @Override
+ public void alertListeners() {
+ mExecution.assertIsMainThread();
+ if (mAlerting.getAndSet(true)) {
+ return;
+ }
+ if (mLastEvent != null) {
+ ThresholdSensorEvent lastEvent = mLastEvent; // Listeners can null out mLastEvent.
+ List<ThresholdSensor.Listener> listeners = new ArrayList<>(mListeners);
+ listeners.forEach(proximitySensorListener ->
+ proximitySensorListener.onThresholdCrossed(lastEvent));
+ }
+
+ mAlerting.set(false);
+ }
+
+ private void onPrimarySensorEvent(ThresholdSensorEvent event) {
+ mExecution.assertIsMainThread();
+ if (mLastPrimaryEvent != null && event.getBelow() == mLastPrimaryEvent.getBelow()) {
+ return;
+ }
+
+ mLastPrimaryEvent = event;
+
+ if (mSecondarySafe && mSecondaryThresholdSensor.isLoaded()) {
+ logDebug("Primary sensor reported " + (event.getBelow() ? "near" : "far")
+ + ". Checking secondary.");
+ if (mCancelSecondaryRunnable == null) {
+ mSecondaryThresholdSensor.resume();
+ }
+ return;
+ }
+
+
+ if (!mSecondaryThresholdSensor.isLoaded()) { // No secondary
+ logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
+ onSensorEvent(event);
+ } else if (event.getBelow()) { // Covered? Check secondary.
+ logDebug("Primary sensor event: " + event.getBelow() + ". Checking secondary.");
+ if (mCancelSecondaryRunnable != null) {
+ mCancelSecondaryRunnable.run();
+ }
+ mSecondaryThresholdSensor.resume();
+ } else { // Uncovered. Report immediately.
+ onSensorEvent(event);
+ }
+ }
+
+ private void onSensorEvent(ThresholdSensorEvent event) {
+ mExecution.assertIsMainThread();
+ if (mLastEvent != null && event.getBelow() == mLastEvent.getBelow()) {
+ return;
+ }
+
+ if (!mSecondarySafe && !event.getBelow()) {
+ chooseSensor();
+ }
+
+ mLastEvent = event;
+ alertListeners();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{registered=%s, paused=%s, near=%s, posture=%s, primarySensor=%s, "
+ + "secondarySensor=%s secondarySafe=%s}",
+ isRegistered(), mPaused, isNear(), mDevicePosture, mPrimaryThresholdSensor,
+ mSecondaryThresholdSensor, mSecondarySafe);
+ }
+
+ void logDebug(String msg) {
+ if (DEBUG) {
+ Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java
index 11e7df8..0be6068c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java
@@ -16,11 +16,23 @@
package com.android.systemui.util.sensors;
+import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import java.util.HashMap;
+import java.util.Map;
+
+import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -31,8 +43,10 @@
public class SensorModule {
@Provides
@PrimaryProxSensor
- static ThresholdSensor providePrimaryProxSensor(SensorManager sensorManager,
- ThresholdSensorImpl.Builder thresholdSensorBuilder) {
+ static ThresholdSensor providePrimaryProximitySensor(
+ SensorManager sensorManager,
+ ThresholdSensorImpl.Builder thresholdSensorBuilder
+ ) {
try {
return thresholdSensorBuilder
.setSensorDelay(SensorManager.SENSOR_DELAY_NORMAL)
@@ -52,8 +66,9 @@
@Provides
@SecondaryProxSensor
- static ThresholdSensor provideSecondaryProxSensor(
- ThresholdSensorImpl.Builder thresholdSensorBuilder) {
+ static ThresholdSensor provideSecondaryProximitySensor(
+ ThresholdSensorImpl.Builder thresholdSensorBuilder
+ ) {
try {
return thresholdSensorBuilder
.setSensorResourceId(R.string.proximity_sensor_secondary_type, true)
@@ -64,4 +79,153 @@
return thresholdSensorBuilder.setSensor(null).setThresholdValue(0).build();
}
}
+
+ /**
+ * If postures are supported on the device, returns a posture dependent proximity sensor
+ * which switches proximity sensors based on the current posture.
+ *
+ * If postures are not supported the regular {@link ProximitySensorImpl} will be returned.
+ */
+ @Provides
+ static ProximitySensor provideProximitySensor(
+ @Main Resources resources,
+ Lazy<PostureDependentProximitySensor> postureDependentProximitySensorProvider,
+ Lazy<ProximitySensorImpl> proximitySensorProvider
+ ) {
+ if (hasPostureSupport(
+ resources.getStringArray(R.array.proximity_sensor_posture_mapping))) {
+ return postureDependentProximitySensorProvider.get();
+ } else {
+ return proximitySensorProvider.get();
+ }
+ }
+
+ @Provides
+ static ProximityCheck provideProximityCheck(
+ ProximitySensor proximitySensor,
+ @Main DelayableExecutor delayableExecutor
+ ) {
+ return new ProximityCheck(
+ proximitySensor,
+ delayableExecutor
+ );
+ }
+
+ @Provides
+ @PrimaryProxSensor
+ @NonNull
+ static ThresholdSensor[] providePostureToProximitySensorMapping(
+ ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory,
+ @Main Resources resources
+ ) {
+ return createPostureToSensorMapping(
+ thresholdSensorImplBuilderFactory,
+ resources.getStringArray(R.array.proximity_sensor_posture_mapping),
+ R.dimen.proximity_sensor_threshold,
+ R.dimen.proximity_sensor_threshold_latch
+ );
+ }
+
+ @Provides
+ @SecondaryProxSensor
+ @NonNull
+ static ThresholdSensor[] providePostureToSecondaryProximitySensorMapping(
+ ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory,
+ @Main Resources resources
+ ) {
+ return createPostureToSensorMapping(
+ thresholdSensorImplBuilderFactory,
+ resources.getStringArray(R.array.proximity_sensor_secondary_posture_mapping),
+ R.dimen.proximity_sensor_secondary_threshold,
+ R.dimen.proximity_sensor_secondary_threshold_latch
+ );
+ }
+
+ /**
+ * Builds sensors to use per posture.
+ *
+ * @param sensorTypes an array where the index represents
+ * {@link DevicePostureController.DevicePostureInt} and the value
+ * at the given index is the sensorType. Empty values represent
+ * no sensor desired.
+ * @param proximitySensorThresholdResourceId resource id for the threshold for all sensor
+ * postures. This currently only supports one value.
+ * This needs to be updated in the future if postures
+ * use different sensors with differing thresholds.
+ * @param proximitySensorThresholdLatchResourceId resource id for the latch for all sensor
+ * postures. This currently only supports one
+ * value. This needs to be updated in the future
+ * if postures use different sensors with
+ * differing latches.
+ * @return an array where the index represents the device posture
+ * {@link DevicePostureController.DevicePostureInt} and the value at the index is the sensor to
+ * use when the device is in that posture.
+ */
+ @NonNull
+ private static ThresholdSensor[] createPostureToSensorMapping(
+ ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory,
+ String[] sensorTypes,
+ int proximitySensorThresholdResourceId,
+ int proximitySensorThresholdLatchResourceId
+
+ ) {
+ ThresholdSensor noProxSensor = thresholdSensorImplBuilderFactory
+ .createBuilder()
+ .setSensor(null).setThresholdValue(0).build();
+
+
+ // length and index of sensorMap correspond to DevicePostureController.DevicePostureInt:
+ final ThresholdSensor[] sensorMap =
+ new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE];
+ for (int i = 0; i < DevicePostureController.SUPPORTED_POSTURES_SIZE; i++) {
+ sensorMap[i] = noProxSensor;
+ }
+
+ if (!hasPostureSupport(sensorTypes)) {
+ Log.e("SensorModule", "config doesn't support postures,"
+ + " but attempting to retrieve proxSensorMapping");
+ return sensorMap;
+ }
+
+ // Map of sensorType => Sensor, so we reuse the same sensor if it's the same between
+ // postures
+ Map<String, ThresholdSensor> typeToSensorMap = new HashMap<>();
+ for (int i = 0; i < sensorTypes.length; i++) {
+ try {
+ final String sensorType = sensorTypes[i];
+ if (typeToSensorMap.containsKey(sensorType)) {
+ sensorMap[i] = typeToSensorMap.get(sensorType);
+ } else {
+ sensorMap[i] = thresholdSensorImplBuilderFactory
+ .createBuilder()
+ .setSensorType(sensorTypes[i], true)
+ .setThresholdResourceId(proximitySensorThresholdResourceId)
+ .setThresholdLatchResourceId(proximitySensorThresholdLatchResourceId)
+ .build();
+ typeToSensorMap.put(sensorType, sensorMap[i]);
+ }
+ } catch (IllegalStateException e) {
+ // do nothing, sensor at this posture is already set to noProxSensor
+ }
+ }
+
+ return sensorMap;
+ }
+
+ /**
+ * Returns true if there's at least one non-empty sensor type in the given array.
+ */
+ private static boolean hasPostureSupport(String[] postureToSensorTypeMapping) {
+ if (postureToSensorTypeMapping == null || postureToSensorTypeMapping.length == 0) {
+ return false;
+ }
+
+ for (String sensorType : postureToSensorTypeMapping) {
+ if (!TextUtils.isEmpty(sensorType)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensor.java
index 363a734..d81a8d5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensor.java
@@ -16,8 +16,6 @@
package com.android.systemui.util.sensors;
-import java.util.Locale;
-
/**
* A wrapper class for sensors that have a boolean state - above/below.
*/
@@ -77,6 +75,16 @@
void unregister(Listener listener);
/**
+ * Name of the sensor.
+ */
+ String getName();
+
+ /**
+ * Type of the sensor.
+ */
+ String getType();
+
+ /**
* Interface for listening to events on {@link ThresholdSensor}
*/
interface Listener {
@@ -85,34 +93,4 @@
*/
void onThresholdCrossed(ThresholdSensorEvent event);
}
-
- /**
- * Returned when the below/above state of a {@link ThresholdSensor} changes.
- */
- class ThresholdSensorEvent {
- private final boolean mBelow;
- private final long mTimestampNs;
-
- public ThresholdSensorEvent(boolean below, long timestampNs) {
- mBelow = below;
- mTimestampNs = timestampNs;
- }
-
- public boolean getBelow() {
- return mBelow;
- }
-
- public long getTimestampNs() {
- return mTimestampNs;
- }
-
- public long getTimestampMs() {
- return mTimestampNs / 1000000;
- }
-
- @Override
- public String toString() {
- return String.format((Locale) null, "{near=%s, timestamp_ns=%d}", mBelow, mTimestampNs);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorEvent.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorEvent.java
new file mode 100644
index 0000000..afce09f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.sensors;
+
+import java.util.Locale;
+
+/**
+ * Returned when the below/above state of a {@link ThresholdSensor} changes.
+ */
+public class ThresholdSensorEvent {
+ private final boolean mBelow;
+ private final long mTimestampNs;
+
+ public ThresholdSensorEvent(boolean below, long timestampNs) {
+ mBelow = below;
+ mTimestampNs = timestampNs;
+ }
+
+ public boolean getBelow() {
+ return mBelow;
+ }
+
+ public long getTimestampNs() {
+ return mTimestampNs;
+ }
+
+ public long getTimestampMs() {
+ return mTimestampNs / 1000000;
+ }
+
+ @Override
+ public String toString() {
+ return String.format((Locale) null, "{near=%s, timestamp_ns=%d}", mBelow, mTimestampNs);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java
index d10cf9b..a9086b1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java
@@ -21,6 +21,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -32,7 +33,10 @@
import javax.inject.Inject;
-class ThresholdSensorImpl implements ThresholdSensor {
+/**
+ * Sensor that will only trigger beyond some lower and upper threshold.
+ */
+public class ThresholdSensorImpl implements ThresholdSensor {
private static final String TAG = "ThresholdSensor";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -198,6 +202,15 @@
alertListenersInternal(belowThreshold, timestampNs);
}
+ @Override
+ public String getName() {
+ return mSensor != null ? mSensor.getName() : null;
+ }
+
+ @Override
+ public String getType() {
+ return mSensor != null ? mSensor.getStringType() : null;
+ }
@Override
public String toString() {
@@ -211,7 +224,12 @@
}
}
- static class Builder {
+ /**
+ * Use to build a ThresholdSensor. Should only be used once per sensor built, since
+ * parameters are not reset after calls to build(). For ease of retrievingnew Builders, use
+ * {@link BuilderFactory}.
+ */
+ public static class Builder {
private final Resources mResources;
private final AsyncSensorManager mSensorManager;
private final Execution mExecution;
@@ -318,7 +336,7 @@
@VisibleForTesting
Sensor findSensorByType(String sensorType, boolean requireWakeUp) {
- if (sensorType.isEmpty()) {
+ if (TextUtils.isEmpty(sensorType)) {
return null;
}
@@ -336,4 +354,29 @@
return sensor;
}
}
+
+ /**
+ * Factory that creates a new ThresholdSensorImpl.Builder. In general, Builders should not be
+ * reused after creating a ThresholdSensor or else there may be default threshold and sensor
+ * values set from the previous built sensor.
+ */
+ public static class BuilderFactory {
+ private final Resources mResources;
+ private final AsyncSensorManager mSensorManager;
+ private final Execution mExecution;
+
+ @Inject
+ BuilderFactory(
+ @Main Resources resources,
+ AsyncSensorManager sensorManager,
+ Execution execution) {
+ mResources = resources;
+ mSensorManager = sensorManager;
+ mExecution = execution;
+ }
+
+ ThresholdSensorImpl.Builder createBuilder() {
+ return new Builder(mResources, mSensorManager, mExecution);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index f420a85..ff26310 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -28,7 +28,6 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.WMComponent;
import com.android.systemui.dagger.WMSingleton;
-import com.android.wm.shell.FullscreenTaskListener;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellCommandHandlerImpl;
@@ -57,6 +56,8 @@
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
+import com.android.wm.shell.fullscreen.FullscreenTaskListener;
+import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
@@ -79,6 +80,7 @@
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController;
import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
import java.util.Optional;
@@ -218,8 +220,28 @@
@WMSingleton
@Provides
- static FullscreenTaskListener provideFullscreenTaskListener(SyncTransactionQueue syncQueue) {
- return new FullscreenTaskListener(syncQueue);
+ static FullscreenTaskListener provideFullscreenTaskListener(
+ SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> controller) {
+ return new FullscreenTaskListener(syncQueue, controller);
+ }
+
+ //
+ // Unfold transition
+ //
+
+ @WMSingleton
+ @Provides
+ static Optional<FullscreenUnfoldController> provideFullscreenUnfoldController(
+ Context context,
+ Optional<ShellUnfoldProgressProvider> progressProvider,
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ DisplayInsetsController displayInsetsController,
+ @ShellMainThread ShellExecutor mainExecutor
+ ) {
+ return progressProvider.map(shellUnfoldTransitionProgressProvider ->
+ new FullscreenUnfoldController(context, mainExecutor,
+ shellUnfoldTransitionProgressProvider, rootTaskDisplayAreaOrganizer,
+ displayInsetsController));
}
//
@@ -474,6 +496,7 @@
Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
+ Optional<FullscreenUnfoldController> appUnfoldTransitionController,
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
Transitions transitions,
StartingWindowController startingWindow,
@@ -489,6 +512,7 @@
appPairsOptional,
pipTouchHandlerOptional,
fullscreenTaskListener,
+ appUnfoldTransitionController,
freeformTaskListener,
transitions,
startingWindow,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index b688fcc..31fa3f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -53,7 +53,8 @@
import com.android.systemui.util.sensors.FakeProximitySensor;
import com.android.systemui.util.sensors.FakeSensorManager;
import com.android.systemui.util.sensors.FakeThresholdSensor;
-import com.android.systemui.util.sensors.ProximitySensor;
+import com.android.systemui.util.sensors.ProximityCheck;
+import com.android.systemui.util.sensors.ThresholdSensorEvent;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLock;
@@ -80,7 +81,7 @@
@Mock
private DockManager mDockManager;
@Mock
- private ProximitySensor.ProximityCheck mProximityCheck;
+ private ProximityCheck mProximityCheck;
@Mock
private AuthController mAuthController;
@Mock
@@ -136,14 +137,14 @@
mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
clearInvocations(mMachine);
- mProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(true, 1));
+ mProximitySensor.setLastEvent(new ThresholdSensorEvent(true, 1));
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
mProximitySensor.alertListeners();
verify(mMachine, never()).requestState(any());
verify(mMachine, never()).requestPulse(anyInt());
- mProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(false, 2));
+ mProximitySensor.setLastEvent(new ThresholdSensorEvent(false, 2));
mProximitySensor.alertListeners();
waitForSensorManager();
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 07ebaea..baed694 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -75,6 +75,7 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -99,6 +100,7 @@
@Mock private HeadsUpManagerPhone mHeadsUpManager;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
@Mock private TunerService mTunerService;
+ @Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private DynamicPrivacyController mDynamicPrivacyController;
@Mock private ConfigurationController mConfigurationController;
@Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
@@ -152,6 +154,7 @@
mHeadsUpManager,
mNotificationRoundnessManager,
mTunerService,
+ mDeviceProvisionedController,
mDynamicPrivacyController,
mConfigurationController,
mSysuiStatusBarStateController,
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 4e76b16..9f42fa4d 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
@@ -280,6 +280,8 @@
@Test
public void testUpdateFooter_noNotifications() {
setBarStateForTest(StatusBarState.SHADE);
+ mStackScroller.setCurrentUserSetup(true);
+
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
mStackScroller.updateFooter();
@@ -289,6 +291,7 @@
@Test
public void testUpdateFooter_remoteInput() {
setBarStateForTest(StatusBarState.SHADE);
+ mStackScroller.setCurrentUserSetup(true);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(true);
@@ -308,6 +311,7 @@
@Test
public void testUpdateFooter_oneClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
+ mStackScroller.setCurrentUserSetup(true);
when(mEmptyShadeView.getVisibility()).thenReturn(GONE);
when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL))
@@ -321,8 +325,25 @@
}
@Test
+ public void testUpdateFooter_oneClearableNotification_beforeUserSetup() {
+ setBarStateForTest(StatusBarState.SHADE);
+ mStackScroller.setCurrentUserSetup(false);
+
+ when(mEmptyShadeView.getVisibility()).thenReturn(GONE);
+ when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL))
+ .thenReturn(true);
+ when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true);
+
+ FooterView view = mock(FooterView.class);
+ mStackScroller.setFooterView(view);
+ mStackScroller.updateFooter();
+ verify(mStackScroller).updateFooterView(false, true, true);
+ }
+
+ @Test
public void testUpdateFooter_oneNonClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
+ mStackScroller.setCurrentUserSetup(true);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(false);
@@ -341,6 +362,8 @@
@Test
public void testUpdateFooter_atEnd() {
+ mStackScroller.setCurrentUserSetup(true);
+
// add footer
mStackScroller.inflateFooterView();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
index 50947ab..22cf744 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
@@ -19,14 +19,21 @@
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.FakeExecution;
-public class FakeProximitySensor extends ProximitySensor {
+public class FakeProximitySensor extends ProximitySensorImpl {
private boolean mAvailable;
private boolean mRegistered;
- public FakeProximitySensor(ThresholdSensor primary, ThresholdSensor secondary,
- DelayableExecutor delayableExecutor) {
- super(primary, secondary == null ? new FakeThresholdSensor() : secondary,
- delayableExecutor, new FakeExecution());
+ public FakeProximitySensor(
+ ThresholdSensor primary,
+ ThresholdSensor secondary,
+ DelayableExecutor delayableExecutor
+ ) {
+ super(
+ primary,
+ secondary == null ? new FakeThresholdSensor() : secondary,
+ delayableExecutor,
+ new FakeExecution()
+ );
mAvailable = true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeThresholdSensor.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeThresholdSensor.java
index d9f9789..0d4a6c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeThresholdSensor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeThresholdSensor.java
@@ -59,6 +59,16 @@
mListeners.remove(listener);
}
+ @Override
+ public String getName() {
+ return "FakeThresholdSensorName";
+ }
+
+ @Override
+ public String getType() {
+ return "FakeThresholdSensorType";
+ }
+
public void setLoaded(boolean loaded) {
mIsLoaded = loaded;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
new file mode 100644
index 0000000..075f393
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.sensors;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.util.concurrency.FakeExecution;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class PostureDependentProximitySensorTest extends SysuiTestCase {
+ @Mock private Resources mResources;
+ @Mock private DevicePostureController mDevicePostureController;
+ @Mock private AsyncSensorManager mSensorManager;
+
+ @Captor private ArgumentCaptor<DevicePostureController.Callback> mPostureListenerCaptor =
+ ArgumentCaptor.forClass(DevicePostureController.Callback.class);
+ private DevicePostureController.Callback mPostureListener;
+
+ private PostureDependentProximitySensor mProximitySensor;
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ allowTestableLooperAsMainThread();
+
+ mProximitySensor = new PostureDependentProximitySensor(
+ new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE],
+ new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE],
+ mFakeExecutor,
+ new FakeExecution(),
+ mDevicePostureController
+ );
+ }
+
+ @Test
+ public void testPostureChangeListenerAdded() {
+ capturePostureListener();
+ }
+
+ @Test
+ public void testPostureChangeListenerUpdatesPosture() {
+ // GIVEN posture listener is registered
+ capturePostureListener();
+
+ // WHEN the posture changes to DEVICE_POSTURE_OPENED
+ mPostureListener.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED);
+
+ // THEN device posture is updated to DEVICE_POSTURE_OPENED
+ assertEquals(DevicePostureController.DEVICE_POSTURE_OPENED,
+ mProximitySensor.mDevicePosture);
+
+ // WHEN the posture changes to DEVICE_POSTURE_CLOSED
+ mPostureListener.onPostureChanged(DevicePostureController.DEVICE_POSTURE_CLOSED);
+
+ // THEN device posture is updated to DEVICE_POSTURE_CLOSED
+ assertEquals(DevicePostureController.DEVICE_POSTURE_CLOSED,
+ mProximitySensor.mDevicePosture);
+
+ // WHEN the posture changes to DEVICE_POSTURE_FLIPPED
+ mPostureListener.onPostureChanged(DevicePostureController.DEVICE_POSTURE_FLIPPED);
+
+ // THEN device posture is updated to DEVICE_POSTURE_FLIPPED
+ assertEquals(DevicePostureController.DEVICE_POSTURE_FLIPPED,
+ mProximitySensor.mDevicePosture);
+
+ // WHEN the posture changes to DEVICE_POSTURE_HALF_OPENED
+ mPostureListener.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
+
+ // THEN device posture is updated to DEVICE_POSTURE_HALF_OPENED
+ assertEquals(DevicePostureController.DEVICE_POSTURE_HALF_OPENED,
+ mProximitySensor.mDevicePosture);
+ }
+
+ private void capturePostureListener() {
+ verify(mDevicePostureController).addCallback(mPostureListenerCaptor.capture());
+ mPostureListener = mPostureListenerCaptor.getValue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
index 242fe9f..19dbf9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -49,7 +49,7 @@
private TestableCallback mTestableCallback = new TestableCallback();
- private ProximitySensor.ProximityCheck mProximityCheck;
+ private ProximityCheck mProximityCheck;
@Before
public void setUp() throws Exception {
@@ -58,7 +58,7 @@
thresholdSensor.setLoaded(true);
mFakeProximitySensor = new FakeProximitySensor(thresholdSensor, null, mFakeExecutor);
- mProximityCheck = new ProximitySensor.ProximityCheck(mFakeProximitySensor, mFakeExecutor);
+ mProximityCheck = new ProximityCheck(mFakeProximitySensor, mFakeExecutor);
}
@Test
@@ -67,7 +67,7 @@
assertNull(mTestableCallback.mLastResult);
- mFakeProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(true, 0));
+ mFakeProximitySensor.setLastEvent(new ThresholdSensorEvent(true, 0));
mFakeProximitySensor.alertListeners();
assertTrue(mTestableCallback.mLastResult);
@@ -103,7 +103,7 @@
mProximityCheck.check(100, mTestableCallback);
- mFakeProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(true, 0));
+ mFakeProximitySensor.setLastEvent(new ThresholdSensorEvent(true, 0));
mFakeProximitySensor.alertListeners();
assertThat(mTestableCallback.mLastResult).isNotNull();
@@ -123,7 +123,7 @@
assertNull(mTestableCallback.mLastResult);
- mFakeProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(true, 0));
+ mFakeProximitySensor.setLastEvent(new ThresholdSensorEvent(true, 0));
mFakeProximitySensor.alertListeners();
assertTrue(mTestableCallback.mLastResult);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
index 0e9d96c..5e75578 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
@@ -42,7 +42,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class ProximitySensorDualTest extends SysuiTestCase {
+public class ProximitySensorImplDualTest extends SysuiTestCase {
private ProximitySensor mProximitySensor;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private FakeThresholdSensor mThresholdSensorPrimary;
@@ -57,7 +57,7 @@
mThresholdSensorSecondary = new FakeThresholdSensor();
mThresholdSensorSecondary.setLoaded(true);
- mProximitySensor = new ProximitySensor(
+ mProximitySensor = new ProximitySensorImpl(
mThresholdSensorPrimary, mThresholdSensorSecondary, mFakeExecutor,
new FakeExecution());
}
@@ -430,11 +430,11 @@
}
private static class TestableListener implements ThresholdSensor.Listener {
- ThresholdSensor.ThresholdSensorEvent mLastEvent;
+ ThresholdSensorEvent mLastEvent;
int mCallCount = 0;
@Override
- public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+ public void onThresholdCrossed(ThresholdSensorEvent proximityEvent) {
mLastEvent = proximityEvent;
mCallCount++;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorSingleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorSingleTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
index 6c6d355..752cd32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorSingleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
@@ -42,7 +42,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class ProximitySensorSingleTest extends SysuiTestCase {
+public class ProximitySensorImplSingleTest extends SysuiTestCase {
private ProximitySensor mProximitySensor;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private FakeThresholdSensor mThresholdSensor;
@@ -54,7 +54,7 @@
mThresholdSensor = new FakeThresholdSensor();
mThresholdSensor.setLoaded(true);
- mProximitySensor = new ProximitySensor(
+ mProximitySensor = new ProximitySensorImpl(
mThresholdSensor, new FakeThresholdSensor(), mFakeExecutor, new FakeExecution());
}
@@ -215,7 +215,7 @@
public void testPreventRecursiveAlert() {
TestableListener listenerA = new TestableListener() {
@Override
- public void onThresholdCrossed(ProximitySensor.ThresholdSensorEvent proximityEvent) {
+ public void onThresholdCrossed(ThresholdSensorEvent proximityEvent) {
super.onThresholdCrossed(proximityEvent);
if (mCallCount < 2) {
mProximitySensor.alertListeners();
@@ -231,11 +231,11 @@
}
private static class TestableListener implements ThresholdSensor.Listener {
- ThresholdSensor.ThresholdSensorEvent mLastEvent;
+ ThresholdSensorEvent mLastEvent;
int mCallCount = 0;
@Override
- public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+ public void onThresholdCrossed(ThresholdSensorEvent proximityEvent) {
mLastEvent = proximityEvent;
mCallCount++;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java
index 125063a..b10f16c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java
@@ -380,7 +380,7 @@
int mCallCount;
@Override
- public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent event) {
+ public void onThresholdCrossed(ThresholdSensorEvent event) {
mBelow = event.getBelow();
mTimestampNs = event.getTimestampNs();
mCallCount++;
diff --git a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
index 9801407..5080ca2 100644
--- a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
+++ b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
@@ -95,7 +95,7 @@
filter.addAction(ACTION_A11Y_SETTINGS);
filter.addAction(ACTION_DISMISS_NOTIFICATION);
mContext.registerReceiver(mNotificationController, filter,
- Manifest.permission.MANAGE_ACCESSIBILITY, mMainHandler);
+ Manifest.permission.MANAGE_ACCESSIBILITY, mMainHandler, Context.RECEIVER_EXPORTED);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 012c5b1..5e2449d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -209,7 +209,8 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
+ context.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler(),
+ Context.RECEIVER_NOT_EXPORTED);
mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(getContext(),
com.android.internal.R.string.config_defaultAugmentedAutofillService);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index e3b7fdd..7a38a02 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -145,6 +145,7 @@
import java.util.Date;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
@@ -156,6 +157,15 @@
@SuppressLint("LongLogTag")
public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
+ private static final Map<String, String> DEVICE_PROFILE_TO_PERMISSION;
+ static {
+ final Map<String, String> map = new ArrayMap<>();
+ map.put(AssociationRequest.DEVICE_PROFILE_WATCH,
+ Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH);
+
+ DEVICE_PROFILE_TO_PERMISSION = Collections.unmodifiableMap(map);
+ }
+
private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
".CompanionDeviceDiscoveryService");
@@ -429,7 +439,8 @@
checkCallerIsSystemOr(callingPackage);
int userId = getCallingUserId();
checkUsesFeature(callingPackage, userId);
- checkProfilePermissions(request);
+ final String deviceProfile = request.getDeviceProfile();
+ validateDeviceProfileAndCheckPermission(deviceProfile);
mFindDeviceCallback = callback;
mRequest = request;
@@ -442,13 +453,8 @@
}
callback.asBinder().linkToDeath(CompanionDeviceManagerService.this /* recipient */, 0);
- AndroidFuture<String> fetchProfileDescription =
- request.getDeviceProfile() == null
- ? AndroidFuture.completedFuture(null)
- : getDeviceProfilePermissionDescription(
- request.getDeviceProfile());
-
- mOngoingDeviceDiscovery = fetchProfileDescription.thenComposeAsync(description -> {
+ mOngoingDeviceDiscovery = getDeviceProfilePermissionDescription(deviceProfile)
+ .thenComposeAsync(description -> {
Slog.d(LOG_TAG, "fetchProfileDescription done: " + description);
request.setDeviceProfilePrivilegesDescription(description);
@@ -464,8 +470,7 @@
}, FgThread.getExecutor()).whenComplete(uncheckExceptions((deviceAddress, err) -> {
if (err == null) {
Association association = new Association(userId, deviceAddress, callingPackage,
- mRequest.getDeviceProfile(), false,
- System.currentTimeMillis());
+ deviceProfile, false, System.currentTimeMillis());
addAssociation(association, userId);
} else {
Slog.e(LOG_TAG, "Failed to discover device(s)", err);
@@ -542,18 +547,18 @@
}
}
- private void checkProfilePermissions(AssociationRequest request) {
- checkProfilePermission(request,
- AssociationRequest.DEVICE_PROFILE_WATCH,
- Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH);
- }
+ private void validateDeviceProfileAndCheckPermission(@Nullable String deviceProfile) {
+ // Device profile can be null.
+ if (deviceProfile == null) return;
- private void checkProfilePermission(
- AssociationRequest request, String profile, String permission) {
- if (profile.equals(request.getDeviceProfile())
- && getContext().checkCallingOrSelfPermission(permission)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Using " + profile + " requires " + permission);
+ if (!DEVICE_PROFILE_TO_PERMISSION.containsKey(deviceProfile)) {
+ throw new IllegalArgumentException("Unsupported device profile: " + deviceProfile);
+ }
+
+ final String permission = DEVICE_PROFILE_TO_PERMISSION.get(deviceProfile);
+ if (getContext().checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
+ throw new SecurityException("Application must hold " + permission + " to associate "
+ + "with a device with " + deviceProfile + " profile.");
}
}
@@ -1517,8 +1522,14 @@
return result;
}
- private AndroidFuture<String> getDeviceProfilePermissionDescription(String deviceProfile) {
- AndroidFuture<String> result = new AndroidFuture<>();
+ @NonNull
+ private AndroidFuture<String> getDeviceProfilePermissionDescription(
+ @Nullable String deviceProfile) {
+ if (deviceProfile == null) {
+ return AndroidFuture.completedFuture(null);
+ }
+
+ final AndroidFuture<String> result = new AndroidFuture<>();
mPermissionControllerManager.getPrivilegesDescriptionStringForProfile(
deviceProfile, FgThread.getExecutor(), desc -> {
try {
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 57ce342..19f8f38 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -347,7 +347,7 @@
intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
}
}, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY),
- MANAGE_SENSOR_PRIVACY, null);
+ MANAGE_SENSOR_PRIVACY, null, Context.RECEIVER_EXPORTED);
mUserManagerInternal.addUserRestrictionsListener(this);
}
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index a03425c..b48e21e 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -681,7 +681,7 @@
intentFilter = new IntentFilter();
intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
mUserAllContext.registerReceiver(
- mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
+ mIntentReceiver, intentFilter, NETWORK_STACK, mHandler, Context.RECEIVER_EXPORTED);
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 46efa3c..e7b078a 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -143,6 +143,8 @@
);
public static final String[] AIDL_INTERFACE_PREFIXES_OF_INTEREST = new String[] {
+ "android.hardware.biometrics.face.IFace/",
+ "android.hardware.biometrics.fingerprint.IFingerprint/",
"android.hardware.light.ILights/",
"android.hardware.power.stats.IPowerStats/",
};
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6a63254..5330252 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5091,14 +5091,19 @@
@Override
public PendingIntentInfo getInfoForIntentSender(IIntentSender sender) {
if (sender instanceof PendingIntentRecord) {
- PendingIntentRecord res = (PendingIntentRecord) sender;
+ final PendingIntentRecord res = (PendingIntentRecord) sender;
+ final String packageName = res.key.packageName;
+ final int uid = res.uid;
+ final boolean shouldFilter = getPackageManagerInternal().filterAppAccess(
+ packageName, Binder.getCallingUid(), UserHandle.getUserId(uid));
return new PendingIntentInfo(
- res.key.packageName,
- res.uid,
+ shouldFilter ? null : packageName,
+ shouldFilter ? INVALID_UID : uid,
(res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0,
res.key.type);
} else {
- return new PendingIntentInfo(null, -1, false, ActivityManager.INTENT_SENDER_UNKNOWN);
+ return new PendingIntentInfo(null, INVALID_UID, false,
+ ActivityManager.INTENT_SENDER_UNKNOWN);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 289396e..3aa7ab9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1122,7 +1122,8 @@
intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
- mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null,
+ Context.RECEIVER_EXPORTED);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
index dc5dace9..a0befea 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
@@ -79,7 +79,7 @@
mLockoutReceiver = new LockoutReceiver();
context.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
- RESET_FINGERPRINT_LOCKOUT, null /* handler */);
+ RESET_FINGERPRINT_LOCKOUT, null /* handler */, Context.RECEIVER_EXPORTED);
}
// Attempt counter should only be cleared when Keyguard goes away or when
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d6c28e2..87b9e6a 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
+import static android.os.PowerManager.BRIGHTNESS_INVALID;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,6 +41,7 @@
import android.os.IThermalService;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -61,6 +63,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.display.utils.AmbientFilter;
@@ -153,7 +156,7 @@
mAppRequestObserver = new AppRequestObserver();
mSettingsObserver = new SettingsObserver(context, handler);
mDisplayObserver = new DisplayObserver(context, handler);
- mBrightnessObserver = new BrightnessObserver(context, handler);
+ mBrightnessObserver = new BrightnessObserver(context, handler, injector);
mUdfpsObserver = new UdfpsObserver();
final BallotBox ballotBox = (displayId, priority, vote) -> {
synchronized (mLock) {
@@ -1425,8 +1428,6 @@
@Override
public void onDisplayChanged(int displayId) {
updateDisplayModes(displayId);
- // TODO: Break the coupling between DisplayObserver and BrightnessObserver.
- mBrightnessObserver.onDisplayChanged(displayId);
}
private void updateDisplayModes(int displayId) {
@@ -1463,7 +1464,7 @@
* {@link R.array#config_ambientThresholdsOfPeakRefreshRate}.
*/
@VisibleForTesting
- public class BrightnessObserver extends ContentObserver {
+ public class BrightnessObserver implements DisplayManager.DisplayListener {
private final static int LIGHT_SENSOR_RATE_MS = 250;
private int[] mLowDisplayBrightnessThresholds;
private int[] mLowAmbientBrightnessThresholds;
@@ -1486,6 +1487,8 @@
private int mBrightness = -1;
private final Context mContext;
+ private final Injector mInjector;
+ private final Handler mHandler;
// Enable light sensor only when mShouldObserveAmbientLowChange is true or
// mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate
@@ -1498,9 +1501,11 @@
private int mRefreshRateInLowZone;
private int mRefreshRateInHighZone;
- BrightnessObserver(Context context, Handler handler) {
- super(handler);
+ BrightnessObserver(Context context, Handler handler, Injector injector) {
mContext = context;
+ mHandler = handler;
+ mInjector = injector;
+
mLowDisplayBrightnessThresholds = context.getResources().getIntArray(
R.array.config_brightnessThresholdsOfPeakRefreshRate);
mLowAmbientBrightnessThresholds = context.getResources().getIntArray(
@@ -1567,8 +1572,7 @@
public void observe(SensorManager sensorManager) {
mSensorManager = sensorManager;
final ContentResolver cr = mContext.getContentResolver();
- mBrightness = Settings.System.getIntForUser(cr,
- Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
+ mBrightness = getBrightness(Display.DEFAULT_DISPLAY);
// DeviceConfig is accessible after system ready.
int[] lowDisplayBrightnessThresholds =
@@ -1601,6 +1605,10 @@
restartObserver();
mDeviceConfigDisplaySettings.startListening();
+
+ mInjector.registerDisplayListener(this, mHandler,
+ DisplayManager.EVENT_FLAG_DISPLAY_CHANGED |
+ DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
}
public void setLoggingEnabled(boolean loggingEnabled) {
@@ -1716,28 +1724,30 @@
}
}
+ @Override
+ public void onDisplayAdded(int displayId) {}
+
+ @Override
+ public void onDisplayRemoved(int displayId) {}
+
+ @Override
public void onDisplayChanged(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
updateDefaultDisplayState();
- }
- }
- @Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- synchronized (mLock) {
- final ContentResolver cr = mContext.getContentResolver();
- int brightness = Settings.System.getIntForUser(cr,
- Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
- if (brightness != mBrightness) {
- mBrightness = brightness;
- onBrightnessChangedLocked();
+ // We don't support multiple display blocking zones yet, so only handle
+ // brightness changes for the default display for now.
+ int brightness = getBrightness(displayId);
+ synchronized (mLock) {
+ if (brightness != mBrightness) {
+ mBrightness = brightness;
+ onBrightnessChangedLocked();
+ }
}
}
}
private void restartObserver() {
- final ContentResolver cr = mContext.getContentResolver();
-
if (mRefreshRateInLowZone > 0) {
mShouldObserveDisplayLowChange = hasValidThreshold(
mLowDisplayBrightnessThresholds);
@@ -1758,15 +1768,6 @@
mShouldObserveAmbientHighChange = false;
}
- if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) {
- // Content Service does not check if an listener has already been registered.
- // To ensure only one listener is registered, force an unregistration first.
- mInjector.unregisterBrightnessObserver(cr, this);
- mInjector.registerBrightnessObserver(cr, this);
- } else {
- mInjector.unregisterBrightnessObserver(cr, this);
- }
-
if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) {
Resources resources = mContext.getResources();
String lightSensorType = resources.getString(
@@ -1966,6 +1967,15 @@
return mDefaultDisplayState == Display.STATE_ON;
}
+ private int getBrightness(int displayId) {
+ final BrightnessInfo info = mInjector.getBrightnessInfo(displayId);
+ if (info != null) {
+ return BrightnessSynchronizer.brightnessFloatToInt(info.adjustedBrightness);
+ }
+
+ return BRIGHTNESS_INVALID;
+ }
+
private final class LightSensorEventListener implements SensorEventListener {
final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
private float mLastSensorData;
@@ -2283,6 +2293,7 @@
private final BallotBox mBallotBox;
private final Handler mHandler;
private final SparseIntArray mHbmMode = new SparseIntArray();
+ private final SparseBooleanArray mHbmActive = new SparseBooleanArray();
private final Injector mInjector;
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
private int mRefreshRateInHbmSunlight;
@@ -2351,6 +2362,7 @@
public void onDisplayRemoved(int displayId) {
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
mHbmMode.delete(displayId);
+ mHbmActive.delete(displayId);
}
@Override
@@ -2360,12 +2372,17 @@
// Display no longer there. Assume we'll get an onDisplayRemoved very soon.
return;
}
+
final int hbmMode = info.highBrightnessMode;
- if (hbmMode == mHbmMode.get(displayId)) {
+ final boolean isHbmActive = hbmMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF &&
+ info.adjustedBrightness > info.highBrightnessTransitionPoint;
+ if (hbmMode == mHbmMode.get(displayId) &&
+ isHbmActive == mHbmActive.get(displayId)) {
// no change, ignore.
return;
}
mHbmMode.put(displayId, hbmMode);
+ mHbmActive.put(displayId, isHbmActive);
recalculateVotesForDisplay(displayId);
}
@@ -2379,28 +2396,36 @@
}
private void recalculateVotesForDisplay(int displayId) {
- final int hbmMode = mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
Vote vote = null;
- if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
- // Device resource properties take priority over DisplayDeviceConfig
- if (mRefreshRateInHbmSunlight > 0) {
- vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight,
- mRefreshRateInHbmSunlight);
- } else {
- final List<RefreshRateLimitation> limits =
- mDisplayManagerInternal.getRefreshRateLimitations(displayId);
- for (int i = 0; limits != null && i < limits.size(); i++) {
- final RefreshRateLimitation limitation = limits.get(i);
- if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
- vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max);
- break;
+ if (mHbmActive.get(displayId, false)) {
+ final int hbmMode =
+ mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
+ if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
+ // Device resource properties take priority over DisplayDeviceConfig
+ if (mRefreshRateInHbmSunlight > 0) {
+ vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight,
+ mRefreshRateInHbmSunlight);
+ } else {
+ final List<RefreshRateLimitation> limits =
+ mDisplayManagerInternal.getRefreshRateLimitations(displayId);
+ for (int i = 0; limits != null && i < limits.size(); i++) {
+ final RefreshRateLimitation limitation = limits.get(i);
+ if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
+ vote = Vote.forRefreshRates(limitation.range.min,
+ limitation.range.max);
+ break;
+ }
}
}
+ } else if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR &&
+ mRefreshRateInHbmHdr > 0) {
+ // HBM for HDR vote isn't supported through DisplayDeviceConfig yet, so look for
+ // a vote from Device properties
+ vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr);
+ } else {
+ Slog.w(TAG, "Unexpected HBM mode " + hbmMode + " for display ID " + displayId);
}
- }
- if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
- && mRefreshRateInHbmHdr > 0) {
- vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr);
+
}
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
}
@@ -2408,6 +2433,7 @@
void dumpLocked(PrintWriter pw) {
pw.println(" HbmObserver");
pw.println(" mHbmMode: " + mHbmMode);
+ pw.println(" mHbmActive: " + mHbmActive);
pw.println(" mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight);
pw.println(" mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr);
}
@@ -2630,19 +2656,11 @@
}
interface Injector {
- // TODO: brightnessfloat: change this to the float setting
- Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
@NonNull
DeviceConfigInterface getDeviceConfig();
- void registerBrightnessObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer);
-
- void unregisterBrightnessObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer);
-
void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer);
@@ -2672,19 +2690,6 @@
}
@Override
- public void registerBrightnessObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/,
- observer, UserHandle.USER_SYSTEM);
- }
-
- @Override
- public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- cr.unregisterContentObserver(observer);
- }
-
- @Override
public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer) {
cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1063481..bf5208a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1259,10 +1259,6 @@
putScreenBrightnessSetting(brightnessState, /* updateCurrent */ true);
}
- // We save the brightness info *after* the brightness setting has been changed so that
- // the brightness info reflects the latest value.
- saveBrightnessInfo(getScreenBrightnessSetting());
-
// Apply dimming by at least some minimum amount when user activity
// timeout is about to expire.
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
@@ -1393,6 +1389,11 @@
hadUserBrightnessPoint);
}
+ // We save the brightness info *after* the brightness setting has been changed and
+ // adjustments made so that the brightness info reflects the latest value.
+ saveBrightnessInfo(getScreenBrightnessSetting(), animateValue);
+ } else {
+ saveBrightnessInfo(getScreenBrightnessSetting());
}
// Log any changes to what is currently driving the brightness setting.
@@ -1509,18 +1510,27 @@
synchronized (mCachedBrightnessInfo) {
return new BrightnessInfo(
mCachedBrightnessInfo.brightness,
+ mCachedBrightnessInfo.adjustedBrightness,
mCachedBrightnessInfo.brightnessMin,
mCachedBrightnessInfo.brightnessMax,
- mCachedBrightnessInfo.hbmMode);
+ mCachedBrightnessInfo.hbmMode,
+ mCachedBrightnessInfo.highBrightnessTransitionPoint);
}
}
private void saveBrightnessInfo(float brightness) {
+ saveBrightnessInfo(brightness, brightness);
+ }
+
+ private void saveBrightnessInfo(float brightness, float adjustedBrightness) {
synchronized (mCachedBrightnessInfo) {
mCachedBrightnessInfo.brightness = brightness;
+ mCachedBrightnessInfo.adjustedBrightness = adjustedBrightness;
mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin();
mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax();
mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode();
+ mCachedBrightnessInfo.highBrightnessTransitionPoint =
+ mHbmController.getTransitionPoint();
}
}
@@ -2195,6 +2205,18 @@
pw.println(" mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp);
pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig);
pw.println(" mColorFadeEnabled=" + mColorFadeEnabled);
+ synchronized (mCachedBrightnessInfo) {
+ pw.println(" mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness);
+ pw.println(" mCachedBrightnessInfo.adjustedBrightness=" +
+ mCachedBrightnessInfo.adjustedBrightness);
+ pw.println(" mCachedBrightnessInfo.brightnessMin=" +
+ mCachedBrightnessInfo.brightnessMin);
+ pw.println(" mCachedBrightnessInfo.brightnessMax=" +
+ mCachedBrightnessInfo.brightnessMax);
+ pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode);
+ pw.println(" mCachedBrightnessInfo.highBrightnessTransitionPoint=" +
+ mCachedBrightnessInfo.highBrightnessTransitionPoint);
+ }
pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
@@ -2606,8 +2628,10 @@
static class CachedBrightnessInfo {
public float brightness;
+ public float adjustedBrightness;
public float brightnessMin;
public float brightnessMax;
public int hbmMode;
+ public float highBrightnessTransitionPoint;
}
}
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 2791f6a..1e1cfeb 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -59,6 +59,9 @@
private static final float HDR_PERCENT_OF_SCREEN_REQUIRED = 0.50f;
+ @VisibleForTesting
+ static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;
+
private final float mBrightnessMin;
private final float mBrightnessMax;
private final Handler mHandler;
@@ -214,6 +217,14 @@
return mHbmMode;
}
+ float getTransitionPoint() {
+ if (deviceSupportsHbm()) {
+ return mHbmData.transitionPoint;
+ } else {
+ return HBM_TRANSITION_POINT_INVALID;
+ }
+ }
+
void stop() {
registerHdrListener(null /*displayToken*/);
mSkinThermalStatusObserver.stopObserving();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index aba7d39..c2ed24a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -568,10 +568,8 @@
}
}
- if (!mService.isPowerStandbyOrTransient()) {
- addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
- activeSource.physicalAddress, deviceType));
- }
+ addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
+ activeSource.physicalAddress, deviceType));
}
private boolean handleNewDeviceAtTheTailOfActivePath(int path) {
@@ -723,14 +721,12 @@
@ServiceThreadOnly
void onNewAvrAdded(HdmiDeviceInfo avr) {
assertRunOnServiceThread();
- if (!mService.isPowerStandbyOrTransient()) {
- addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
- if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
- startArcAction(false);
- } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
- && !hasAction(SetArcTransmissionStateAction.class)) {
- startArcAction(true);
- }
+ addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
+ if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
+ startArcAction(false);
+ } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+ && !hasAction(SetArcTransmissionStateAction.class)) {
+ startArcAction(true);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 075b74d..cfc32ce 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1798,7 +1798,8 @@
final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
- UserHandle.ALL, broadcastFilterForAllUsers, null, null);
+ UserHandle.ALL, broadcastFilterForAllUsers, null, null,
+ Context.RECEIVER_NOT_EXPORTED);
final String defaultImiId = mSettings.getSelectedInputMethod();
final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index f2ccf9f..6e2fe52 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -41,7 +41,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
@@ -49,6 +48,7 @@
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.pm.pkg.PackageUserState;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -598,7 +598,7 @@
0,
0,
null,
- new PackageUserState(),
+ PackageUserState.DEFAULT,
UserHandle.getCallingUserId(),
null);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 84be7f5..d37c1c8 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -976,7 +976,8 @@
// listen for restrict background changes from notifications
final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
- mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
+ mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler,
+ Context.RECEIVER_EXPORTED);
// Listen for snooze from notifications
mContext.registerReceiver(mSnoozeReceiver,
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index ed1f5f5..3fc4169 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -356,7 +356,7 @@
return false;
}
- if (Math.abs(exitInfo.getTimestamp() - mTimestampMs) > 1000) {
+ if (Math.abs(exitInfo.getTimestamp() - mTimestampMs) > 5000) {
return false;
}
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 75dbf04..d6b9c34 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -33,7 +33,6 @@
import android.content.pm.InstantAppResolveInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageUserState;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -43,6 +42,7 @@
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.pkg.PackageUserState;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1549,7 +1549,7 @@
&& (!matchExplicitlyVisibleOnly || info.isExplicitlyVisibleToInstantApp());
final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to ephemeral apps
- if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) {
+ if (matchVisibleToInstantApp && !(componentVisible || userState.isInstantApp())) {
if (DEBUG) {
log("Filter(s) not visible to ephemeral apps"
+ "; matchVisibleToInstantApp=" + matchVisibleToInstantApp
@@ -1563,7 +1563,7 @@
return null;
}
// throw out instant app filters if we're not explicitly requesting them
- if (!matchInstantApp && userState.instantApp) {
+ if (!matchInstantApp && userState.isInstantApp()) {
if (DEBUG) {
log("Instant app filter is not explicitly requested", info, match, userId);
}
@@ -1571,7 +1571,7 @@
}
// throw out instant app filters if updates are available; will trigger
// instant app resolution
- if (userState.instantApp && ps.isUpdateAvailable()) {
+ if (userState.isInstantApp() && ps.isUpdateAvailable()) {
if (DEBUG) {
log("Instant app update is available", info, match, userId);
}
@@ -1599,7 +1599,7 @@
}
res.iconResourceId = info.getIcon();
res.system = res.activityInfo.applicationInfo.isSystemApp();
- res.isInstantAppAvailable = userState.instantApp;
+ res.isInstantAppAvailable = userState.isInstantApp();
return res;
}
@@ -1846,16 +1846,16 @@
final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to instant applications
if (matchVisibleToInstantApp
- && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
+ && !(filter.isVisibleToInstantApp() || userState.isInstantApp())) {
return null;
}
// throw out instant application filters if we're not explicitly requesting them
- if (!isInstantApp && userState.instantApp) {
+ if (!isInstantApp && userState.isInstantApp()) {
return null;
}
// throw out instant application filters if updates are available; will trigger
// instant application resolution
- if (userState.instantApp && ps.isUpdateAvailable()) {
+ if (userState.isInstantApp() && ps.isUpdateAvailable()) {
return null;
}
final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(
@@ -2093,16 +2093,16 @@
final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to ephemeral apps
if (matchVisibleToInstantApp
- && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
+ && !(filter.isVisibleToInstantApp() || userState.isInstantApp())) {
return null;
}
// throw out ephemeral filters if we're not explicitly requesting them
- if (!isInstantApp && userState.instantApp) {
+ if (!isInstantApp && userState.isInstantApp()) {
return null;
}
// throw out instant app filters if updates are available; will trigger
// instant app resolution
- if (userState.instantApp && ps.isUpdateAvailable()) {
+ if (userState.isInstantApp() && ps.isUpdateAvailable()) {
return null;
}
final ResolveInfo res = new ResolveInfo();
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 9addf0e..34e9428 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -68,7 +68,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
@@ -81,6 +80,8 @@
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.os.Binder;
import android.os.PatternMatcher;
import android.os.Process;
@@ -647,7 +648,7 @@
}
if (resolveComponentName().equals(component)) {
return PackageInfoWithoutStateUtils.generateDelegateActivityInfo(mResolveActivity,
- flags, new PackageUserState(), userId);
+ flags, PackageUserState.DEFAULT, userId);
}
return null;
}
@@ -1312,8 +1313,8 @@
}
final PackageSetting ps =
mSettings.getPackageLPr(instantAppInstallerActivity().packageName);
- if (ps == null
- || !ps.readUserState(userId).isEnabled(instantAppInstallerActivity(), 0)) {
+ if (ps == null || !PackageUserStateUtils.isEnabled(ps.readUserState(userId),
+ instantAppInstallerActivity(), 0)) {
return result;
}
final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
@@ -1388,7 +1389,8 @@
resolveExternalPackageNameLPr(p);
return packageInfo;
- } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) {
+ } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
+ && PackageUserStateUtils.isAvailable(state, flags)) {
PackageInfo pi = new PackageInfo();
pi.packageName = ps.getPackageName();
pi.setLongVersionCode(ps.getVersionCode());
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 4e2b978..5b692b0 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -41,9 +41,9 @@
import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
-import android.content.pm.PackageUserState;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.pkg.PackageUserState;
import android.net.Uri;
import android.os.Binder;
import android.os.Process;
@@ -201,8 +201,8 @@
for (int i = 0; i < allUsers.length; i++) {
PackageUserState userState = uninstalledPs.readUserState(allUsers[i]);
priorUserStates.put(allUsers[i],
- new TempUserState(userState.enabled, userState.lastDisableAppCaller,
- userState.installed));
+ new TempUserState(userState.getEnabledState(),
+ userState.getLastDisableAppCaller(), userState.isInstalled()));
}
} else {
freezeUser = removeUser;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a224b81..df54030 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -62,7 +62,6 @@
import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
-import static com.android.server.pm.parsing.PackageInfoUtils.checkUseInstalledOrHidden;
import android.Manifest;
import android.annotation.AppIdInt;
@@ -138,7 +137,6 @@
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
import android.content.pm.PackagePartitions;
-import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -166,6 +164,9 @@
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateInternal;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -2842,7 +2843,7 @@
if (ps != null) {
final PackageUserState state = ps.readUserState(userId);
if (state != null) {
- return checkUseInstalledOrHidden(p, ps, state, 0 /*flags*/);
+ return PackageUserStateUtils.isAvailable(state, 0);
}
}
}
@@ -3577,7 +3578,7 @@
continue;
}
- if (!ps.readUserState(userId).isAvailable(flags)) {
+ if (!PackageUserStateUtils.isAvailable(ps.readUserState(userId), flags)) {
continue;
}
@@ -7164,7 +7165,7 @@
// The instance stored in PackageManagerService is special cased to be non-user
// specific, so initialize all the needed fields here.
mAndroidApplication = PackageInfoUtils.generateApplicationInfo(pkg, 0,
- new PackageUserState(), UserHandle.USER_SYSTEM, pkgSetting);
+ PackageUserState.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting);
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
@@ -7314,7 +7315,7 @@
// The instance created in PackageManagerService is special cased to be non-user
// specific, so initialize all the needed fields here.
ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0,
- new PackageUserState(), UserHandle.USER_SYSTEM, pkgSetting);
+ PackageUserState.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting);
// Set up information for custom user intent resolution activity.
mResolveActivity.applicationInfo = appInfo;
@@ -8102,11 +8103,11 @@
if (ps == null) {
return null;
}
- final PackageUserState pus = ps.readUserState(userId);
+ final PackageUserStateInternal pus = ps.readUserState(userId);
final Bundle allExtras = new Bundle();
- if (pus.suspended) {
- for (int i = 0; i < pus.suspendParams.size(); i++) {
- final PackageUserState.SuspendParams params = pus.suspendParams.valueAt(i);
+ if (pus.isSuspended()) {
+ for (int i = 0; i < pus.getSuspendParams().size(); i++) {
+ final PackageUserState.SuspendParams params = pus.getSuspendParams().valueAt(i);
if (params != null && params.appExtras != null) {
allExtras.putAll(params.appExtras);
}
@@ -13692,11 +13693,11 @@
final PackageSetting ps = mSettings.getPackageLPr(packageName);
final Bundle allExtras = new Bundle();
if (ps != null) {
- final PackageUserState pus = ps.readUserState(userId);
- if (pus.suspended) {
- for (int i = 0; i < pus.suspendParams.size(); i++) {
+ final PackageUserStateInternal pus = ps.readUserState(userId);
+ if (pus.isSuspended()) {
+ for (int i = 0; i < pus.getSuspendParams().size(); i++) {
final PackageUserState.SuspendParams params =
- pus.suspendParams.valueAt(i);
+ pus.getSuspendParams().valueAt(i);
if (params != null && params.launcherExtras != null) {
allExtras.putAll(params.launcherExtras);
}
@@ -13758,11 +13759,11 @@
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage);
if (ps != null) {
- final PackageUserState pus = ps.readUserState(userId);
- if (pus.suspended) {
+ final PackageUserStateInternal pus = ps.readUserState(userId);
+ if (pus.isSuspended()) {
String suspendingPackage = null;
- for (int i = 0; i < pus.suspendParams.size(); i++) {
- suspendingPackage = pus.suspendParams.keyAt(i);
+ for (int i = 0; i < pus.getSuspendParams().size(); i++) {
+ suspendingPackage = pus.getSuspendParams().keyAt(i);
if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
return suspendingPackage;
}
@@ -13780,10 +13781,10 @@
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage);
if (ps != null) {
- final PackageUserState pus = ps.readUserState(userId);
- if (pus.suspended) {
+ final PackageUserStateInternal pus = ps.readUserState(userId);
+ if (pus.isSuspended()) {
final PackageUserState.SuspendParams suspendParams =
- pus.suspendParams.get(suspendingPackage);
+ pus.getSuspendParams().get(suspendingPackage);
return (suspendParams != null) ? suspendParams.dialogInfo : null;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7d99ba1..1a5415c 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -27,13 +27,14 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageUserState;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateInternal;
import android.os.PersistableBundle;
import android.os.incremental.IncrementalManager;
import android.service.pm.PackageProto;
@@ -51,6 +52,7 @@
import com.android.server.pm.pkg.AndroidPackageApi;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateUnserialized;
+import com.android.server.pm.pkg.PackageUserStateInternalImpl;
import com.android.server.utils.SnapshotCache;
import libcore.util.EmptyArray;
@@ -75,8 +77,6 @@
@DataClass.Suppress({"getSnapshot", })
public class PackageSetting extends SettingBase implements PackageState {
- static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
-
/**
* Temporary holding space for the shared user ID. While parsing package settings, the
* shared users tag may come after the packages. In this case, we must delay linking the
@@ -183,8 +183,7 @@
// TODO: Access is not locked.
// Whether this package is currently stopped, thus can not be
// started until explicitly launched by the user.
- @NonNull
- private final SparseArray<PackageUserState> mUserState = new SparseArray<>();
+ private final SparseArray<PackageUserStateInternalImpl> mUserState = new SparseArray<>();
@NonNull
private InstallSource installSource;
@@ -668,10 +667,10 @@
}
@VisibleForTesting
- PackageUserState modifyUserState(int userId) {
- PackageUserState state = mUserState.get(userId);
+ PackageUserStateInternalImpl modifyUserState(int userId) {
+ PackageUserStateInternalImpl state = mUserState.get(userId);
if (state == null) {
- state = new PackageUserState();
+ state = new PackageUserStateInternalImpl();
mUserState.put(userId, state);
onChanged();
}
@@ -679,10 +678,10 @@
}
@NonNull
- public PackageUserState readUserState(int userId) {
- PackageUserState state = mUserState.get(userId);
+ public PackageUserStateInternal readUserState(int userId) {
+ PackageUserStateInternal state = mUserState.get(userId);
if (state == null) {
- return DEFAULT_USER_STATE;
+ return PackageUserStateInternal.DEFAULT;
}
return state;
}
@@ -693,42 +692,42 @@
}
void setEnabled(int state, int userId, String callingPackage) {
- PackageUserState st = modifyUserState(userId);
- st.enabled = state;
- st.lastDisableAppCaller = callingPackage;
+ modifyUserState(userId)
+ .setEnabledState(state)
+ .setLastDisableAppCaller(callingPackage);
onChanged();
}
int getEnabled(int userId) {
- return readUserState(userId).enabled;
+ return readUserState(userId).getEnabledState();
}
String getLastDisabledAppCaller(int userId) {
- return readUserState(userId).lastDisableAppCaller;
+ return readUserState(userId).getLastDisableAppCaller();
}
void setInstalled(boolean inst, int userId) {
- modifyUserState(userId).installed = inst;
+ modifyUserState(userId).setInstalled(inst);
}
boolean getInstalled(int userId) {
- return readUserState(userId).installed;
+ return readUserState(userId).isInstalled();
}
int getInstallReason(int userId) {
- return readUserState(userId).installReason;
+ return readUserState(userId).getInstallReason();
}
void setInstallReason(int installReason, int userId) {
- modifyUserState(userId).installReason = installReason;
+ modifyUserState(userId).setInstallReason(installReason);
}
int getUninstallReason(int userId) {
- return readUserState(userId).uninstallReason;
+ return readUserState(userId).getUninstallReason();
}
void setUninstallReason(@PackageManager.UninstallReason int uninstallReason, int userId) {
- modifyUserState(userId).uninstallReason = uninstallReason;
+ modifyUserState(userId).setUninstallReason(uninstallReason);
}
boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) {
@@ -751,13 +750,13 @@
/** Only use for testing. Do NOT use in production code. */
@VisibleForTesting
- SparseArray<PackageUserState> getUserState() {
+ SparseArray<PackageUserStateInternalImpl> getUserState() {
return mUserState;
}
boolean isAnyInstalled(int[] users) {
for (int user: users) {
- if (readUserState(user).installed) {
+ if (readUserState(user).isInstalled()) {
return true;
}
}
@@ -783,117 +782,118 @@
}
long getCeDataInode(int userId) {
- return readUserState(userId).ceDataInode;
+ return readUserState(userId).getCeDataInode();
}
void setCeDataInode(long ceDataInode, int userId) {
- modifyUserState(userId).ceDataInode = ceDataInode;
+ modifyUserState(userId).setCeDataInode(ceDataInode);
}
boolean getStopped(int userId) {
- return readUserState(userId).stopped;
+ return readUserState(userId).isStopped();
}
void setStopped(boolean stop, int userId) {
- modifyUserState(userId).stopped = stop;
+ modifyUserState(userId).setStopped(stop);
}
boolean getNotLaunched(int userId) {
- return readUserState(userId).notLaunched;
+ return readUserState(userId).isNotLaunched();
}
void setNotLaunched(boolean stop, int userId) {
- modifyUserState(userId).notLaunched = stop;
+ modifyUserState(userId).setNotLaunched(stop);
}
boolean getHidden(int userId) {
- return readUserState(userId).hidden;
+ return readUserState(userId).isHidden();
}
void setHidden(boolean hidden, int userId) {
- modifyUserState(userId).hidden = hidden;
+ modifyUserState(userId).setHidden(hidden);
}
int getDistractionFlags(int userId) {
- return readUserState(userId).distractionFlags;
+ return readUserState(userId).getDistractionFlags();
}
void setDistractionFlags(int distractionFlags, int userId) {
- modifyUserState(userId).distractionFlags = distractionFlags;
+ modifyUserState(userId).setDistractionFlags(distractionFlags);
}
boolean getSuspended(int userId) {
- return readUserState(userId).suspended;
+ return readUserState(userId).isSuspended();
}
boolean isSuspendedBy(String suspendingPackage, int userId) {
- final PackageUserState state = readUserState(userId);
- return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
+ final PackageUserStateInternal state = readUserState(userId);
+ return state.getSuspendParams() != null
+ && state.getSuspendParams().containsKey(suspendingPackage);
}
boolean addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
- final PackageUserState existingUserState = modifyUserState(userId);
+ final PackageUserStateInternalImpl existingUserState = modifyUserState(userId);
final PackageUserState.SuspendParams newSuspendParams =
PackageUserState.SuspendParams.getInstanceOrNull(dialogInfo, appExtras,
launcherExtras);
- if (existingUserState.suspendParams == null) {
- existingUserState.suspendParams = new ArrayMap<>();
+ if (existingUserState.getSuspendParams() == null) {
+ existingUserState.setSuspendParams(new ArrayMap<>());
}
final PackageUserState.SuspendParams oldSuspendParams =
- existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
- existingUserState.suspended = true;
+ existingUserState.getSuspendParams().put(suspendingPackage, newSuspendParams);
+ existingUserState.setSuspended(true);
onChanged();
return !Objects.equals(oldSuspendParams, newSuspendParams);
}
boolean removeSuspension(String suspendingPackage, int userId) {
boolean wasModified = false;
- final PackageUserState existingUserState = modifyUserState(userId);
- if (existingUserState.suspendParams != null) {
- if (existingUserState.suspendParams.remove(suspendingPackage) != null) {
+ final PackageUserStateInternalImpl existingUserState = modifyUserState(userId);
+ if (existingUserState.getSuspendParams() != null) {
+ if (existingUserState.getSuspendParams().remove(suspendingPackage) != null) {
wasModified = true;
}
- if (existingUserState.suspendParams.size() == 0) {
- existingUserState.suspendParams = null;
+ if (existingUserState.getSuspendParams().size() == 0) {
+ existingUserState.setSuspendParams(null);
}
}
- existingUserState.suspended = (existingUserState.suspendParams != null);
+ existingUserState.setSuspended((existingUserState.getSuspendParams() != null));
onChanged();
return wasModified;
}
void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {
- final PackageUserState existingUserState = modifyUserState(userId);
- if (existingUserState.suspendParams != null) {
- for (int i = existingUserState.suspendParams.size() - 1; i >= 0; i--) {
- final String suspendingPackage = existingUserState.suspendParams.keyAt(i);
+ final PackageUserStateInternalImpl existingUserState = modifyUserState(userId);
+ if (existingUserState.getSuspendParams() != null) {
+ for (int i = existingUserState.getSuspendParams().size() - 1; i >= 0; i--) {
+ final String suspendingPackage = existingUserState.getSuspendParams().keyAt(i);
if (suspendingPackagePredicate.test(suspendingPackage)) {
- existingUserState.suspendParams.removeAt(i);
+ existingUserState.getSuspendParams().removeAt(i);
}
}
- if (existingUserState.suspendParams.size() == 0) {
- existingUserState.suspendParams = null;
+ if (existingUserState.getSuspendParams().size() == 0) {
+ existingUserState.setSuspendParams(null);
}
}
- existingUserState.suspended = (existingUserState.suspendParams != null);
+ existingUserState.setSuspended((existingUserState.getSuspendParams() != null));
onChanged();
}
public boolean getInstantApp(int userId) {
- return readUserState(userId).instantApp;
+ return readUserState(userId).isInstantApp();
}
void setInstantApp(boolean instantApp, int userId) {
- modifyUserState(userId).instantApp = instantApp;
+ modifyUserState(userId).setInstantApp(instantApp);
}
boolean getVirtualPreload(int userId) {
- return readUserState(userId).virtualPreload;
+ return readUserState(userId).isVirtualPreload();
}
void setVirtualPreload(boolean virtualPreload, int userId) {
- modifyUserState(userId).virtualPreload = virtualPreload;
+ modifyUserState(userId).setVirtualPreload(virtualPreload);
}
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
@@ -903,74 +903,77 @@
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int installReason, int uninstallReason,
String harmfulAppWarning, String splashScreenTheme) {
- PackageUserState state = modifyUserState(userId);
- state.ceDataInode = ceDataInode;
- state.enabled = enabled;
- state.installed = installed;
- state.stopped = stopped;
- state.notLaunched = notLaunched;
- state.hidden = hidden;
- state.distractionFlags = distractionFlags;
- state.suspended = suspended;
- state.suspendParams = suspendParams;
- state.lastDisableAppCaller = lastDisableAppCaller;
- state.enabledComponents = enabledComponents;
- state.disabledComponents = disabledComponents;
- state.installReason = installReason;
- state.uninstallReason = uninstallReason;
- state.instantApp = instantApp;
- state.virtualPreload = virtualPreload;
- state.harmfulAppWarning = harmfulAppWarning;
- state.splashScreenTheme = splashScreenTheme;
+ modifyUserState(userId)
+ .setSuspendParams(suspendParams)
+ .setCeDataInode(ceDataInode)
+ .setEnabledState(enabled)
+ .setInstalled(installed)
+ .setStopped(stopped)
+ .setNotLaunched(notLaunched)
+ .setHidden(hidden)
+ .setDistractionFlags(distractionFlags)
+ .setSuspended(suspended)
+ .setLastDisableAppCaller(lastDisableAppCaller)
+ .setEnabledComponents(enabledComponents)
+ .setDisabledComponents(disabledComponents)
+ .setInstallReason(installReason)
+ .setUninstallReason(uninstallReason)
+ .setInstantApp(instantApp)
+ .setVirtualPreload(virtualPreload)
+ .setHarmfulAppWarning(harmfulAppWarning)
+ .setSplashScreenTheme(splashScreenTheme);
onChanged();
}
- void setUserState(int userId, PackageUserState otherState) {
- setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
- otherState.stopped, otherState.notLaunched, otherState.hidden,
- otherState.distractionFlags, otherState.suspended, otherState.suspendParams,
- otherState.instantApp,
- otherState.virtualPreload, otherState.lastDisableAppCaller,
- otherState.enabledComponents, otherState.disabledComponents,
- otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning,
- otherState.splashScreenTheme);
+ void setUserState(int userId, PackageUserStateInternal otherState) {
+ setUserState(userId, otherState.getCeDataInode(), otherState.getEnabledState(),
+ otherState.isInstalled(),
+ otherState.isStopped(), otherState.isNotLaunched(), otherState.isHidden(),
+ otherState.getDistractionFlags(), otherState.isSuspended(),
+ otherState.getSuspendParams(),
+ otherState.isInstantApp(),
+ otherState.isVirtualPreload(), otherState.getLastDisableAppCaller(),
+ otherState.getEnabledComponentsNoCopy(), otherState.getDisabledComponentsNoCopy(),
+ otherState.getInstallReason(), otherState.getUninstallReason(),
+ otherState.getHarmfulAppWarning(), otherState.getSplashScreenTheme());
}
ArraySet<String> getEnabledComponents(int userId) {
- return readUserState(userId).enabledComponents;
+ return readUserState(userId).getEnabledComponentsNoCopy();
}
ArraySet<String> getDisabledComponents(int userId) {
- return readUserState(userId).disabledComponents;
+ return readUserState(userId).getDisabledComponentsNoCopy();
}
void setEnabledComponents(ArraySet<String> components, int userId) {
- modifyUserState(userId).enabledComponents = components;
+ modifyUserState(userId).setEnabledComponents(components);
}
void setDisabledComponents(ArraySet<String> components, int userId) {
- modifyUserState(userId).disabledComponents = components;
+ modifyUserState(userId).setDisabledComponents(components);
}
void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
- modifyUserState(userId).enabledComponents = components != null
- ? new ArraySet<String>(components) : null;
+ modifyUserState(userId).setEnabledComponents(components != null
+ ? new ArraySet<String>(components) : null);
}
void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
- modifyUserState(userId).disabledComponents = components != null
- ? new ArraySet<String>(components) : null;
+ modifyUserState(userId).setDisabledComponents(components != null
+ ? new ArraySet<String>(components) : null);
}
- PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
- PackageUserState state = modifyUserState(userId);
+ PackageUserStateInternalImpl modifyUserStateComponents(int userId, boolean disabled,
+ boolean enabled) {
+ PackageUserStateInternalImpl state = modifyUserState(userId);
boolean changed = false;
- if (disabled && state.disabledComponents == null) {
- state.disabledComponents = new ArraySet<String>(1);
+ if (disabled && state.getDisabledComponentsNoCopy() == null) {
+ state.setDisabledComponents(new ArraySet<String>(1));
changed = true;
}
- if (enabled && state.enabledComponents == null) {
- state.enabledComponents = new ArraySet<String>(1);
+ if (enabled && state.getEnabledComponentsNoCopy() == null) {
+ state.setEnabledComponents(new ArraySet<String>(1));
changed = true;
}
if (changed) {
@@ -980,44 +983,47 @@
}
void addDisabledComponent(String componentClassName, int userId) {
- modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
+ modifyUserStateComponents(userId, true, false)
+ .getDisabledComponentsNoCopy().add(componentClassName);
}
void addEnabledComponent(String componentClassName, int userId) {
- modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
+ modifyUserStateComponents(userId, false, true)
+ .getEnabledComponentsNoCopy().add(componentClassName);
}
boolean enableComponentLPw(String componentClassName, int userId) {
- PackageUserState state = modifyUserStateComponents(userId, false, true);
- boolean changed = state.disabledComponents != null
- ? state.disabledComponents.remove(componentClassName) : false;
- changed |= state.enabledComponents.add(componentClassName);
+ PackageUserStateInternalImpl state = modifyUserStateComponents(userId, false, true);
+ boolean changed = state.getDisabledComponentsNoCopy() != null
+ ? state.getDisabledComponentsNoCopy().remove(componentClassName) : false;
+ changed |= state.getEnabledComponentsNoCopy().add(componentClassName);
return changed;
}
boolean disableComponentLPw(String componentClassName, int userId) {
- PackageUserState state = modifyUserStateComponents(userId, true, false);
- boolean changed = state.enabledComponents != null
- ? state.enabledComponents.remove(componentClassName) : false;
- changed |= state.disabledComponents.add(componentClassName);
+ PackageUserStateInternalImpl state = modifyUserStateComponents(userId, true, false);
+ boolean changed = state.getEnabledComponentsNoCopy() != null
+ ? state.getEnabledComponentsNoCopy().remove(componentClassName) : false;
+ changed |= state.getDisabledComponentsNoCopy().add(componentClassName);
return changed;
}
boolean restoreComponentLPw(String componentClassName, int userId) {
- PackageUserState state = modifyUserStateComponents(userId, true, true);
- boolean changed = state.disabledComponents != null
- ? state.disabledComponents.remove(componentClassName) : false;
- changed |= state.enabledComponents != null
- ? state.enabledComponents.remove(componentClassName) : false;
+ PackageUserStateInternalImpl state = modifyUserStateComponents(userId, true, true);
+ boolean changed = state.getDisabledComponentsNoCopy() != null
+ ? state.getDisabledComponentsNoCopy().remove(componentClassName) : false;
+ changed |= state.getEnabledComponentsNoCopy() != null
+ ? state.getEnabledComponentsNoCopy().remove(componentClassName) : false;
return changed;
}
int getCurrentEnabledStateLPr(String componentName, int userId) {
- PackageUserState state = readUserState(userId);
- if (state.enabledComponents != null && state.enabledComponents.contains(componentName)) {
+ PackageUserStateInternal state = readUserState(userId);
+ if (state.getEnabledComponentsNoCopy() != null
+ && state.getEnabledComponentsNoCopy().contains(componentName)) {
return COMPONENT_ENABLED_STATE_ENABLED;
- } else if (state.disabledComponents != null
- && state.disabledComponents.contains(componentName)) {
+ } else if (state.getDisabledComponentsNoCopy() != null
+ && state.getDisabledComponentsNoCopy().contains(componentName)) {
return COMPONENT_ENABLED_STATE_DISABLED;
} else {
return COMPONENT_ENABLED_STATE_DEFAULT;
@@ -1033,7 +1039,7 @@
int count = 0;
int userStateCount = mUserState.size();
for (int i = 0; i < userStateCount; i++) {
- if (!mUserState.valueAt(i).installed) {
+ if (!mUserState.valueAt(i).isInstalled()) {
count++;
}
}
@@ -1044,7 +1050,7 @@
int[] excludedUserIds = new int[count];
int idx = 0;
for (int i = 0; i < userStateCount; i++) {
- if (!mUserState.valueAt(i).installed) {
+ if (!mUserState.valueAt(i).isInstalled()) {
excludedUserIds[idx++] = mUserState.keyAt(i);
}
}
@@ -1079,45 +1085,44 @@
for (int i = 0; i < count; i++) {
final long userToken = proto.start(fieldId);
final int userId = mUserState.keyAt(i);
- final PackageUserState state = mUserState.valueAt(i);
+ final PackageUserStateInternal state = mUserState.valueAt(i);
proto.write(PackageProto.UserInfoProto.ID, userId);
final int installType;
- if (state.instantApp) {
+ if (state.isInstantApp()) {
installType = PackageProto.UserInfoProto.INSTANT_APP_INSTALL;
- } else if (state.installed) {
+ } else if (state.isInstalled()) {
installType = PackageProto.UserInfoProto.FULL_APP_INSTALL;
} else {
installType = PackageProto.UserInfoProto.NOT_INSTALLED_FOR_USER;
}
proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
- proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
- proto.write(PackageProto.UserInfoProto.DISTRACTION_FLAGS, state.distractionFlags);
- proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
- if (state.suspended) {
- for (int j = 0; j < state.suspendParams.size(); j++) {
+ proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.isHidden());
+ proto.write(PackageProto.UserInfoProto.DISTRACTION_FLAGS, state.getDistractionFlags());
+ proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.isSuspended());
+ if (state.isSuspended()) {
+ for (int j = 0; j < state.getSuspendParams().size(); j++) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
- state.suspendParams.keyAt(j));
+ state.getSuspendParams().keyAt(j));
}
}
- proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
- proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
- proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
+ proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.isStopped());
+ proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.isNotLaunched());
+ proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.getEnabledState());
proto.write(
PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER,
- state.lastDisableAppCaller);
+ state.getLastDisableAppCaller());
proto.end(userToken);
}
}
void setHarmfulAppWarning(int userId, String harmfulAppWarning) {
- PackageUserState userState = modifyUserState(userId);
- userState.harmfulAppWarning = harmfulAppWarning;
+ modifyUserState(userId).setHarmfulAppWarning(harmfulAppWarning);
onChanged();
}
String getHarmfulAppWarning(int userId) {
PackageUserState userState = readUserState(userId);
- return userState.harmfulAppWarning;
+ return userState.getHarmfulAppWarning();
}
/**
@@ -1160,7 +1165,7 @@
* @see android.window.SplashScreen#setSplashScreenTheme(int)
*/
public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) {
- modifyUserState(userId).splashScreenTheme = themeName;
+ modifyUserState(userId).setSplashScreenTheme(themeName);
onChanged();
}
@@ -1172,7 +1177,7 @@
*/
@Nullable
public String getSplashScreenTheme(@UserIdInt int userId) {
- return readUserState(userId).splashScreenTheme;
+ return readUserState(userId).getSplashScreenTheme();
}
/**
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8ee2588..85adaa0 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -42,7 +42,6 @@
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageUserState;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
@@ -56,6 +55,9 @@
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedProcess;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateInternal;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -288,17 +290,17 @@
private static final String TAG_DEFAULT_DIALER = "default-dialer";
private static final String TAG_VERSION = "version";
/**
- * @deprecated Moved to {@link android.content.pm.PackageUserState.SuspendParams}
+ * @deprecated Moved to {@link PackageUserState.SuspendParams}
*/
@Deprecated
private static final String TAG_SUSPENDED_DIALOG_INFO = "suspended-dialog-info";
/**
- * @deprecated Moved to {@link android.content.pm.PackageUserState.SuspendParams}
+ * @deprecated Moved to {@link PackageUserState.SuspendParams}
*/
@Deprecated
private static final String TAG_SUSPENDED_APP_EXTRAS = "suspended-app-extras";
/**
- * @deprecated Moved to {@link android.content.pm.PackageUserState.SuspendParams}
+ * @deprecated Moved to {@link PackageUserState.SuspendParams}
*/
@Deprecated
private static final String TAG_SUSPENDED_LAUNCHER_EXTRAS = "suspended-launcher-extras";
@@ -1163,7 +1165,7 @@
}
for (UserInfo user : allUsers) {
final PackageUserState oldUserState = oldPackage == null
- ? PackageSetting.DEFAULT_USER_STATE
+ ? PackageUserState.DEFAULT
: oldPackage.readUserState(user.id);
if (!oldUserState.equals(newPackage.readUserState(user.id))) {
writePackageRestrictionsLPr(user.id);
@@ -1994,87 +1996,91 @@
if (DEBUG_MU) Log.i(TAG, "Writing " + userPackagesStateFile);
for (final PackageSetting pkg : mPackages.values()) {
- final PackageUserState ustate = pkg.readUserState(userId);
+ final PackageUserStateInternal ustate = pkg.readUserState(userId);
if (DEBUG_MU) {
- Log.i(TAG, " pkg=" + pkg.getPackageName() + ", installed=" + ustate.installed
- + ", state=" + ustate.enabled);
+ Log.i(TAG, " pkg=" + pkg.getPackageName()
+ + ", installed=" + ustate.isInstalled()
+ + ", state=" + ustate.getEnabledState());
}
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, pkg.getPackageName());
- if (ustate.ceDataInode != 0) {
- serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.ceDataInode);
+ if (ustate.getCeDataInode() != 0) {
+ serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.getCeDataInode());
}
- if (!ustate.installed) {
+ if (!ustate.isInstalled()) {
serializer.attributeBoolean(null, ATTR_INSTALLED, false);
}
- if (ustate.stopped) {
+ if (ustate.isStopped()) {
serializer.attributeBoolean(null, ATTR_STOPPED, true);
}
- if (ustate.notLaunched) {
+ if (ustate.isNotLaunched()) {
serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true);
}
- if (ustate.hidden) {
+ if (ustate.isHidden()) {
serializer.attributeBoolean(null, ATTR_HIDDEN, true);
}
- if (ustate.distractionFlags != 0) {
- serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS, ustate.distractionFlags);
+ if (ustate.getDistractionFlags() != 0) {
+ serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS,
+ ustate.getDistractionFlags());
}
- if (ustate.suspended) {
+ if (ustate.isSuspended()) {
serializer.attributeBoolean(null, ATTR_SUSPENDED, true);
}
- if (ustate.instantApp) {
+ if (ustate.isInstantApp()) {
serializer.attributeBoolean(null, ATTR_INSTANT_APP, true);
}
- if (ustate.virtualPreload) {
+ if (ustate.isVirtualPreload()) {
serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true);
}
- if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
- serializer.attributeInt(null, ATTR_ENABLED, ustate.enabled);
- if (ustate.lastDisableAppCaller != null) {
+ if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) {
+ serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState());
+ if (ustate.getLastDisableAppCaller() != null) {
serializer.attribute(null, ATTR_ENABLED_CALLER,
- ustate.lastDisableAppCaller);
+ ustate.getLastDisableAppCaller());
}
}
- if (ustate.installReason != PackageManager.INSTALL_REASON_UNKNOWN) {
- serializer.attributeInt(null, ATTR_INSTALL_REASON, ustate.installReason);
+ if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) {
+ serializer.attributeInt(null, ATTR_INSTALL_REASON,
+ ustate.getInstallReason());
}
- if (ustate.uninstallReason != PackageManager.UNINSTALL_REASON_UNKNOWN) {
- serializer.attributeInt(null, ATTR_UNINSTALL_REASON, ustate.uninstallReason);
+ if (ustate.getUninstallReason() != PackageManager.UNINSTALL_REASON_UNKNOWN) {
+ serializer.attributeInt(null, ATTR_UNINSTALL_REASON,
+ ustate.getUninstallReason());
}
- if (ustate.harmfulAppWarning != null) {
+ if (ustate.getHarmfulAppWarning() != null) {
serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
- ustate.harmfulAppWarning);
+ ustate.getHarmfulAppWarning());
}
- if (ustate.splashScreenTheme != null) {
+ if (ustate.getSplashScreenTheme() != null) {
serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME,
- ustate.splashScreenTheme);
+ ustate.getSplashScreenTheme());
}
- if (ustate.suspended) {
- for (int i = 0; i < ustate.suspendParams.size(); i++) {
- final String suspendingPackage = ustate.suspendParams.keyAt(i);
+ if (ustate.isSuspended()) {
+ for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
+ final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
serializer.startTag(null, TAG_SUSPEND_PARAMS);
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, suspendingPackage);
final PackageUserState.SuspendParams params =
- ustate.suspendParams.valueAt(i);
+ ustate.getSuspendParams().valueAt(i);
if (params != null) {
params.saveToXml(serializer);
}
serializer.endTag(null, TAG_SUSPEND_PARAMS);
}
}
- if (!ArrayUtils.isEmpty(ustate.enabledComponents)) {
+ if (!ArrayUtils.isEmpty(ustate.getEnabledComponentsNoCopy())) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
- for (final String name : ustate.enabledComponents) {
+ for (final String name : ustate.getEnabledComponentsNoCopy()) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, TAG_ENABLED_COMPONENTS);
}
- if (!ArrayUtils.isEmpty(ustate.disabledComponents)) {
+ if (!ArrayUtils.isEmpty(ustate.getDisabledComponentsNoCopy())) {
serializer.startTag(null, TAG_DISABLED_COMPONENTS);
- for (final String name : ustate.disabledComponents) {
+ for (final String name : ustate.getDisabledComponentsNoCopy()) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
@@ -4158,7 +4164,7 @@
if (ps == null) return false;
final PackageUserState userState = ps.readUserState(userId);
- return userState.isMatch(componentInfo, flags);
+ return PackageUserStateUtils.isMatch(userState, componentInfo, flags);
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -4168,7 +4174,8 @@
if (ps == null) return false;
final PackageUserState userState = ps.readUserState(userId);
- return userState.isMatch(pkg.isSystem(), pkg.isEnabled(), component, flags);
+ return PackageUserStateUtils.isMatch(userState, pkg.isSystem(), pkg.isEnabled(), component,
+ flags);
}
boolean isOrphaned(String packageName) {
@@ -4771,12 +4778,12 @@
if (ps.getSuspended(user.id)) {
pw.print(prefix);
pw.println(" Suspend params:");
- final PackageUserState pus = ps.readUserState(user.id);
- for (int i = 0; i < pus.suspendParams.size(); i++) {
+ final PackageUserStateInternal pus = ps.readUserState(user.id);
+ for (int i = 0; i < pus.getSuspendParams().size(); i++) {
pw.print(prefix);
pw.print(" suspendingPackage=");
- pw.print(pus.suspendParams.keyAt(i));
- final PackageUserState.SuspendParams params = pus.suspendParams.valueAt(i);
+ pw.print(pus.getSuspendParams().keyAt(i));
+ final PackageUserState.SuspendParams params = pus.getSuspendParams().valueAt(i);
if (params != null) {
pw.print(" dialogInfo=");
pw.print(params.dialogInfo);
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 876c534..4c88b47 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -28,7 +28,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProcessInfo;
@@ -47,6 +46,8 @@
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -70,8 +71,8 @@
/**
* Methods that use a {@link PackageSetting} use it to override information provided from the raw
- * package, or to provide information that would otherwise be missing. Null can be passed if none
- * of the state values should be applied.
+ * package, or to provide information that would otherwise be missing. Null can be passed if none of
+ * the state values should be applied.
*
* @hide
**/
@@ -97,7 +98,7 @@
public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
@Nullable PackageSetting pkgSetting) {
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
- new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting);
+ PackageUserState.DEFAULT, UserHandle.getCallingUserId(), apexInfo, pkgSetting);
}
/**
@@ -425,7 +426,7 @@
@PackageManager.PackageInfoFlags int flags) {
// Returns false if the package is hidden system app until installed.
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
- && !state.installed
+ && !state.isInstalled()
&& pkgSetting != null
&& pkgSetting.getPkgState().isHiddenUntilInstalled()) {
return false;
@@ -433,7 +434,7 @@
// If available for the target user, or trying to match uninstalled packages and it's
// a system app.
- return state.isAvailable(flags)
+ return PackageUserStateUtils.isAvailable(state, flags)
|| (pkg.isSystem()
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 61f7daf..7598423 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -48,7 +48,7 @@
* and not exposed to the core SDK.
*
* Many of the fields contained here will eventually be moved inside
- * {@link com.android.server.pm.PackageSetting} or {@link android.content.pm.PackageUserState}.
+ * {@link com.android.server.pm.PackageSetting} or {@link android.content.pm.pkg.PackageUserState}.
*
* @hide
*/
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index 4c593d9..0ba6d6e 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -338,6 +338,8 @@
private final Map<String, OverlayPaths> mSharedLibraryOverlayPaths;
@PackageManager.UninstallReason
private final int mUninstallReason;
+ @Nullable
+ private final String mSplashScreenTheme;
private UserStateImpl(@NonNull PackageUserState userState) {
mCeDataInode = userState.getCeDataInode();
@@ -351,6 +353,7 @@
mOverlayPaths = userState.getOverlayPaths();
mSharedLibraryOverlayPaths = userState.getSharedLibraryOverlayPaths();
mUninstallReason = userState.getUninstallReason();
+ mSplashScreenTheme = userState.getSplashScreenTheme();
setBoolean(Booleans.HIDDEN, userState.isHidden());
setBoolean(Booleans.INSTALLED, userState.isInstalled());
setBoolean(Booleans.INSTANT_APP, userState.isInstantApp());
@@ -395,6 +398,31 @@
return getBoolean(Booleans.VIRTUAL_PRELOAD);
}
+ @Override
+ public boolean isComponentEnabled(String componentName) {
+ return mEnabledComponents.contains(componentName);
+ }
+
+ @Override
+ public boolean isComponentDisabled(String componentName) {
+ return mDisabledComponents.contains(componentName);
+ }
+
+ @Override
+ public OverlayPaths getAllOverlayPaths() {
+ if (mOverlayPaths == null && mSharedLibraryOverlayPaths == null) {
+ return null;
+ }
+ final OverlayPaths.Builder newPaths = new OverlayPaths.Builder();
+ newPaths.addAll(mOverlayPaths);
+ if (mSharedLibraryOverlayPaths != null) {
+ for (final OverlayPaths libOverlayPaths : mSharedLibraryOverlayPaths.values()) {
+ newPaths.addAll(libOverlayPaths);
+ }
+ }
+ return newPaths.build();
+ }
+
// Code below generated by codegen v1.0.23.
@@ -471,16 +499,21 @@
}
@DataClass.Generated.Member
+ public @Nullable String getSplashScreenTheme() {
+ return mSplashScreenTheme;
+ }
+
+ @DataClass.Generated.Member
public @NonNull UserStateImpl setBooleans( int value) {
mBooleans = value;
return this;
}
@DataClass.Generated(
- time = 1630604430207L,
+ time = 1630604891308L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
- inputSignatures = "private int mBooleans\nprivate final long mCeDataInode\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mDisabledComponents\nprivate final @android.content.pm.PackageManager.DistractionRestriction int mDistractionFlags\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mEnabledComponents\nprivate final int mEnabledState\nprivate final @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate final @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate final @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate final @android.annotation.NonNull android.content.pm.overlay.OverlayPaths mOverlayPaths\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate final @android.content.pm.PackageManager.UninstallReason int mUninstallReason\npublic static android.content.pm.pkg.PackageUserState copy(android.content.pm.pkg.PackageUserState)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isSuspended()\npublic @java.lang.Override boolean isVirtualPreload()\nclass UserStateImpl extends java.lang.Object implements [android.content.pm.pkg.PackageUserState]\nprivate static final int HIDDEN\nprivate static final int INSTALLED\nprivate static final int INSTANT_APP\nprivate static final int NOT_LAUNCHED\nprivate static final int STOPPED\nprivate static final int SUSPENDED\nprivate static final int VIRTUAL_PRELOAD\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+ inputSignatures = "private int mBooleans\nprivate final long mCeDataInode\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mDisabledComponents\nprivate final @android.content.pm.PackageManager.DistractionRestriction int mDistractionFlags\nprivate final @android.annotation.NonNull java.util.Set<java.lang.String> mEnabledComponents\nprivate final int mEnabledState\nprivate final @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate final @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate final @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate final @android.annotation.NonNull android.content.pm.overlay.OverlayPaths mOverlayPaths\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate final @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate final @android.annotation.Nullable java.lang.String mSplashScreenTheme\npublic static android.content.pm.pkg.PackageUserState copy(android.content.pm.pkg.PackageUserState)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isSuspended()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\nclass UserStateImpl extends java.lang.Object implements [android.content.pm.pkg.PackageUserState, android.content.pm.pkg.PackageUserStateHidden]\nprivate static final int HIDDEN\nprivate static final int INSTALLED\nprivate static final int INSTANT_APP\nprivate static final int NOT_LAUNCHED\nprivate static final int STOPPED\nprivate static final int SUSPENDED\nprivate static final int VIRTUAL_PRELOAD\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
@Deprecated
private void __metadata() {}
@@ -637,7 +670,7 @@
}
@DataClass.Generated(
- time = 1630604430248L,
+ time = 1630604891337L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
inputSignatures = "private int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackageApi mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final int mAppId\nprivate final int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final long mFirstInstallTime\nprivate final long mLastModifiedTime\nprivate final long mLastUpdateTime\nprivate final long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.Integer mSharedUserId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.Nullable java.lang.String mSeInfoOverride\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull int[] mUserIds\nprivate final @android.annotation.NonNull android.util.SparseArray<android.content.pm.pkg.PackageUserState> mUserStates\npublic static com.android.server.pm.pkg.PackageState copy(com.android.server.pm.PackageSetting)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @android.annotation.Nullable @java.lang.Override android.content.pm.pkg.PackageUserState getUserState(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final int SYSTEM\nprivate static final int EXTERNAL_STORAGE\nprivate static final int PRIVILEGED\nprivate static final int OEM\nprivate static final int VENDOR\nprivate static final int PRODUCT\nprivate static final int SYSTEM_EXT\nprivate static final int REQUIRED_FOR_SYSTEM_USER\nprivate static final int ODM\nprivate static final int FORCE_QUERYABLE_OVERRIDE\nprivate static final int HIDDEN_UNTIL_INSTALLED\nprivate static final int INSTALL_PERMISSIONS_FIXED\nprivate static final int UPDATE_AVAILABLE\nprivate static final int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternalImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternalImpl.java
new file mode 100644
index 0000000..d5f8dbf
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternalImpl.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2020 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.pm.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateImpl;
+import android.content.pm.pkg.PackageUserStateInternal;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DataClass;
+
+import java.util.Objects;
+
+@DataClass(genConstructor = false, genBuilder = false, genEqualsHashCode = true)
+@DataClass.Suppress({"mCachedOverlayPathsLock", "mCachedOverlayPaths", "setCachedOverlayPaths"})
+public class PackageUserStateInternalImpl extends PackageUserStateImpl implements
+ PackageUserStateInternal {
+
+ /** Suspending package to suspend params */
+ @Nullable
+ private ArrayMap<String, PackageUserState.SuspendParams> mSuspendParams;
+
+ @Nullable
+ private OverlayPaths mCachedOverlayPaths;
+
+ @Nullable
+ private ArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
+
+ public PackageUserStateInternalImpl() {
+ super();
+ }
+
+ public PackageUserStateInternalImpl(PackageUserStateInternalImpl other) {
+ super(other);
+ mSuspendParams = other.mSuspendParams == null ? null : new ArrayMap<>(other.mSuspendParams);
+ mComponentLabelIconOverrideMap = other.mComponentLabelIconOverrideMap == null ? null
+ : new ArrayMap<>(other.mComponentLabelIconOverrideMap);
+ }
+
+ /**
+ * Sets the path of overlays currently enabled for this package and user combination.
+ * @return true if the path contents differ than what they were previously
+ */
+ @Nullable
+ public boolean setOverlayPaths(@Nullable OverlayPaths paths) {
+ if (Objects.equals(paths, mOverlayPaths)) {
+ return false;
+ }
+ if ((mOverlayPaths == null && paths.isEmpty())
+ || (paths == null && mOverlayPaths.isEmpty())) {
+ return false;
+ }
+ mOverlayPaths = paths;
+ mCachedOverlayPaths = null;
+ return true;
+ }
+
+ /**
+ * Sets the path of overlays currently enabled for a library that this package uses.
+ *
+ * @return true if the path contents for the library differ than what they were previously
+ */
+ public boolean setSharedLibraryOverlayPaths(@NonNull String library,
+ @Nullable OverlayPaths paths) {
+ if (mSharedLibraryOverlayPaths == null) {
+ mSharedLibraryOverlayPaths = new ArrayMap<>();
+ }
+ final OverlayPaths currentPaths = mSharedLibraryOverlayPaths.get(library);
+ if (Objects.equals(paths, currentPaths)) {
+ return false;
+ }
+ mCachedOverlayPaths = null;
+ if (paths == null || paths.isEmpty()) {
+ return mSharedLibraryOverlayPaths.remove(library) != null;
+ } else {
+ mSharedLibraryOverlayPaths.put(library, paths);
+ return true;
+ }
+ }
+
+ @Nullable
+ @Override
+ public ArraySet<String> getDisabledComponentsNoCopy() {
+ return mDisabledComponents;
+ }
+
+ @Nullable
+ @Override
+ public ArraySet<String> getEnabledComponentsNoCopy() {
+ return mEnabledComponents;
+ }
+
+ /**
+ * Overrides the non-localized label and icon of a component.
+ *
+ * @return true if the label or icon was changed.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean overrideLabelAndIcon(@NonNull ComponentName component,
+ @Nullable String nonLocalizedLabel, @Nullable Integer icon) {
+ String existingLabel = null;
+ Integer existingIcon = null;
+
+ if (mComponentLabelIconOverrideMap != null) {
+ Pair<String, Integer> pair = mComponentLabelIconOverrideMap.get(component);
+ if (pair != null) {
+ existingLabel = pair.first;
+ existingIcon = pair.second;
+ }
+ }
+
+ boolean changed = !TextUtils.equals(existingLabel, nonLocalizedLabel)
+ || !Objects.equals(existingIcon, icon);
+
+ if (changed) {
+ if (nonLocalizedLabel == null && icon == null) {
+ mComponentLabelIconOverrideMap.remove(component);
+ if (mComponentLabelIconOverrideMap.isEmpty()) {
+ mComponentLabelIconOverrideMap = null;
+ }
+ } else {
+ if (mComponentLabelIconOverrideMap == null) {
+ mComponentLabelIconOverrideMap = new ArrayMap<>(1);
+ }
+
+ mComponentLabelIconOverrideMap.put(component, Pair.create(nonLocalizedLabel, icon));
+ }
+ }
+
+ return changed;
+ }
+
+ /**
+ * Clears all values previously set by {@link #overrideLabelAndIcon(ComponentName,
+ * String, Integer)}.
+ *
+ * This is done when the package is updated as the components and resource IDs may have changed.
+ */
+ public void resetOverrideComponentLabelIcon() {
+ mComponentLabelIconOverrideMap = null;
+ }
+
+ @Nullable
+ public Pair<String, Integer> getOverrideLabelIconForComponent(ComponentName componentName) {
+ if (ArrayUtils.isEmpty(mComponentLabelIconOverrideMap)) {
+ return null;
+ }
+
+ return mComponentLabelIconOverrideMap.get(componentName);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof PackageUserStateInternalImpl)) return false;
+ if (!super.equals(o)) return false;
+ PackageUserStateInternalImpl that = (PackageUserStateInternalImpl) o;
+ return Objects.equals(mSuspendParams, that.mSuspendParams)
+ && Objects.equals(mCachedOverlayPaths, that.mCachedOverlayPaths)
+ && Objects.equals(mComponentLabelIconOverrideMap,
+ that.mComponentLabelIconOverrideMap);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mSuspendParams, mCachedOverlayPaths,
+ mComponentLabelIconOverrideMap);
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateInternalImpl.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Suspending package to suspend params
+ */
+ @DataClass.Generated.Member
+ public @Nullable ArrayMap<String,PackageUserState.SuspendParams> getSuspendParams() {
+ return mSuspendParams;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable OverlayPaths getCachedOverlayPaths() {
+ return mCachedOverlayPaths;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable ArrayMap<ComponentName,Pair<String,Integer>> getComponentLabelIconOverrideMap() {
+ return mComponentLabelIconOverrideMap;
+ }
+
+ /**
+ * Suspending package to suspend params
+ */
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateInternalImpl setSuspendParams(@NonNull ArrayMap<String,PackageUserState.SuspendParams> value) {
+ mSuspendParams = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull PackageUserStateInternalImpl setComponentLabelIconOverrideMap(@NonNull ArrayMap<ComponentName,Pair<String,Integer>> value) {
+ mComponentLabelIconOverrideMap = value;
+ return this;
+ }
+
+ @DataClass.Generated(
+ time = 1626458385872L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateInternalImpl.java",
+ inputSignatures = "private @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.PackageUserState.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\nclass PackageUserStateInternalImpl extends android.content.pm.pkg.PackageUserStateImpl implements [android.content.pm.pkg.PackageUserStateInternal, android.content.pm.pkg.PackageUserStateHidden]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index f0f825a..3174e91 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -29,9 +29,10 @@
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageUserState;
import android.content.pm.ResolveInfo;
import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateUtils;
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationManager;
@@ -1743,13 +1744,13 @@
userId, debugObject);
if (includeNegative && approvalLevel == APPROVAL_LEVEL_NONE) {
PackageUserState pkgUserState = pkgSetting.readUserState(userId);
- if (!pkgUserState.installed) {
+ if (!pkgUserState.isInstalled()) {
return APPROVAL_LEVEL_NOT_INSTALLED;
}
AndroidPackage pkg = pkgSetting.getPkg();
if (pkg != null) {
- if (!pkgUserState.isPackageEnabled(pkg)) {
+ if (!PackageUserStateUtils.isPackageEnabled(pkgUserState, pkg)) {
return APPROVAL_LEVEL_DISABLED;
} else if (mCollector.containsAutoVerifyDomain(pkgSetting.getPkg(), host)) {
return APPROVAL_LEVEL_UNVERIFIED;
@@ -1783,7 +1784,7 @@
return APPROVAL_LEVEL_NONE;
}
- if (!pkgUserState.installed) {
+ if (!pkgUserState.isInstalled()) {
if (DEBUG_APPROVAL) {
debugApproval(packageName, debugObject, userId, false,
"package not installed for user");
@@ -1791,7 +1792,7 @@
return APPROVAL_LEVEL_NONE;
}
- if (!pkgUserState.isPackageEnabled(pkg)) {
+ if (!PackageUserStateUtils.isPackageEnabled(pkgUserState, pkg)) {
if (DEBUG_APPROVAL) {
debugApproval(packageName, debugObject, userId, false,
"package not enabled for user");
@@ -1799,7 +1800,7 @@
return APPROVAL_LEVEL_NONE;
}
- if (pkgUserState.suspended) {
+ if (pkgUserState.isSuspended()) {
if (DEBUG_APPROVAL) {
debugApproval(packageName, debugObject, userId, false,
"package suspended for user");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 811a434..12e6086d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1816,7 +1816,11 @@
@Override
public int onAppTransitionStartingLocked(boolean keyguardGoingAway, long duration,
long statusBarAnimationStartTime, long statusBarAnimationDuration) {
- return handleStartTransitionForKeyguardLw(keyguardGoingAway, duration);
+ // When remote animation is enabled for KEYGUARD_GOING_AWAY transition, SysUI
+ // receives IRemoteAnimationRunner#onAnimationStart to start animation, so we don't
+ // need to call IKeyguardService#keyguardGoingAway here.
+ return handleStartTransitionForKeyguardLw(keyguardGoingAway
+ && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation, duration);
}
@Override
@@ -3066,7 +3070,7 @@
private int handleStartTransitionForKeyguardLw(boolean keyguardGoingAway, long duration) {
final int res = applyKeyguardOcclusionChange();
if (res != 0) return res;
- if (!WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation && keyguardGoingAway) {
+ if (keyguardGoingAway) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "Starting keyguard exit animation");
startKeyguardExitAnimation(SystemClock.uptimeMillis(), duration);
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index d190678..86ff33e 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -410,8 +410,7 @@
}
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
- if (!WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation
- && mKeyguardService != null) {
+ if (mKeyguardService != null) {
mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration);
}
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 5f6fff1..59f8e54 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -425,7 +425,8 @@
mBound = context.bindServiceAsUser(intent, mConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, user);
if (mBound) {
- mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
+ mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null,
+ Context.RECEIVER_EXPORTED);
} else {
Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 161a2bc..b807863 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4938,7 +4938,8 @@
} else {
// If we are being set visible, and the starting window is not yet displayed,
// then make sure it doesn't get displayed.
- if (mStartingWindow != null && !mStartingWindow.isDrawn()) {
+ if (mStartingWindow != null && !mStartingWindow.isDrawn()
+ && (firstWindowDrawn || allDrawn)) {
mStartingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
mStartingWindow.mLegacyPolicyVisibilityAfterAnim = false;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 1a2bf9a..ffaf710 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -1108,6 +1108,11 @@
// the same transition.
for (int i = rootTasks.size() - 1; i >= 0; i--) {
final Task rootTask = rootTasks.valueAt(i);
+ if (rootTask == null) {
+ // It is possible that one activity may have been removed from the hierarchy. No
+ // need to check for this case.
+ continue;
+ }
final boolean notReady = rootTask.forAllLeafTaskFragments(taskFragment -> {
if (!taskFragment.isReadyToTransit()) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Organized TaskFragment is not ready= %s",
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 1909875..e50e8ef 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -758,8 +758,13 @@
(flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0,
(flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
(flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
- mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation(
- SystemClock.uptimeMillis(), 0 /* duration */);
+ if (!WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) {
+ // When remote animation is enabled for KEYGUARD_GOING_AWAY transition, SysUI
+ // receives IRemoteAnimationRunner#onAnimationStart to start animation, so we don't
+ // need to call IKeyguardService#keyguardGoingAway here.
+ mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation(
+ SystemClock.uptimeMillis(), 0 /* duration */);
+ }
}
if ((flags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
mController.mAtm.mWindowManager.mPolicy.applyKeyguardOcclusionChange();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 00e58ef..59f831e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10630,19 +10630,21 @@
}
}
final String adminPkg = admin.getPackageName();
- try {
- // Install the profile owner if not present.
- if (!mIPackageManager.isPackageAvailable(adminPkg, userId)) {
- mIPackageManager.installExistingPackageAsUser(adminPkg, userId,
- PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
- PackageManager.INSTALL_REASON_POLICY,
- /* allowlistedRestrictedPermissions= */ null);
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ try {
+ // Install the profile owner if not present.
+ if (!mIPackageManager.isPackageAvailable(adminPkg, userId)) {
+ mIPackageManager.installExistingPackageAsUser(adminPkg, userId,
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_POLICY,
+ /* allowlistedRestrictedPermissions= */ null);
+ }
+ } catch (RemoteException e) {
+ // Does not happen, same process
+ Slogf.wtf(LOG_TAG, e, "Failed to install admin package %s for user %d",
+ adminPkg, userId);
}
- } catch (RemoteException e) {
- // Does not happen, same process
- Slogf.wtf(LOG_TAG, e, "Failed to install admin package %s for user %d",
- adminPkg, userId);
- }
+ });
// Set admin.
setActiveAdmin(profileOwner, /* refreshing= */ true, userId);
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index ef1201e..e6fd916 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -161,7 +161,8 @@
mStatusExpReceiver = new ConversationStatusExpirationBroadcastReceiver();
mContext.registerReceiver(mStatusExpReceiver,
- ConversationStatusExpirationBroadcastReceiver.getFilter());
+ ConversationStatusExpirationBroadcastReceiver.getFilter(),
+ Context.RECEIVER_NOT_EXPORTED);
IntentFilter shutdownIntentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
BroadcastReceiver shutdownBroadcastReceiver = new ShutdownBroadcastReceiver();
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index d6d5e62..1ad1879 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -19,9 +19,10 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.PackageUserState
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.pkg.PackageUserState
+import android.content.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainVerificationManager
import android.content.pm.verify.domain.DomainVerificationState
import android.os.Build
@@ -331,13 +332,13 @@
domainSetId
)
) {
- whenever(getPackageName()) { packageName }
- whenever(getPkg()) { mockPkg(packageName) }
+ whenever(this.packageName) { packageName }
+ whenever(pkg) { mockPkg(packageName) }
whenever(this.domainSetId) { domainSetId }
- whenever(readUserState(0)) { PackageUserState() }
- whenever(readUserState(1)) { PackageUserState() }
+ whenever(readUserState(0)) { PackageUserStateInternal.DEFAULT }
+ whenever(readUserState(1)) { PackageUserStateInternal.DEFAULT }
whenever(getInstantApp(anyInt())) { false }
- whenever(isSystem()) { false }
+ whenever(isSystem) { false }
}
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index d67b26a..b65995f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -19,9 +19,9 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.PackageUserState
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainOwner
import android.content.pm.verify.domain.DomainVerificationInfo
import android.content.pm.verify.domain.DomainVerificationManager
@@ -77,7 +77,7 @@
}
assertThat(service.queryValidVerificationPackageNames())
- .containsExactly(pkgWithDomains.getPackageName())
+ .containsExactly(pkgWithDomains.packageName)
}
@Test
@@ -104,16 +104,18 @@
addPackages(pkgWithDomains, pkgWithoutDomains)
}
- val infoOne = service.getDomainVerificationInfo(pkgWithDomains.getPackageName())
+ val infoOne = service.getDomainVerificationInfo(pkgWithDomains.packageName)
assertThat(infoOne).isNotNull()
assertThat(infoOne!!.identifier).isEqualTo(pkgWithDomains.domainSetId)
- assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.getPackageName())
- assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(mapOf(
+ assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.packageName)
+ assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(
+ mapOf(
DOMAIN_1 to DomainVerificationInfo.STATE_NO_RESPONSE,
DOMAIN_2 to DomainVerificationInfo.STATE_NO_RESPONSE
- ))
+ )
+ )
- assertThat(service.getDomainVerificationInfo(pkgWithoutDomains.getPackageName())).isNull()
+ assertThat(service.getDomainVerificationInfo(pkgWithoutDomains.packageName)).isNull()
assertFailsWith(PackageManager.NameNotFoundException::class) {
service.getDomainVerificationInfo("invalid.pkg.name")
@@ -125,14 +127,14 @@
val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, listOf(DOMAIN_1, DOMAIN_2))
val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, listOf(DOMAIN_3, DOMAIN_4))
- val map = mutableMapOf(pkg1.getPackageName() to pkg1, pkg2.getPackageName() to pkg2)
+ val map = mutableMapOf(pkg1.packageName to pkg1, pkg2.packageName to pkg2)
val service = makeService(map::get).apply { addPackages(pkg1, pkg2) }
assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_2), 1100))
- .isEqualTo(DomainVerificationManager.STATUS_OK)
+ .isEqualTo(DomainVerificationManager.STATUS_OK)
assertThat(service.setStatus(UUID_INVALID, setOf(DOMAIN_1), 1100))
- .isEqualTo(DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID)
+ .isEqualTo(DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID)
assertFailsWith(IllegalArgumentException::class) {
DomainVerificationJavaUtil.setStatusForceNullable(service, null, setOf(DOMAIN_1), 1100)
@@ -147,10 +149,10 @@
}
assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_3), 1100))
- .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
+ .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_1, DOMAIN_2, DOMAIN_3), 1100))
- .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
+ .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
assertFailsWith(IllegalArgumentException::class) {
service.setStatus(UUID_ONE, setOf(DOMAIN_1), 15)
@@ -167,22 +169,28 @@
val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, listOf(DOMAIN_1, DOMAIN_2))
val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, listOf(DOMAIN_3, DOMAIN_4))
- val map = mutableMapOf(pkg1.getPackageName() to pkg1, pkg2.getPackageName() to pkg2)
+ val map = mutableMapOf(pkg1.packageName to pkg1, pkg2.packageName to pkg2)
val service = makeService(map::get).apply { addPackages(pkg1, pkg2) }
service.setDomainVerificationLinkHandlingAllowed(PKG_ONE, false, 0)
// Should edit same package, same user
- assertThat(service.getDomainVerificationUserState(PKG_ONE, 0)
- ?.isLinkHandlingAllowed).isEqualTo(false)
+ assertThat(
+ service.getDomainVerificationUserState(PKG_ONE, 0)
+ ?.isLinkHandlingAllowed
+ ).isEqualTo(false)
// Shouldn't edit different user
- assertThat(service.getDomainVerificationUserState(PKG_ONE, 1)
- ?.isLinkHandlingAllowed).isEqualTo(true)
+ assertThat(
+ service.getDomainVerificationUserState(PKG_ONE, 1)
+ ?.isLinkHandlingAllowed
+ ).isEqualTo(true)
// Shouldn't edit different package
- assertThat(service.getDomainVerificationUserState(PKG_TWO, 0)
- ?.isLinkHandlingAllowed).isEqualTo(true)
+ assertThat(
+ service.getDomainVerificationUserState(PKG_TWO, 0)
+ ?.isLinkHandlingAllowed
+ ).isEqualTo(true)
assertFailsWith(PackageManager.NameNotFoundException::class) {
service.setDomainVerificationLinkHandlingAllowed("invalid.pkg.name", false, 0)
@@ -196,26 +204,30 @@
val pkg3 = mockPkgSetting(PKG_THREE, UUID_THREE, listOf(DOMAIN_1, DOMAIN_2))
val map = mutableMapOf(
- pkg1.getPackageName() to pkg1,
- pkg2.getPackageName() to pkg2,
- pkg3.getPackageName() to pkg3
+ pkg1.packageName to pkg1,
+ pkg2.packageName to pkg2,
+ pkg3.packageName to pkg3
)
val service = makeService(map::get).apply { addPackages(pkg1, pkg2, pkg3) }
assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, 0))
- .isEqualTo(DomainVerificationManager.STATUS_OK)
+ .isEqualTo(DomainVerificationManager.STATUS_OK)
assertThat(service.setUserSelection(UUID_INVALID, setOf(DOMAIN_1), true, 0))
- .isEqualTo(DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID)
+ .isEqualTo(DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID)
assertFailsWith(IllegalArgumentException::class) {
- DomainVerificationJavaUtil.setUserSelectionForceNullable(service, null,
- setOf(DOMAIN_1), true, 0)
+ DomainVerificationJavaUtil.setUserSelectionForceNullable(
+ service, null,
+ setOf(DOMAIN_1), true, 0
+ )
}
assertFailsWith(IllegalArgumentException::class) {
- DomainVerificationJavaUtil.setUserSelectionForceNullable(service, UUID_ONE, null,
- true, 0)
+ DomainVerificationJavaUtil.setUserSelectionForceNullable(
+ service, UUID_ONE, null,
+ true, 0
+ )
}
assertFailsWith(IllegalArgumentException::class) {
@@ -223,10 +235,10 @@
}
assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_3), true, 0))
- .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
+ .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_1, DOMAIN_2, DOMAIN_3), true, 0))
- .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
+ .isEqualTo(DomainVerificationManager.ERROR_UNKNOWN_DOMAIN)
service.setStatus(UUID_ONE, setOf(DOMAIN_2), DomainVerificationInfo.STATE_SUCCESS)
@@ -248,20 +260,22 @@
addPackages(pkgWithDomains, pkgWithoutDomains)
}
- val infoOne = service.getDomainVerificationUserState(pkgWithDomains.getPackageName(), 0)
+ val infoOne = service.getDomainVerificationUserState(pkgWithDomains.packageName, 0)
assertThat(infoOne).isNotNull()
assertThat(infoOne!!.identifier).isEqualTo(pkgWithDomains.domainSetId)
- assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.getPackageName())
+ assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.packageName)
assertThat(infoOne.isLinkHandlingAllowed).isTrue()
- assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(mapOf(
+ assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(
+ mapOf(
DOMAIN_1 to DomainVerificationUserState.DOMAIN_STATE_NONE,
DOMAIN_2 to DomainVerificationUserState.DOMAIN_STATE_NONE
- ))
+ )
+ )
- val infoTwo = service.getDomainVerificationUserState(pkgWithoutDomains.getPackageName(), 0)
+ val infoTwo = service.getDomainVerificationUserState(pkgWithoutDomains.packageName, 0)
assertThat(infoTwo).isNotNull()
assertThat(infoTwo!!.identifier).isEqualTo(pkgWithoutDomains.domainSetId)
- assertThat(infoTwo.packageName).isEqualTo(pkgWithoutDomains.getPackageName())
+ assertThat(infoTwo.packageName).isEqualTo(pkgWithoutDomains.packageName)
assertThat(infoOne.isLinkHandlingAllowed).isTrue()
assertThat(infoTwo.hostToStateMap).isEmpty()
@@ -276,10 +290,15 @@
val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, listOf(DOMAIN_1, DOMAIN_2), pkgUserState0 = {
mockThrowOnUnmocked {
- whenever(isPackageEnabled(any())) {
- pkg1User0Enabled.get()
+ whenever(enabledState) {
+ if (pkg1User0Enabled.get()) {
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ } else {
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ }
}
- installed = true
+ whenever(isInstalled) { true }
+ whenever(isSuspended) { false }
}
})
val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, listOf(DOMAIN_1, DOMAIN_2))
@@ -323,43 +342,43 @@
service.getOwnersForDomain(DOMAIN_1, 0).let {
assertThat(it).containsExactly(
- DomainOwner(pkg1.getPackageName(), false),
- DomainOwner(pkg2.getPackageName(), false)
+ DomainOwner(pkg1.packageName, false),
+ DomainOwner(pkg2.packageName, false)
).inOrder()
}
manager0.getOwnersForDomain(DOMAIN_1).let {
assertThat(it).containsExactly(
- DomainOwner(pkg1.getPackageName(), false),
- DomainOwner(pkg2.getPackageName(), false)
+ DomainOwner(pkg1.packageName, false),
+ DomainOwner(pkg2.packageName, false)
).inOrder()
}
service.getOwnersForDomain(DOMAIN_2, 0).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
manager0.getOwnersForDomain(DOMAIN_2).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
assertThat(service.getOwnersForDomain(DOMAIN_2, 1)).isEmpty()
assertThat(manager1.getOwnersForDomain(DOMAIN_2)).isEmpty()
service.setUserSelection(pkg1.domainSetId, setOf(DOMAIN_2), true, 1)
service.getOwnersForDomain(DOMAIN_2, 1).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
manager1.getOwnersForDomain(DOMAIN_2).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
// "Uninstall" the package from user 0 and ensure it's stripped from the results
pkg1User0Enabled.set(false)
- service.clearPackageForUser(pkg1.getPackageName(), 0)
+ service.clearPackageForUser(pkg1.packageName, 0)
service.getOwnersForDomain(DOMAIN_1, 0).let {
- assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), false))
+ assertThat(it).containsExactly(DomainOwner(pkg2.packageName, false))
}
manager0.getOwnersForDomain(DOMAIN_1).let {
- assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), false))
+ assertThat(it).containsExactly(DomainOwner(pkg2.packageName, false))
}
// Domain 2 user selection gone for user 0
@@ -367,33 +386,33 @@
// Domain 2 user selection still around for user 1
service.getOwnersForDomain(DOMAIN_2, 1).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
manager1.getOwnersForDomain(DOMAIN_2).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
// Now assert for user 1 that it was unaffected by the change to user 0
service.getOwnersForDomain(DOMAIN_1, 1).let {
assertThat(it).containsExactly(
- DomainOwner(pkg1.getPackageName(), false),
- DomainOwner(pkg2.getPackageName(), false)
+ DomainOwner(pkg1.packageName, false),
+ DomainOwner(pkg2.packageName, false)
).inOrder()
}
manager1.getOwnersForDomain(DOMAIN_1).let {
assertThat(it).containsExactly(
- DomainOwner(pkg1.getPackageName(), false),
- DomainOwner(pkg2.getPackageName(), false)
+ DomainOwner(pkg1.packageName, false),
+ DomainOwner(pkg2.packageName, false)
).inOrder()
}
service.setUserSelection(pkg1.domainSetId, setOf(DOMAIN_2), true, 0)
service.getOwnersForDomain(DOMAIN_2, 1).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
manager1.getOwnersForDomain(DOMAIN_2).let {
- assertThat(it).containsExactly(DomainOwner(pkg1.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg1.packageName, true))
}
// "Reinstall" the package to user 0
@@ -406,10 +425,10 @@
// Other package unaffected
service.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_2), true, 0)
service.getOwnersForDomain(DOMAIN_2, 0).let {
- assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg2.packageName, true))
}
manager0.getOwnersForDomain(DOMAIN_2).let {
- assertThat(it).containsExactly(DomainOwner(pkg2.getPackageName(), true))
+ assertThat(it).containsExactly(DomainOwner(pkg2.packageName, true))
}
}
@@ -456,42 +475,44 @@
}
private fun makeService(vararg pkgSettings: PackageSetting) =
- makeService { pkgName -> pkgSettings.find { pkgName == it.getPackageName() } }
+ makeService { pkgName -> pkgSettings.find { pkgName == it.packageName } }
private fun makeService(pkgSettingFunction: (String) -> PackageSetting? = { null }) =
- DomainVerificationService(mockThrowOnUnmocked {
- // Assume the test has every permission necessary
- whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString()))
- whenever(checkPermission(anyString(), anyInt(), anyInt())) {
- PackageManager.PERMISSION_GRANTED
- }
- }, mockThrowOnUnmocked {
- whenever(linkedApps) { ArraySet<String>() }
- }, mockThrowOnUnmocked {
- whenever(isChangeEnabledInternalNoLogging(anyLong(), any())) { true }
- }).apply {
- setConnection(mockThrowOnUnmocked {
- whenever(filterAppAccess(anyString(), anyInt(), anyInt())) { false }
- whenever(doesUserExist(0)) { true }
- whenever(doesUserExist(1)) { true }
- whenever(scheduleWriteSettings())
-
- // Need to provide an internal UID so some permission checks are ignored
- whenever(callingUid) { Process.ROOT_UID }
- whenever(callingUserId) { 0 }
-
- mockPackageSettings {
- pkgSettingFunction(it)
- }
- })
+ DomainVerificationService(mockThrowOnUnmocked {
+ // Assume the test has every permission necessary
+ whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString()))
+ whenever(checkPermission(anyString(), anyInt(), anyInt())) {
+ PackageManager.PERMISSION_GRANTED
}
+ }, mockThrowOnUnmocked {
+ whenever(linkedApps) { ArraySet<String>() }
+ }, mockThrowOnUnmocked {
+ whenever(isChangeEnabledInternalNoLogging(anyLong(), any())) { true }
+ }).apply {
+ setConnection(mockThrowOnUnmocked {
+ whenever(filterAppAccess(anyString(), anyInt(), anyInt())) { false }
+ whenever(doesUserExist(0)) { true }
+ whenever(doesUserExist(1)) { true }
+ whenever(scheduleWriteSettings())
+
+ // Need to provide an internal UID so some permission checks are ignored
+ whenever(callingUid) { Process.ROOT_UID }
+ whenever(callingUserId) { 0 }
+
+ mockPackageSettings {
+ pkgSettingFunction(it)
+ }
+ })
+ }
private fun mockPkgSetting(
pkgName: String,
domainSetId: UUID,
domains: List<String> = listOf(DOMAIN_1, DOMAIN_2),
- pkgUserState0: PackageSetting.() -> PackageUserState = { PackageUserState() },
- pkgUserState1: PackageSetting.() -> PackageUserState = { PackageUserState() }
+ pkgUserState0: PackageSetting.() -> PackageUserStateInternal = {
+ PackageUserStateInternal.DEFAULT },
+ pkgUserState1: PackageSetting.() -> PackageUserStateInternal = {
+ PackageUserStateInternal.DEFAULT }
) = mockThrowOnUnmocked<PackageSetting> {
val pkg = mockThrowOnUnmocked<AndroidPackage> {
whenever(packageName) { pkgName }
@@ -499,41 +520,43 @@
whenever(isEnabled) { true }
val activityList = listOf(
- ParsedActivity().apply {
- domains.forEach {
- addIntent(
- ParsedIntentInfo().apply {
- autoVerify = true
- addAction(Intent.ACTION_VIEW)
- addCategory(Intent.CATEGORY_BROWSABLE)
- addCategory(Intent.CATEGORY_DEFAULT)
- addDataScheme("http")
- addDataScheme("https")
- addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
- addDataAuthority(it, null)
- }
- )
- }
+ ParsedActivity().apply {
+ domains.forEach {
+ addIntent(
+ ParsedIntentInfo().apply {
+ autoVerify = true
+ addAction(Intent.ACTION_VIEW)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("http")
+ addDataScheme("https")
+ addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
+ addDataAuthority(it, null)
+ }
+ )
}
+ }
)
whenever(activities) { activityList }
}
whenever(getPkg()) { pkg }
- whenever(getPackageName()) { pkgName }
+ whenever(packageName) { pkgName }
whenever(this.domainSetId) { domainSetId }
whenever(getInstantApp(anyInt())) { false }
whenever(firstInstallTime) { 0L }
whenever(readUserState(0)) { pkgUserState0() }
whenever(readUserState(1)) { pkgUserState1() }
- whenever(isSystem()) { false }
+ whenever(isSystem) { false }
}
private fun DomainVerificationService.addPackages(vararg pkgSettings: PackageSetting) =
- pkgSettings.forEach(::addPackage)
+ pkgSettings.forEach(::addPackage)
private fun makeManager(service: DomainVerificationService, userId: Int) =
- DomainVerificationManager(mockThrowOnUnmocked { whenever(this.userId) { userId } },
- DomainVerificationManagerStub(service))
+ DomainVerificationManager(
+ mockThrowOnUnmocked { whenever(this.userId) { userId } },
+ DomainVerificationManagerStub(service)
+ )
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index 74ae7a9..dbec56f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -18,11 +18,11 @@
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.PackageUserState
import android.content.pm.Signature
import android.content.pm.SigningDetails
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainOwner
import android.content.pm.verify.domain.DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED
import android.content.pm.verify.domain.DomainVerificationInfo.STATE_NO_RESPONSE
@@ -834,13 +834,13 @@
whenever(activities) { activityList }
}
- whenever(getPkg()) { pkg }
+ whenever(this.pkg) { pkg }
whenever(packageName) { pkgName }
whenever(this.domainSetId) { domainSetId }
whenever(getInstantApp(anyInt())) { false }
whenever(firstInstallTime) { 0L }
- whenever(readUserState(0)) { PackageUserState() }
- whenever(readUserState(10)) { PackageUserState() }
+ whenever(readUserState(0)) { PackageUserStateInternal.DEFAULT }
+ whenever(readUserState(10)) { PackageUserStateInternal.DEFAULT }
whenever(isSystem) { isSystemApp }
val mockSigningDetails = SigningDetails(arrayOf(spy(Signature(signature)) {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 32866ea..8125128 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -19,9 +19,10 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.PackageUserState
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.pkg.PackageUserState
+import android.content.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainVerificationState
import android.os.Build
import android.os.Process
@@ -231,13 +232,13 @@
TEST_UUID
)
) {
- whenever(getPackageName()) { TEST_PKG }
- whenever(getPkg()) { mockPkg() }
+ whenever(packageName) { TEST_PKG }
+ whenever(pkg) { mockPkg() }
whenever(domainSetId) { TEST_UUID }
- whenever(readUserState(0)) { PackageUserState() }
- whenever(readUserState(10)) { PackageUserState() }
+ whenever(readUserState(0)) { PackageUserStateInternal.DEFAULT }
+ whenever(readUserState(10)) { PackageUserStateInternal.DEFAULT }
whenever(getInstantApp(anyInt())) { false }
- whenever(isSystem()) { false }
+ whenever(isSystem) { false }
}
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 1d5e280..1711355 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -18,9 +18,10 @@
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.PackageUserState
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.pkg.PackageUserState
+import android.content.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainVerificationManager
import android.content.pm.verify.domain.DomainVerificationState
import android.content.pm.verify.domain.DomainVerificationUserState
@@ -138,14 +139,14 @@
whenever(activities) { activityList }
}
- whenever(getPkg()) { pkg }
- whenever(getPackageName()) { pkgName }
+ whenever(this.pkg) { pkg }
+ whenever(packageName) { pkgName }
whenever(this.domainSetId) { domainSetId }
whenever(getInstantApp(anyInt())) { false }
whenever(firstInstallTime) { 0L }
- whenever(readUserState(0)) { PackageUserState() }
- whenever(readUserState(1)) { PackageUserState() }
- whenever(isSystem()) { false }
+ whenever(readUserState(0)) { PackageUserStateInternal.DEFAULT }
+ whenever(readUserState(1)) { PackageUserStateInternal.DEFAULT }
+ whenever(isSystem) { false }
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
new file mode 100644
index 0000000..98e089e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+package com.android.server.job.controllers;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.eq;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.controllers.PrefetchController.PcConstants;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.ZoneOffset;
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class PrefetchControllerTest {
+ private PrefetchController mPrefetchController;
+ private PcConstants mPcConstants;
+ private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private Context mContext;
+ @Mock
+ private JobSchedulerService mJobSchedulerService;
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DeviceConfig.class)
+ .mockStatic(LocalServices.class)
+ .startMocking();
+
+ // Called in StateController constructor.
+ when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
+ when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
+ // Used in PrefetchController.PcConstants
+ doAnswer((Answer<Void>) invocationOnMock -> null)
+ .when(() -> DeviceConfig.addOnPropertiesChangedListener(
+ anyString(), any(Executor.class),
+ any(DeviceConfig.OnPropertiesChangedListener.class)));
+ mDeviceConfigPropertiesBuilder =
+ new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
+ doAnswer(
+ (Answer<DeviceConfig.Properties>) invocationOnMock
+ -> mDeviceConfigPropertiesBuilder.build())
+ .when(() -> DeviceConfig.getProperties(
+ eq(DeviceConfig.NAMESPACE_JOB_SCHEDULER), ArgumentMatchers.<String>any()));
+
+ // Freeze the clocks at 24 hours after this moment in time. Several tests create sessions
+ // in the past, and PrefetchController sometimes floors values at 0, so if the test time
+ // causes sessions with negative timestamps, they will fail.
+ JobSchedulerService.sSystemClock =
+ getShiftedClock(Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC),
+ 24 * HOUR_IN_MILLIS);
+ JobSchedulerService.sUptimeMillisClock = getShiftedClock(
+ Clock.fixed(SystemClock.uptimeClock().instant(), ZoneOffset.UTC),
+ 24 * HOUR_IN_MILLIS);
+ JobSchedulerService.sElapsedRealtimeClock = getShiftedClock(
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC),
+ 24 * HOUR_IN_MILLIS);
+
+ // Initialize real objects.
+ // Capture the listeners.
+ mPrefetchController = new PrefetchController(mJobSchedulerService);
+ mPcConstants = mPrefetchController.getPcConstants();
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private Clock getShiftedClock(Clock clock, long incrementMs) {
+ return Clock.offset(clock, Duration.ofMillis(incrementMs));
+ }
+
+ private void setDeviceConfigLong(String key, long val) {
+ mDeviceConfigPropertiesBuilder.setLong(key, val);
+ synchronized (mPrefetchController.mLock) {
+ mPrefetchController.prepareForUpdatedConstantsLocked();
+ mPcConstants.processConstantLocked(mDeviceConfigPropertiesBuilder.build(), key);
+ }
+ }
+
+ @Test
+ public void testConstantsUpdating_ValidValues() {
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 5 * HOUR_IN_MILLIS);
+
+ assertEquals(5 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
+ }
+
+ @Test
+ public void testConstantsUpdating_InvalidValues() {
+ // Test negatives/too low.
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 4 * MINUTE_IN_MILLIS);
+
+ assertEquals(HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
+
+ // Test larger than a day. Controller should cap at one day.
+ setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 25 * HOUR_IN_MILLIS);
+
+ assertEquals(24 * HOUR_IN_MILLIS, mPrefetchController.getLaunchTimeThresholdMs());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 0dd5c61..418831f 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -26,6 +26,7 @@
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
import static com.android.server.display.DisplayModeDirector.Vote.INVALID_SIZE;
+import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
import static com.google.common.truth.Truth.assertThat;
@@ -74,6 +75,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
@@ -110,6 +112,7 @@
private static final boolean DEBUG = false;
private static final float FLOAT_TOLERANCE = 0.01f;
private static final int DISPLAY_ID = 0;
+ private static final float TRANSITION_POINT = 0.763f;
private Context mContext;
private FakesInjector mInjector;
@@ -751,19 +754,27 @@
director.start(sensorManager);
- ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor<DisplayListener> displayListenerCaptor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
+ any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ DisplayListener displayListener = displayListenerCaptor.getValue();
+
+ ArgumentCaptor<SensorEventListener> sensorListenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
.registerListener(
- listenerCaptor.capture(),
+ sensorListenerCaptor.capture(),
eq(lightSensor),
anyInt(),
any(Handler.class));
- SensorEventListener listener = listenerCaptor.getValue();
+ SensorEventListener sensorListener = sensorListenerCaptor.getValue();
- setBrightness(10);
+ setBrightness(10, 10, displayListener);
// Sensor reads 20 lux,
- listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/));
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/));
Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
assertVoteForRefreshRate(vote, 90 /*fps*/);
@@ -771,9 +782,11 @@
assertThat(vote).isNotNull();
assertThat(vote.disableRefreshRateSwitching).isTrue();
- setBrightness(125);
+ // We expect DisplayModeDirector to act on BrightnessInfo.adjustedBrightness; set only this
+ // parameter to the necessary threshold
+ setBrightness(10, 125, displayListener);
// Sensor reads 1000 lux,
- listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/));
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/));
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
assertThat(vote).isNull();
@@ -799,6 +812,14 @@
director.start(sensorManager);
+ ArgumentCaptor<DisplayListener> displayListenerCaptor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
+ any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ DisplayListener displayListener = displayListenerCaptor.getValue();
+
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
@@ -807,20 +828,22 @@
eq(lightSensor),
anyInt(),
any(Handler.class));
- SensorEventListener listener = listenerCaptor.getValue();
+ SensorEventListener sensorListener = listenerCaptor.getValue();
- setBrightness(100);
+ setBrightness(100, 100, displayListener);
// Sensor reads 2000 lux,
- listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000));
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000));
Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
assertThat(vote).isNull();
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNull();
- setBrightness(255);
+ // We expect DisplayModeDirector to act on BrightnessInfo.adjustedBrightness; set only this
+ // parameter to the necessary threshold
+ setBrightness(100, 255, displayListener);
// Sensor reads 9000 lux,
- listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000));
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000));
vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
assertVoteForRefreshRate(vote, 60 /*fps*/);
@@ -1435,16 +1458,58 @@
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertNull(vote);
- // Turn on HBM
+ // Turn on HBM, with brightness in the HBM range
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR));
+ new BrightnessInfo(TRANSITION_POINT + FLOAT_TOLERANCE, 0.0f, 1.0f,
+ BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, hbmRefreshRate);
+
+ // Turn on HBM, with brightness below the HBM range
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(TRANSITION_POINT - FLOAT_TOLERANCE, 0.0f, 1.0f,
+ BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HBM, with brightness in the HBM range
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(TRANSITION_POINT + FLOAT_TOLERANCE, 0.0f, 1.0f,
+ BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertVoteForRefreshRate(vote, hbmRefreshRate);
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HBM, with brightness below the HBM range
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(TRANSITION_POINT - FLOAT_TOLERANCE, 0.0f, 1.0f,
+ BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertNull(vote);
@@ -1514,7 +1579,8 @@
// Turn on HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertVoteForRefreshRate(vote, initialRefreshRate);
@@ -1531,14 +1597,16 @@
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertNull(vote);
// Turn HBM on again and ensure the updated vote value stuck
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertVoteForRefreshRate(vote, updatedRefreshRate);
@@ -1553,7 +1621,8 @@
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertNull(vote);
@@ -1584,14 +1653,82 @@
// Turn on HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertNull(vote);
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+ }
+
+ @Test
+ public void testHbmVoting_HbmUnsupported() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> captor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener listener = captor.getValue();
+
+ // Specify Limitation
+ when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
+ List.of(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
+ 60.0f, 60.0f)));
+
+ // Verify that there is no HBM vote initially
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HBM when HBM is supported; expect a valid transition point and a vote.
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
+ TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, 60.0f);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on Sunlight HBM when HBM is unsupported; expect an invalid transition point and
+ // no vote.
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
+ HBM_TRANSITION_POINT_INVALID));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HDR HBM when HBM is unsupported; expect an invalid transition point and
+ // no vote.
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR,
+ HBM_TRANSITION_POINT_INVALID));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertNull(vote);
@@ -1600,7 +1737,7 @@
private void setHbmAndAssertRefreshRate(
DisplayModeDirector director, DisplayListener listener, int mode, float rr) {
when(mInjector.getBrightnessInfo(DISPLAY_ID))
- .thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode));
+ .thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode, TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
final Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
@@ -1679,7 +1816,8 @@
// Turn on HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
- new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
+ TRANSITION_POINT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
assertVoteForRefreshRate(vote, 60.f);
@@ -1834,11 +1972,14 @@
}
}
- private void setBrightness(int brightness) {
- Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
- brightness);
- mInjector.notifyBrightnessChanged();
- waitForIdleSync();
+ private void setBrightness(int brightness, int adjustedBrightness, DisplayListener listener) {
+ float floatBri = BrightnessSynchronizer.brightnessIntToFloat(brightness);
+ float floatAdjBri = BrightnessSynchronizer.brightnessIntToFloat(adjustedBrightness);
+
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(floatBri, floatAdjBri, 0.0f, 1.0f,
+ BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, TRANSITION_POINT));
+ listener.onDisplayChanged(DISPLAY_ID);
}
private void setPeakRefreshRate(float fps) {
@@ -1902,27 +2043,6 @@
}
@Override
- public void registerBrightnessObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- if (mBrightnessObserver != null) {
- throw new IllegalStateException("Tried to register a second brightness observer");
- }
- mBrightnessObserver = observer;
- }
-
- @Override
- public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- mBrightnessObserver = null;
- }
-
- void notifyBrightnessChanged() {
- if (mBrightnessObserver != null) {
- mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI);
- }
- }
-
- @Override
public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer) {
mPeakRefreshRateObserver = observer;
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index cc3591c8..aca8632 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -20,6 +20,8 @@
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
@@ -124,6 +126,7 @@
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN,
DEFAULT_MAX, null, () -> {}, mContextSpy);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
+ assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
}
@Test
@@ -135,6 +138,7 @@
hbmc.setAutoBrightnessEnabled(true);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
+ assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
index 0247590..f8c3bf3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
@@ -25,17 +25,16 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageUserState;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Build;
import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.pkg.PackageUserStateInternalImpl;
import org.junit.After;
import org.junit.Before;
@@ -45,16 +44,14 @@
private boolean mCompatibilityModeEnabled;;
private PackageImpl mMockAndroidPackage;
- private PackageUserState mMockUserState;
+ private PackageUserStateInternalImpl mMockUserState;
@Before
public void setUp() {
mCompatibilityModeEnabled = ParsingPackageUtils.sCompatibilityModeEnabled;
mMockAndroidPackage = mock(PackageImpl.class);
- mMockUserState = mock(PackageUserState.class);
- mMockUserState.installed = true;
- when(mMockUserState.isAvailable(anyInt())).thenReturn(true);
- when(mMockUserState.getAllOverlayPaths()).thenReturn(null);
+ mMockUserState = new PackageUserStateInternalImpl();
+ mMockUserState.setInstalled(true);
}
@After
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 33099bb..24377a9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -40,9 +40,10 @@
import android.app.PropertyInvalidatedCache;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageUserState;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.pkg.PackageUserState;
+import android.content.pm.pkg.PackageUserStateInternal;
import android.os.BaseBundle;
import android.os.PersistableBundle;
import android.os.Process;
@@ -208,24 +209,24 @@
settingsUnderTest.readPackageRestrictionsLPr(0);
PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
- PackageUserState packageUserState1 = ps1.readUserState(0);
- assertThat(packageUserState1.suspended, is(true));
- assertThat(packageUserState1.suspendParams.size(), is(1));
- assertThat(packageUserState1.suspendParams.keyAt(0), is("android"));
- assertThat(packageUserState1.suspendParams.valueAt(0), is(nullValue()));
+ PackageUserStateInternal packageUserState1 = ps1.readUserState(0);
+ assertThat(packageUserState1.isSuspended(), is(true));
+ assertThat(packageUserState1.getSuspendParams().size(), is(1));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().valueAt(0), is(nullValue()));
// Verify that the snapshot returns the same answers
ps1 = snapshot.mPackages.get(PACKAGE_NAME_1);
packageUserState1 = ps1.readUserState(0);
- assertThat(packageUserState1.suspended, is(true));
- assertThat(packageUserState1.suspendParams.size(), is(1));
- assertThat(packageUserState1.suspendParams.keyAt(0), is("android"));
- assertThat(packageUserState1.suspendParams.valueAt(0), is(nullValue()));
+ assertThat(packageUserState1.isSuspended(), is(true));
+ assertThat(packageUserState1.getSuspendParams().size(), is(1));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().valueAt(0), is(nullValue()));
PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
- PackageUserState packageUserState2 = ps2.readUserState(0);
- assertThat(packageUserState2.suspended, is(false));
- assertThat(packageUserState2.suspendParams, is(nullValue()));
+ PackageUserStateInternal packageUserState2 = ps2.readUserState(0);
+ assertThat(packageUserState2.isSuspended(), is(false));
+ assertThat(packageUserState2.getSuspendParams(), is(nullValue()));
// Verify that the snapshot returns different answers
ps2 = snapshot.mPackages.get(PACKAGE_NAME_2);
@@ -246,12 +247,13 @@
final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
watcher.verifyNoChangeReported("get package 1");
- final PackageUserState packageUserState1 = ps1.readUserState(0);
+ final PackageUserStateInternal packageUserState1 = ps1.readUserState(0);
watcher.verifyNoChangeReported("readUserState");
- assertThat(packageUserState1.suspended, is(true));
- assertThat(packageUserState1.suspendParams.size(), is(1));
- assertThat(packageUserState1.suspendParams.keyAt(0), is(PACKAGE_NAME_3));
- final PackageUserState.SuspendParams params = packageUserState1.suspendParams.valueAt(0);
+ assertThat(packageUserState1.isSuspended(), is(true));
+ assertThat(packageUserState1.getSuspendParams().size(), is(1));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(PACKAGE_NAME_3));
+ final PackageUserState.SuspendParams params =
+ packageUserState1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("fetch user state");
assertThat(params, is(notNullValue()));
assertThat(params.appExtras.size(), is(1));
@@ -330,15 +332,15 @@
// now read and verify
settingsUnderTest.readPackageRestrictionsLPr(0);
watcher.verifyChangeReported("readPackageRestrictions");
- final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
+ final PackageUserStateInternal readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
.readUserState(0);
watcher.verifyNoChangeReported("package get 1");
- assertThat(readPus1.suspended, is(true));
- assertThat(readPus1.suspendParams.size(), is(2));
+ assertThat(readPus1.isSuspended(), is(true));
+ assertThat(readPus1.getSuspendParams().size(), is(2));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.suspendParams.keyAt(0), is("suspendingPackage1"));
- final PackageUserState.SuspendParams params11 = readPus1.suspendParams.valueAt(0);
+ assertThat(readPus1.getSuspendParams().keyAt(0), is("suspendingPackage1"));
+ final PackageUserState.SuspendParams params11 = readPus1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("read package param");
assertThat(params11, is(notNullValue()));
assertThat(params11.dialogInfo, is(dialogInfo1));
@@ -347,8 +349,8 @@
is(true));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.suspendParams.keyAt(1), is("suspendingPackage2"));
- final PackageUserState.SuspendParams params12 = readPus1.suspendParams.valueAt(1);
+ assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2"));
+ final PackageUserState.SuspendParams params12 = readPus1.getSuspendParams().valueAt(1);
assertThat(params12, is(notNullValue()));
assertThat(params12.dialogInfo, is(dialogInfo2));
assertThat(BaseBundle.kindofEquals(params12.appExtras, appExtras2), is(true));
@@ -356,22 +358,22 @@
is(true));
watcher.verifyNoChangeReported("read package param");
- final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
+ final PackageUserStateInternal readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
.readUserState(0);
- assertThat(readPus2.suspended, is(true));
- assertThat(readPus2.suspendParams.size(), is(1));
- assertThat(readPus2.suspendParams.keyAt(0), is("suspendingPackage3"));
- final PackageUserState.SuspendParams params21 = readPus2.suspendParams.valueAt(0);
+ assertThat(readPus2.isSuspended(), is(true));
+ assertThat(readPus2.getSuspendParams().size(), is(1));
+ assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3"));
+ final PackageUserState.SuspendParams params21 = readPus2.getSuspendParams().valueAt(0);
assertThat(params21, is(notNullValue()));
assertThat(params21.dialogInfo, is(nullValue()));
assertThat(BaseBundle.kindofEquals(params21.appExtras, appExtras1), is(true));
assertThat(params21.launcherExtras, is(nullValue()));
watcher.verifyNoChangeReported("read package param");
- final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
+ final PackageUserStateInternal readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
.readUserState(0);
- assertThat(readPus3.suspended, is(false));
- assertThat(readPus3.suspendParams, is(nullValue()));
+ assertThat(readPus3.isSuspended(), is(false));
+ assertThat(readPus3.getSuspendParams(), is(nullValue()));
watcher.verifyNoChangeReported("package get 3");
}
@@ -411,15 +413,15 @@
settingsUnderTest.readPackageRestrictionsLPr(0);
final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
.readUserState(0);
- assertThat(readPus1.distractionFlags, is(distractionFlags1));
+ assertThat(readPus1.getDistractionFlags(), is(distractionFlags1));
final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
.readUserState(0);
- assertThat(readPus2.distractionFlags, is(distractionFlags2));
+ assertThat(readPus2.getDistractionFlags(), is(distractionFlags2));
final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
.readUserState(0);
- assertThat(readPus3.distractionFlags, is(distractionFlags3));
+ assertThat(readPus3.getDistractionFlags(), is(distractionFlags3));
}
@Test
@@ -895,13 +897,13 @@
private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
boolean userStateChanged, boolean notLaunched, boolean stopped, boolean installed) {
- assertThat(userState.enabled, is(0));
- assertThat(userState.hidden, is(false));
- assertThat(userState.installed, is(installed));
- assertThat(userState.notLaunched, is(notLaunched));
- assertThat(userState.stopped, is(stopped));
- assertThat(userState.suspended, is(false));
- assertThat(userState.distractionFlags, is(0));
+ assertThat(userState.getEnabledState(), is(0));
+ assertThat(userState.isHidden(), is(false));
+ assertThat(userState.isInstalled(), is(installed));
+ assertThat(userState.isNotLaunched(), is(notLaunched));
+ assertThat(userState.isStopped(), is(stopped));
+ assertThat(userState.isSuspended(), is(false));
+ assertThat(userState.getDistractionFlags(), is(0));
if (oldUserState != null) {
assertThat(userState.equals(oldUserState), is(not(userStateChanged)));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 4113332..c85b2e8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -40,7 +40,6 @@
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageUserState;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
@@ -54,6 +53,7 @@
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
import android.content.pm.parsing.component.ParsedUsesPermission;
+import android.content.pm.pkg.PackageUserState;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -645,9 +645,9 @@
assertArrayEquals(a.getSplitFlags(), b.getSplitFlags());
PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0,
- Collections.emptySet(), new PackageUserState(), 0, mockPkgSetting(a));
+ Collections.emptySet(), PackageUserState.DEFAULT, 0, mockPkgSetting(a));
PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0,
- Collections.emptySet(), new PackageUserState(), 0, mockPkgSetting(b));
+ Collections.emptySet(), PackageUserState.DEFAULT, 0, mockPkgSetting(b));
assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions()));
@@ -802,9 +802,9 @@
// Validity check for ServiceInfo.
ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0,
- new PackageUserState(), 0, mockPkgSetting(aPkg));
+ PackageUserState.DEFAULT, 0, mockPkgSetting(aPkg));
ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0,
- new PackageUserState(), 0, mockPkgSetting(bPkg));
+ PackageUserState.DEFAULT, 0, mockPkgSetting(bPkg));
assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
assertEquals(a.getName(), b.getName());
}
@@ -829,9 +829,9 @@
// Validity check for ActivityInfo.
ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0,
- new PackageUserState(), 0, mockPkgSetting(aPkg));
+ PackageUserState.DEFAULT, 0, mockPkgSetting(aPkg));
ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0,
- new PackageUserState(), 0, mockPkgSetting(bPkg));
+ PackageUserState.DEFAULT, 0, mockPkgSetting(bPkg));
assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
assertEquals(a.getName(), b.getName());
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 93aae28..f1c8dd6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -16,12 +16,12 @@
package com.android.server.pm;
-import android.content.pm.PackageUserState;
import android.content.pm.SigningDetails;
import android.util.ArraySet;
import android.util.SparseArray;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageUserStateInternalImpl;
import java.io.File;
import java.util.Map;
@@ -41,7 +41,7 @@
private int mSharedUserId;
private String mVolumeUuid;
private int mAppId;
- private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+ private SparseArray<PackageUserStateInternalImpl> mUserStates = new SparseArray<>();
private AndroidPackage mPkg;
private InstallSource mInstallSource;
private String[] mUsesStaticLibraries;
@@ -139,17 +139,17 @@
public PackageSettingBuilder setInstantAppUserState(int userId, boolean isInstant) {
if (mUserStates.indexOfKey(userId) < 0) {
- mUserStates.put(userId, new PackageUserState());
+ mUserStates.put(userId, new PackageUserStateInternalImpl());
}
- mUserStates.get(userId).instantApp = isInstant;
+ mUserStates.get(userId).setInstantApp(isInstant);
return this;
}
public PackageSettingBuilder setInstallState(int userId, boolean installed) {
if (mUserStates.indexOfKey(userId) < 0) {
- mUserStates.put(userId, new PackageUserState());
+ mUserStates.put(userId, new PackageUserStateInternalImpl());
}
- mUserStates.get(userId).installed = installed;
+ mUserStates.get(userId).setInstalled(installed);
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 7297622..5376298 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -17,7 +17,6 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
@@ -26,9 +25,9 @@
import static org.junit.Assert.assertTrue;
import android.content.pm.PackageManager;
-import android.content.pm.PackageUserState;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.pkg.PackageUserState;
import android.os.PersistableBundle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -37,6 +36,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.pm.pkg.PackageStateUnserialized;
+import com.android.server.pm.pkg.PackageUserStateInternalImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,142 +47,141 @@
@Test
public void testPackageUserState01() {
- final PackageUserState testUserState = new PackageUserState();
- PackageUserState oldUserState;
+ final PackageUserStateInternalImpl testUserState = new PackageUserStateInternalImpl();
+ PackageUserStateInternalImpl oldUserState;
- oldUserState = new PackageUserState();
+ oldUserState = new PackageUserStateInternalImpl();
assertThat(testUserState.equals(null), is(false));
assertThat(testUserState.equals(testUserState), is(true));
assertThat(testUserState.equals(oldUserState), is(true));
- oldUserState = new PackageUserState();
- oldUserState.ceDataInode = 4000L;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setCeDataInode(4000L);
assertThat(testUserState.equals(oldUserState), is(false));
- oldUserState = new PackageUserState();
- oldUserState.enabled = COMPONENT_ENABLED_STATE_ENABLED;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setEnabledState(COMPONENT_ENABLED_STATE_ENABLED);
assertThat(testUserState.equals(oldUserState), is(false));
- oldUserState = new PackageUserState();
- oldUserState.hidden = true;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setHidden(true);
assertThat(testUserState.equals(oldUserState), is(false));
- oldUserState = new PackageUserState();
- oldUserState.installed = false;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setInstalled(false);
assertThat(testUserState.equals(oldUserState), is(false));
- oldUserState = new PackageUserState();
- oldUserState.notLaunched = true;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setNotLaunched(true);
assertThat(testUserState.equals(oldUserState), is(false));
- oldUserState = new PackageUserState();
- oldUserState.stopped = true;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setStopped(true);
assertThat(testUserState.equals(oldUserState), is(false));
- oldUserState = new PackageUserState();
- oldUserState.suspended = true;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setSuspended(true);
assertThat(testUserState.equals(oldUserState), is(false));
- oldUserState = new PackageUserState();
- oldUserState.uninstallReason = PackageManager.UNINSTALL_REASON_USER_TYPE;
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setUninstallReason(PackageManager.UNINSTALL_REASON_USER_TYPE);
assertThat(testUserState.equals(oldUserState), is(false));
}
@Test
public void testPackageUserState02() {
- final PackageUserState testUserState01 = new PackageUserState();
- PackageUserState oldUserState;
+ final PackageUserStateInternalImpl testUserState01 = new PackageUserStateInternalImpl();
+ PackageUserStateInternalImpl oldUserState;
- oldUserState = new PackageUserState();
- oldUserState.lastDisableAppCaller = "unit_test";
+ oldUserState = new PackageUserStateInternalImpl();
+ oldUserState.setLastDisableAppCaller("unit_test");
assertThat(testUserState01.equals(oldUserState), is(false));
- final PackageUserState testUserState02 = new PackageUserState();
- testUserState02.lastDisableAppCaller = "unit_test";
+ final PackageUserStateInternalImpl testUserState02 = new PackageUserStateInternalImpl();
+ testUserState02.setLastDisableAppCaller("unit_test");
assertThat(testUserState02.equals(oldUserState), is(true));
- final PackageUserState testUserState03 = new PackageUserState();
- testUserState03.lastDisableAppCaller = "unit_test_00";
+ final PackageUserStateInternalImpl testUserState03 = new PackageUserStateInternalImpl();
+ testUserState03.setLastDisableAppCaller("unit_test_00");
assertThat(testUserState03.equals(oldUserState), is(false));
}
@Test
public void testPackageUserState03() {
- final PackageUserState oldUserState = new PackageUserState();
+ final PackageUserStateInternalImpl oldUserState = new PackageUserStateInternalImpl();
// only new user state has array defined; different
- final PackageUserState testUserState01 = new PackageUserState();
- testUserState01.disabledComponents = new ArraySet<>();
+ final PackageUserStateInternalImpl testUserState01 = new PackageUserStateInternalImpl();
+ testUserState01.setDisabledComponents(new ArraySet<>());
assertThat(testUserState01.equals(oldUserState), is(false));
// only old user state has array defined; different
- final PackageUserState testUserState02 = new PackageUserState();
- oldUserState.disabledComponents = new ArraySet<>();
+ final PackageUserStateInternalImpl testUserState02 = new PackageUserStateInternalImpl();
+ oldUserState.setDisabledComponents(new ArraySet<>());
assertThat(testUserState02.equals(oldUserState), is(false));
// both states have array defined; not different
- final PackageUserState testUserState03 = new PackageUserState();
- testUserState03.disabledComponents = new ArraySet<>();
+ final PackageUserStateInternalImpl testUserState03 = new PackageUserStateInternalImpl();
+ testUserState03.setDisabledComponents(new ArraySet<>());
assertThat(testUserState03.equals(oldUserState), is(true));
// fewer elements in old user state; different
- testUserState03.disabledComponents.add("com.android.unit_test01");
- testUserState03.disabledComponents.add("com.android.unit_test02");
- testUserState03.disabledComponents.add("com.android.unit_test03");
- oldUserState.disabledComponents.add("com.android.unit_test03");
- oldUserState.disabledComponents.add("com.android.unit_test02");
+ testUserState03.getDisabledComponentsNoCopy().add("com.android.unit_test01");
+ testUserState03.getDisabledComponentsNoCopy().add("com.android.unit_test02");
+ testUserState03.getDisabledComponentsNoCopy().add("com.android.unit_test03");
+ oldUserState.getDisabledComponentsNoCopy().add("com.android.unit_test03");
+ oldUserState.getDisabledComponentsNoCopy().add("com.android.unit_test02");
assertThat(testUserState03.equals(oldUserState), is(false));
// same elements in old user state; not different
- oldUserState.disabledComponents.add("com.android.unit_test01");
+ oldUserState.getDisabledComponentsNoCopy().add("com.android.unit_test01");
assertThat(testUserState03.equals(oldUserState), is(true));
// more elements in old user state; different
- oldUserState.disabledComponents.add("com.android.unit_test04");
+ oldUserState.getDisabledComponentsNoCopy().add("com.android.unit_test04");
assertThat(testUserState03.equals(oldUserState), is(false));
// different elements in old user state; different
- testUserState03.disabledComponents.add("com.android.unit_test_04");
+ testUserState03.getDisabledComponentsNoCopy().add("com.android.unit_test_04");
assertThat(testUserState03.equals(oldUserState), is(false));
}
@Test
public void testPackageUserState04() {
- final PackageUserState oldUserState = new PackageUserState();
+ final PackageUserStateInternalImpl oldUserState = new PackageUserStateInternalImpl();
// only new user state has array defined; different
- final PackageUserState testUserState01 = new PackageUserState();
- testUserState01.enabledComponents = new ArraySet<>();
+ final PackageUserStateInternalImpl testUserState01 = new PackageUserStateInternalImpl();
+ testUserState01.setEnabledComponents(new ArraySet<>());
assertThat(testUserState01.equals(oldUserState), is(false));
// only old user state has array defined; different
- final PackageUserState testUserState02 = new PackageUserState();
- oldUserState.enabledComponents = new ArraySet<>();
+ final PackageUserStateInternalImpl testUserState02 = new PackageUserStateInternalImpl();
+ oldUserState.setEnabledComponents(new ArraySet<>());
assertThat(testUserState02.equals(oldUserState), is(false));
// both states have array defined; not different
- final PackageUserState testUserState03 = new PackageUserState();
- testUserState03.enabledComponents = new ArraySet<>();
+ final PackageUserStateInternalImpl testUserState03 = new PackageUserStateInternalImpl();
+ testUserState03.setEnabledComponents(new ArraySet<>());
assertThat(testUserState03.equals(oldUserState), is(true));
// fewer elements in old user state; different
- testUserState03.enabledComponents.add("com.android.unit_test01");
- testUserState03.enabledComponents.add("com.android.unit_test02");
- testUserState03.enabledComponents.add("com.android.unit_test03");
- oldUserState.enabledComponents.add("com.android.unit_test03");
- oldUserState.enabledComponents.add("com.android.unit_test02");
+ testUserState03.getEnabledComponentsNoCopy().add("com.android.unit_test01");
+ testUserState03.getEnabledComponentsNoCopy().add("com.android.unit_test02");
+ testUserState03.getEnabledComponentsNoCopy().add("com.android.unit_test03");
+ oldUserState.getEnabledComponentsNoCopy().add("com.android.unit_test03");
+ oldUserState.getEnabledComponentsNoCopy().add("com.android.unit_test02");
assertThat(testUserState03.equals(oldUserState), is(false));
// same elements in old user state; not different
- oldUserState.enabledComponents.add("com.android.unit_test01");
+ oldUserState.getEnabledComponentsNoCopy().add("com.android.unit_test01");
assertThat(testUserState03.equals(oldUserState), is(true));
// more elements in old user state; different
- oldUserState.enabledComponents.add("com.android.unit_test04");
+ oldUserState.getEnabledComponentsNoCopy().add("com.android.unit_test04");
assertThat(testUserState03.equals(oldUserState), is(false));
// different elements in old user state; different
- testUserState03.enabledComponents.add("com.android.unit_test_04");
+ testUserState03.getEnabledComponentsNoCopy().add("com.android.unit_test_04");
assertThat(testUserState03.equals(oldUserState), is(false));
}
private static PackageUserState.SuspendParams createSuspendParams(SuspendDialogInfo dialogInfo,
PersistableBundle appExtras, PersistableBundle launcherExtras) {
- PackageUserState.SuspendParams obj = PackageUserState.SuspendParams.getInstanceOrNull(
+ return PackageUserState.SuspendParams.getInstanceOrNull(
dialogInfo, appExtras, launcherExtras);
- return obj;
}
private static PersistableBundle createPersistableBundle(String lKey, long lValue, String sKey,
@@ -230,29 +229,32 @@
appExtras2, launcherExtras2));
- final PackageUserState testUserState1 = new PackageUserState();
- testUserState1.suspended = true;
- testUserState1.suspendParams = paramsMap1;
+ final PackageUserStateInternalImpl testUserState1 = new PackageUserStateInternalImpl();
+ testUserState1.setSuspended(true);
+ testUserState1.setSuspendParams(paramsMap1);
- PackageUserState testUserState2 = new PackageUserState(testUserState1);
+ PackageUserStateInternalImpl testUserState2 =
+ new PackageUserStateInternalImpl(testUserState1);
assertThat(testUserState1.equals(testUserState2), is(true));
- testUserState2.suspendParams = paramsMap2;
+ testUserState2.setSuspendParams(paramsMap2);
// Should not be equal since suspendParams maps are different
assertThat(testUserState1.equals(testUserState2), is(false));
}
@Test
public void testPackageUserState06() {
- final PackageUserState userState1 = new PackageUserState();
- assertThat(userState1.distractionFlags, is(PackageManager.RESTRICTION_NONE));
- userState1.distractionFlags = PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+ final PackageUserStateInternalImpl userState1 = new PackageUserStateInternalImpl();
+ assertThat(userState1.getDistractionFlags(), is(PackageManager.RESTRICTION_NONE));
+ userState1.setDistractionFlags(PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS);
- final PackageUserState copyOfUserState1 = new PackageUserState(userState1);
- assertThat(userState1.distractionFlags, is(copyOfUserState1.distractionFlags));
+ final PackageUserStateInternalImpl copyOfUserState1 =
+ new PackageUserStateInternalImpl(userState1);
+ assertThat(userState1.getDistractionFlags(), is(copyOfUserState1.getDistractionFlags()));
assertThat(userState1.equals(copyOfUserState1), is(true));
- final PackageUserState userState2 = new PackageUserState(userState1);
- userState2.distractionFlags = PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
+ final PackageUserStateInternalImpl userState2 =
+ new PackageUserStateInternalImpl(userState1);
+ userState2.setDistractionFlags(PackageManager.RESTRICTION_HIDE_NOTIFICATIONS);
assertThat(userState1.equals(userState2), is(false));
}
@@ -352,7 +354,7 @@
@Test
public void testOverlayPaths() {
- final PackageUserState testState = new PackageUserState();
+ final PackageUserStateInternalImpl testState = new PackageUserStateInternalImpl();
assertFalse(testState.setOverlayPaths(null));
assertFalse(testState.setOverlayPaths(new OverlayPaths.Builder().build()));
@@ -366,7 +368,7 @@
}
@Test
public void testSharedLibOverlayPaths() {
- final PackageUserState testState = new PackageUserState();
+ final PackageUserStateInternalImpl testState = new PackageUserStateInternalImpl();
final String LIB_ONE = "lib1";
final String LIB_TW0 = "lib2";
assertFalse(testState.setSharedLibraryOverlayPaths(LIB_ONE, null));
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 370b1c9..82bf2f4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -158,7 +158,7 @@
final ScanResult scanResult = executeScan(scanRequest);
for (int uid : userIds) {
- assertThat(scanResult.mPkgSetting.readUserState(uid).installed, is(true));
+ assertThat(scanResult.mPkgSetting.readUserState(uid).isInstalled(), is(true));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 5d3905a..0602a55 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -19,13 +19,11 @@
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
-import android.content.pm.ComponentInfo
import android.content.pm.ConfigurationInfo
import android.content.pm.FeatureInfo
import android.content.pm.InstrumentationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageParser
-import android.content.pm.PackageUserState
import android.content.pm.PermissionInfo
import android.content.pm.ProviderInfo
import android.content.pm.ServiceInfo
@@ -40,14 +38,11 @@
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageStateUnserialized
+import com.android.server.pm.pkg.PackageUserStateInternalImpl
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import org.junit.BeforeClass
-import org.mockito.Mockito.any
-import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.anyString
-import org.mockito.Mockito.mock
import java.io.File
open class AndroidPackageParsingTestBase {
@@ -90,13 +85,7 @@
}
.distinct()
- private val dummyUserState = mock(PackageUserState::class.java).apply {
- installed = true
- whenever(isAvailable(anyInt())) { true }
- whenever(isMatch(any<ComponentInfo>(), anyInt())) { true }
- whenever(isMatch(anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
- anyString(), anyInt())) { true }
- }
+ private val dummyUserState = PackageUserStateInternalImpl()
val oldPackages = mutableListOf<PackageParser.Package>()
diff --git a/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
index e932905..521ffe6 100644
--- a/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
+++ b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
@@ -67,7 +67,7 @@
fun <Type : Any?> whenever(mock: Type) = Mockito.`when`(mock)
@Suppress("UNCHECKED_CAST")
-fun <Type : Any?> whenever(mock: Type, block: InvocationOnMock.() -> Any?) =
+fun <Type> whenever(mock: Type, block: InvocationOnMock.() -> Type) =
Mockito.`when`(mock).thenAnswer { block(it) }
fun whenever(mock: Unit) = Mockito.`when`(mock).thenAnswer { }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 5fa76bb..82140f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -922,6 +922,40 @@
verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any());
}
+ @Test
+ public void testTransitionGoodToGoForTaskFragments_detachedApp() {
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment changeTaskFragment =
+ createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setOrganizer(organizer)
+ .build();
+ changeTaskFragment.getTopMostActivity().allDrawn = true;
+ // To make sure that having a detached activity won't cause any issue.
+ final ActivityRecord detachedActivity = createActivityRecord(task);
+ detachedActivity.removeImmediately();
+ assertNull(detachedActivity.getRootTask());
+ spyOn(mDisplayContent.mAppTransition);
+ spyOn(emptyTaskFragment);
+
+ prepareAndTriggerAppTransition(
+ null /* openingActivity */, detachedActivity, changeTaskFragment);
+
+ // Transition not ready because there is an empty non-finishing TaskFragment.
+ verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any());
+
+ doReturn(true).when(emptyTaskFragment).hasChild();
+ emptyTaskFragment.remove(false /* withTransition */, "test");
+
+ mDisplayContent.mAppTransitionController.handleAppTransitionReady();
+
+ // Transition ready because the empty (no running activity) TaskFragment is requested to be
+ // removed.
+ verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any());
+ }
+
/** Registers remote animation for the organizer. */
private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
RemoteAnimationAdapter adapter) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 52c5b6bb..f4f06fd 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -190,7 +190,8 @@
ServiceManager.getService(Context.WINDOW_SERVICE));
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
+ mContext.registerReceiver(mBroadcastReceiver, filter, null, handler,
+ Context.RECEIVER_NOT_EXPORTED);
}
public boolean showSessionLocked(Bundle args, int flags,
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java
index aa57394..00fe6f2 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java
@@ -24,10 +24,12 @@
import android.net.Uri;
import android.os.Build;
import android.util.Log;
+
import androidx.media.filterfw.FrameImage2D;
import androidx.media.filterfw.FrameValue;
import androidx.media.filterfw.RenderTarget;
+import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
@TargetApi(16)
@@ -276,12 +278,13 @@
}
@TargetApi(17)
- private void retrieveDefaultRotation() {
+ private void retrieveDefaultRotation() throws IOException {
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
metadataRetriever.setDataSource(mContext, mUri);
String rotationString = metadataRetriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
mDefaultRotation = rotationString == null ? 0 : Integer.parseInt(rotationString);
+ metadataRetriever.release();
}
private void onStop(boolean notifyListener) {