Merge "Import translations. DO NOT MERGE ANYWHERE"
diff --git a/apct-tests/perftests/core/src/android/util/ArrayMapPerfTest.java b/apct-tests/perftests/core/src/android/util/ArrayMapPerfTest.java
new file mode 100644
index 0000000..b93a6ea
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/ArrayMapPerfTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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 android.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.BiConsumer;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ArrayMapPerfTest {
+ private static final int NUM_ITERATIONS = 100;
+ private static final int SET_SIZE_SMALL = 10;
+ private static final int SET_SIZE_LARGE = 50;
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void testForEach_Small() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BiConsumer<String, Integer> consumer = (s, i) -> {
+ };
+ while (state.keepRunning()) {
+ for (int i = 0; i < NUM_ITERATIONS; ++i) {
+ ArrayMap<String, Integer> map = new ArrayMap<>();
+ for (int j = 0; j < SET_SIZE_SMALL; j++) {
+ map.put(Integer.toString(j), j);
+ }
+ map.forEach(consumer);
+ }
+ }
+ }
+
+ @Test
+ public void testForEach_Large() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BiConsumer<String, Integer> consumer = (s, i) -> {
+ };
+ while (state.keepRunning()) {
+ for (int i = 0; i < NUM_ITERATIONS; ++i) {
+ ArrayMap<String, Integer> map = new ArrayMap<>();
+ for (int j = 0; j < SET_SIZE_LARGE; j++) {
+ map.put(Integer.toString(j), j);
+ }
+ map.forEach(consumer);
+ }
+ }
+ }
+}
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index 4053bdd..8c8d2bf 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -285,7 +285,7 @@
/** @hide */
public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT = 0;
/** @hide */
- public static final double DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING = 0.01;
+ public static final float DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING = 0.01f;
/** @hide */
public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX = 500;
/** @hide */
@@ -372,7 +372,7 @@
/** @hide */
public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT = 0;
/** @hide */
- public static final double DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING = 0.5;
+ public static final float DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING = 0.5f;
/** @hide */
public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX = 15000;
/** @hide */
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 f0745f3..26237c4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -40,6 +40,7 @@
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -50,6 +51,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
@@ -66,6 +68,7 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.DeviceConfig;
+import android.provider.Settings;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -106,6 +109,7 @@
import com.android.server.job.controllers.RestrictingController;
import com.android.server.job.controllers.StateController;
import com.android.server.job.controllers.StorageController;
+import com.android.server.job.controllers.TareController;
import com.android.server.job.controllers.TimeController;
import com.android.server.job.restrictions.JobRestriction;
import com.android.server.job.restrictions.ThermalStatusRestriction;
@@ -250,6 +254,8 @@
private final DeviceIdleJobsController mDeviceIdleJobsController;
/** Needed to get remaining quota time. */
private final QuotaController mQuotaController;
+ /** Needed to get max execution time and expedited-job allowance. */
+ private final TareController mTareController;
/**
* List of restrictions.
* Note: do not add to or remove from this list at runtime except in the constructor, because we
@@ -344,15 +350,41 @@
// (ScheduledJobStateChanged and JobStatusDumpProto).
public static final int RESTRICTED_INDEX = 5;
- private class ConstantsObserver implements DeviceConfig.OnPropertiesChangedListener {
+ private class ConstantsObserver extends ContentObserver
+ implements DeviceConfig.OnPropertiesChangedListener {
+ private final ContentResolver mContentResolver;
+
+ ConstantsObserver(Handler handler, Context context) {
+ super(handler);
+ mContentResolver = context.getContentResolver();
+ }
+
public void start() {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
JobSchedulerBackgroundThread.getExecutor(), this);
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ENABLE_TARE), false, this);
// Load all the constants.
+ synchronized (mLock) {
+ mConstants.updateSettingsConstantsLocked(mContentResolver);
+ }
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
}
@Override
+ public void onChange(boolean selfChange) {
+ synchronized (mLock) {
+ if (mConstants.updateSettingsConstantsLocked(mContentResolver)) {
+ for (int controller = 0; controller < mControllers.size(); controller++) {
+ final StateController sc = mControllers.get(controller);
+ sc.onConstantsUpdatedLocked();
+ }
+ onControllerStateChanged(null);
+ }
+ }
+ }
+
+ @Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
boolean apiQuotaScheduleUpdated = false;
boolean concurrencyUpdated = false;
@@ -482,6 +514,7 @@
public static final long DEFAULT_RUNTIME_MIN_GUARANTEE_MS = 10 * MINUTE_IN_MILLIS;
@VisibleForTesting
public static final long DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS = 3 * MINUTE_IN_MILLIS;
+ private static final boolean DEFAULT_USE_TARE_POLICY = false;
/**
* Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
@@ -559,6 +592,11 @@
*/
public long RUNTIME_MIN_EJ_GUARANTEE_MS = DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS;
+ /**
+ * If true, use TARE policy for job limiting. If false, use quotas.
+ */
+ public boolean USE_TARE_POLICY = DEFAULT_USE_TARE_POLICY;
+
private void updateBatchingConstantsLocked() {
MIN_READY_NON_ACTIVE_JOBS_COUNT = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
@@ -637,6 +675,17 @@
DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS));
}
+ private boolean updateSettingsConstantsLocked(ContentResolver contentResolver) {
+ boolean changed = false;
+ final boolean isTareEnabled = Settings.Global.getInt(contentResolver,
+ Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE) == 1;
+ if (USE_TARE_POLICY != isTareEnabled) {
+ USE_TARE_POLICY = isTareEnabled;
+ changed = true;
+ }
+ return changed;
+ }
+
void dump(IndentingPrintWriter pw) {
pw.println("Settings:");
pw.increaseIndent();
@@ -665,6 +714,8 @@
pw.print(KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
.println();
+ pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY).println();
+
pw.decreaseIndent();
}
@@ -1130,9 +1181,12 @@
JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
// Return failure early if expedited job quota used up.
- if (jobStatus.isRequestedExpeditedJob()
- && !mQuotaController.isWithinEJQuotaLocked(jobStatus)) {
- return JobScheduler.RESULT_FAILURE;
+ if (jobStatus.isRequestedExpeditedJob()) {
+ if ((mConstants.USE_TARE_POLICY && !mTareController.canScheduleEJ(jobStatus))
+ || (!mConstants.USE_TARE_POLICY
+ && !mQuotaController.isWithinEJQuotaLocked(jobStatus))) {
+ return JobScheduler.RESULT_FAILURE;
+ }
}
// Give exemption if the source is in the foreground just now.
@@ -1474,7 +1528,7 @@
mHandler = new JobHandler(context.getMainLooper());
mConstants = new Constants();
- mConstantsObserver = new ConstantsObserver();
+ mConstantsObserver = new ConstantsObserver(mHandler, context);
mJobSchedulerStub = new JobSchedulerStub();
mConcurrencyManager = new JobConcurrencyManager(this);
@@ -1519,6 +1573,9 @@
new QuotaController(this, backgroundJobsController, connectivityController);
mControllers.add(mQuotaController);
mControllers.add(new ComponentController(this));
+ mTareController =
+ new TareController(this, backgroundJobsController, connectivityController);
+ mControllers.add(mTareController);
mRestrictiveControllers = new ArrayList<>();
mRestrictiveControllers.add(mBatteryController);
@@ -2560,7 +2617,9 @@
public long getMaxJobExecutionTimeMs(JobStatus job) {
synchronized (mLock) {
return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
- mQuotaController.getMaxJobExecutionTimeMsLocked(job));
+ mConstants.USE_TARE_POLICY
+ ? mTareController.getMaxJobExecutionTimeMsLocked(job)
+ : mQuotaController.getMaxJobExecutionTimeMsLocked(job));
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index c61a414..5bdee5e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -54,6 +54,9 @@
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
+import com.android.server.tare.EconomicPolicy;
+import com.android.server.tare.EconomyManagerInternal;
+import com.android.server.tare.JobSchedulerEconomicPolicy;
/**
* Handles client binding and lifecycle of a job. Jobs execute one at a time on an instance of this
@@ -107,6 +110,7 @@
private final Context mContext;
private final Object mLock;
private final IBatteryStats mBatteryStats;
+ private final EconomyManagerInternal mEconomyManagerInternal;
private final JobPackageTracker mJobPackageTracker;
private final PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
@@ -211,6 +215,7 @@
mLock = service.getLock();
mService = service;
mBatteryStats = batteryStats;
+ mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
mJobPackageTracker = tracker;
mCallbackHandler = new JobServiceHandler(looper);
mJobConcurrencyManager = concurrencyManager;
@@ -288,6 +293,11 @@
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
+ // Note the start when we try to bind so that the app is charged for some processing
+ // even if binding fails.
+ mEconomyManagerInternal.noteInstantaneousEvent(
+ job.getSourceUserId(), job.getSourcePackageName(),
+ getStartActionId(job), String.valueOf(job.getJobId()));
mVerb = VERB_BINDING;
scheduleOpTimeOutLocked();
final Intent intent = new Intent().setComponent(job.getServiceComponent());
@@ -350,6 +360,9 @@
} catch (RemoteException e) {
// Whatever.
}
+ mEconomyManagerInternal.noteOngoingEventStarted(
+ job.getSourceUserId(), job.getSourcePackageName(),
+ getRunningActionId(job), String.valueOf(job.getJobId()));
final String jobPackage = job.getSourcePackageName();
final int jobUserId = job.getSourceUserId();
UsageStatsManagerInternal usageStats =
@@ -363,6 +376,22 @@
}
}
+ @EconomicPolicy.AppAction
+ private static int getStartActionId(@NonNull JobStatus job) {
+ if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) {
+ return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START;
+ }
+ return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START;
+ }
+
+ @EconomicPolicy.AppAction
+ private static int getRunningActionId(@NonNull JobStatus job) {
+ if (job.startedAsExpeditedJob || job.shouldTreatAsExpeditedJob()) {
+ return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING;
+ }
+ return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING;
+ }
+
/**
* Used externally to query the running job. Will return null if there is no job running.
*/
@@ -982,6 +1011,15 @@
} catch (RemoteException e) {
// Whatever.
}
+ mEconomyManagerInternal.noteOngoingEventStopped(
+ mRunningJob.getSourceUserId(), mRunningJob.getSourcePackageName(),
+ getRunningActionId(mRunningJob), String.valueOf(mRunningJob.getJobId()));
+ if (mParams.getStopReason() == JobParameters.STOP_REASON_TIMEOUT) {
+ mEconomyManagerInternal.noteInstantaneousEvent(
+ mRunningJob.getSourceUserId(), mRunningJob.getSourcePackageName(),
+ JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT,
+ String.valueOf(mRunningJob.getJobId()));
+ }
if (mWakeLock != null) {
mWakeLock.release();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 321c0b3..607ed3c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -661,7 +661,8 @@
NetworkCapabilities capabilities, Constants constants) {
// A restricted job that's out of quota MUST use an unmetered network.
if (jobStatus.getEffectiveStandbyBucket() == RESTRICTED_INDEX
- && !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
+ && (!jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)
+ || !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_TARE_WEALTH))) {
final NetworkCapabilities.Builder builder =
copyCapabilities(jobStatus.getJob().getRequiredNetwork());
builder.addCapability(NET_CAPABILITY_NOT_METERED);
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 844a480..3801885 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
@@ -1141,7 +1141,7 @@
* treated as an expedited job.
*/
public boolean shouldTreatAsExpeditedJob() {
- return mExpeditedQuotaApproved && isRequestedExpeditedJob();
+ return mExpeditedQuotaApproved && mExpeditedTareApproved && isRequestedExpeditedJob();
}
/**
@@ -1564,7 +1564,8 @@
// sessions (exempt from dynamic restrictions), we need the additional check to ensure
// that NEVER jobs don't run.
// TODO: cleanup quota and standby bucket management so we don't need the additional checks
- if ((!mReadyWithinQuota && !mReadyDynamicSatisfied && !shouldTreatAsExpeditedJob())
+ if (((!mReadyWithinQuota || !mReadyTareWealth)
+ && !mReadyDynamicSatisfied && !shouldTreatAsExpeditedJob())
|| getEffectiveStandbyBucket() == NEVER_INDEX) {
return false;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 36afac8..4ea46eb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -372,6 +372,9 @@
private final BackgroundJobsController mBackgroundJobsController;
private final ConnectivityController mConnectivityController;
+ @GuardedBy("mLock")
+ private boolean mIsEnabled;
+
/** How much time each app will have to run jobs within their standby bucket window. */
private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
@@ -590,6 +593,7 @@
mQcConstants = new QcConstants();
mBackgroundJobsController = backgroundJobsController;
mConnectivityController = connectivityController;
+ mIsEnabled = !mConstants.USE_TARE_POLICY;
// Set up the app standby bucketing tracker
AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
@@ -837,6 +841,9 @@
/** @return true if the job is within expedited job quota. */
@GuardedBy("mLock")
public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) {
+ if (!mIsEnabled) {
+ return true;
+ }
if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) {
return true;
}
@@ -884,6 +891,9 @@
@VisibleForTesting
boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
+ if (!mIsEnabled) {
+ return true;
+ }
final int standbyBucket = jobStatus.getEffectiveStandbyBucket();
// A job is within quota if one of the following is true:
// 1. it was started while the app was in the TOP state
@@ -910,6 +920,9 @@
@GuardedBy("mLock")
boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
final int standbyBucket) {
+ if (!mIsEnabled) {
+ return true;
+ }
if (standbyBucket == NEVER_INDEX) return false;
if (isQuotaFreeLocked(standbyBucket)) return true;
@@ -2980,7 +2993,8 @@
@Override
public void onConstantsUpdatedLocked() {
- if (mQcConstants.mShouldReevaluateConstraints) {
+ if (mQcConstants.mShouldReevaluateConstraints || mIsEnabled == mConstants.USE_TARE_POLICY) {
+ mIsEnabled = !mConstants.USE_TARE_POLICY;
// Update job bookkeeping out of band.
JobSchedulerBackgroundThread.getHandler().post(() -> {
synchronized (mLock) {
@@ -4120,6 +4134,7 @@
@Override
public void dumpControllerStateLocked(final IndentingPrintWriter pw,
final Predicate<JobStatus> predicate) {
+ pw.println("Is enabled: " + mIsEnabled);
pw.println("Is charging: " + mChargeTracker.isChargingLocked());
pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
pw.println();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
index 401646d..be3a3ee 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
@@ -27,6 +27,7 @@
import android.util.SparseArrayMap;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.tare.EconomyManagerInternal;
@@ -170,6 +171,7 @@
mBackgroundJobsController = backgroundJobsController;
mConnectivityController = connectivityController;
mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
+ mIsEnabled = mConstants.USE_TARE_POLICY;
}
@Override
@@ -237,6 +239,32 @@
}
}
+ @Override
+ @GuardedBy("mLock")
+ public void onConstantsUpdatedLocked() {
+ if (mIsEnabled != mConstants.USE_TARE_POLICY) {
+ mIsEnabled = mConstants.USE_TARE_POLICY;
+ // Update job bookkeeping out of band.
+ JobSchedulerBackgroundThread.getHandler().post(() -> {
+ synchronized (mLock) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ mService.getJobStore().forEachJob((jobStatus) -> {
+ if (!mIsEnabled) {
+ jobStatus.setTareWealthConstraintSatisfied(nowElapsed, true);
+ setExpeditedTareApproved(jobStatus, nowElapsed, true);
+ } else {
+ jobStatus.setTareWealthConstraintSatisfied(
+ nowElapsed, hasEnoughWealthLocked(jobStatus));
+ setExpeditedTareApproved(jobStatus, nowElapsed,
+ jobStatus.isRequestedExpeditedJob()
+ && canAffordExpeditedBillLocked(jobStatus));
+ }
+ });
+ }
+ });
+ }
+ }
+
@GuardedBy("mLock")
public boolean canScheduleEJ(@NonNull JobStatus jobStatus) {
if (!mIsEnabled) {
@@ -246,6 +274,21 @@
}
@GuardedBy("mLock")
+ public long getMaxJobExecutionTimeMsLocked(@NonNull JobStatus jobStatus) {
+ if (!mIsEnabled) {
+ return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
+ }
+ if (jobStatus.shouldTreatAsExpeditedJob()) {
+ return mEconomyManagerInternal.getMaxDurationMs(
+ jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
+ BILL_JOB_RUNNING_EXPEDITED);
+ }
+ return mEconomyManagerInternal.getMaxDurationMs(
+ jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
+ BILL_JOB_RUNNING_DEFAULT);
+ }
+
+ @GuardedBy("mLock")
private void addJobToBillList(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index 829ad27..d7c3a86 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -238,8 +238,9 @@
}
@GuardedBy("mLock")
- void noteOngoingEventLocked(final int userId, @NonNull final String pkgName, final int eventId,
- @Nullable String tag, final long startElapsed, final boolean updateBalanceCheck) {
+ private void noteOngoingEventLocked(final int userId, @NonNull final String pkgName,
+ final int eventId, @Nullable String tag, final long startElapsed,
+ final boolean updateBalanceCheck) {
SparseArrayMap<String, OngoingEvent> ongoingEvents =
mCurrentOngoingEvents.get(userId, pkgName);
if (ongoingEvents == null) {
@@ -398,8 +399,8 @@
* registered bills and notify listeners about any changes.
*/
@GuardedBy("mLock")
- void stopOngoingActionLocked(final int userId, @NonNull final String pkgName, final int eventId,
- @Nullable String tag, final long nowElapsed, final long now,
+ private void stopOngoingActionLocked(final int userId, @NonNull final String pkgName,
+ final int eventId, @Nullable String tag, final long nowElapsed, final long now,
final boolean updateBalanceCheck, final boolean notifyOnAffordabilityChange) {
final Ledger ledger = getLedgerLocked(userId, pkgName);
@@ -408,7 +409,7 @@
if (ongoingEvents == null) {
// This may occur if TARE goes from disabled to enabled while an event is already
// occurring.
- Slog.w(TAG, "No ongoing transactions for <" + userId + ">" + pkgName);
+ Slog.w(TAG, "No ongoing transactions for " + appToString(userId, pkgName));
return;
}
final OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag);
@@ -417,7 +418,7 @@
// occurring.
Slog.w(TAG, "Nonexistent ongoing transaction "
+ eventToString(eventId) + (tag == null ? "" : ":" + tag)
- + " for <" + userId + ">" + pkgName + " ended");
+ + " for " + appToString(userId, pkgName) + " ended");
return;
}
ongoingEvent.refCount--;
@@ -472,7 +473,8 @@
Slog.i(TAG, "Would result in too many credits in circulation. Decreasing transaction "
+ eventToString(transaction.eventId)
+ (transaction.tag == null ? "" : ":" + transaction.tag)
- + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta));
+ + " for " + appToString(userId, pkgName)
+ + " by " + (transaction.delta - newDelta));
transaction = new Ledger.Transaction(
transaction.startTimeMs, transaction.endTimeMs,
transaction.eventId, transaction.tag, newDelta);
@@ -485,7 +487,8 @@
Slog.i(TAG, "Would result in becoming too rich. Decreasing transaction "
+ eventToString(transaction.eventId)
+ (transaction.tag == null ? "" : ":" + transaction.tag)
- + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta));
+ + " for " + appToString(userId, pkgName)
+ + " by " + (transaction.delta - newDelta));
transaction = new Ledger.Transaction(
transaction.startTimeMs, transaction.endTimeMs,
transaction.eventId, transaction.tag, newDelta);
@@ -548,7 +551,7 @@
}
if (toReclaim > 0) {
Slog.i(TAG, "Reclaiming unused wealth! Taking " + toReclaim
- + " from <" + userId + ">" + pkgName);
+ + " from " + appToString(userId, pkgName));
recordTransactionLocked(userId, pkgName, ledger,
new Ledger.Transaction(
@@ -845,7 +848,7 @@
@Override
public String toString() {
- return "<" + userId + ">" + packageName;
+ return appToString(userId, packageName);
}
@Override
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 acdf689..6ef9456 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -16,6 +16,79 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.KEY_AM_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
+
import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
@@ -24,6 +97,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
import android.util.SparseArray;
/**
@@ -31,6 +111,8 @@
* AlarmManager.
*/
public class AlarmManagerEconomicPolicy extends EconomicPolicy {
+ private static final String TAG = "TARE- " + AlarmManagerEconomicPolicy.class.getSimpleName();
+
public static final int ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE =
TYPE_ACTION | POLICY_AM | 0;
public static final int ACTION_ALARM_WAKEUP_EXACT =
@@ -57,30 +139,50 @@
COST_MODIFIER_PROCESS_STATE
};
+ private long mMinSatiatedBalance;
+ private long mMaxSatiatedBalance;
+ private long mMaxSatiatedCirculation;
+
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+ private final SettingsObserver mSettingsObserver;
+ private final InternalResourceService mInternalResourceService;
+
private final SparseArray<Action> mActions = new SparseArray<>();
private final SparseArray<Reward> mRewards = new SparseArray<>();
AlarmManagerEconomicPolicy(InternalResourceService irs) {
super(irs);
- loadActions();
- loadRewards();
+ mInternalResourceService = irs;
+ mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
+ loadConstants("");
+ }
+
+ @Override
+ void setup() {
+ super.setup();
+ ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
+ resolver.registerContentObserver(
+ Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_ALARM_MANAGER_CONSTANTS));
}
@Override
long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
// TODO: take exemption into account
- return arcToNarc(160);
+ return mMinSatiatedBalance;
}
@Override
long getMaxSatiatedBalance() {
- return arcToNarc(1440);
+ return mMaxSatiatedBalance;
}
-
@Override
long getMaxSatiatedCirculation() {
- return arcToNarc(52000);
+ return mMaxSatiatedCirculation;
}
@NonNull
@@ -101,43 +203,162 @@
return mRewards.get(rewardId);
}
- private void loadActions() {
+ private void loadConstants(String policyValuesString) {
+ mActions.clear();
+ mRewards.clear();
+
+ try {
+ mParser.setString(policyValuesString);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Global setting key incorrect: ", e);
+ }
+
+ mMinSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
+ DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP));
+ mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MAX_SATIATED_BALANCE,
+ DEFAULT_AM_MAX_SATIATED_BALANCE));
+ mMaxSatiatedCirculation = arcToNarc(mParser.getInt(KEY_AM_MAX_CIRCULATION,
+ DEFAULT_AM_MAX_CIRCULATION));
+
+ final long exactAllowWhileIdleWakeupBasePrice = arcToNarc(
+ mParser.getInt(KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
- new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(5)));
+ new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP)),
+ exactAllowWhileIdleWakeupBasePrice));
mActions.put(ACTION_ALARM_WAKEUP_EXACT,
- new Action(ACTION_ALARM_WAKEUP_EXACT, arcToNarc(3), arcToNarc(4)));
+ new Action(ACTION_ALARM_WAKEUP_EXACT,
+ arcToNarc(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP)),
+ arcToNarc(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE))));
+
+ final long inexactAllowWhileIdleWakeupBasePrice =
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- arcToNarc(3), arcToNarc(4)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP)),
+ inexactAllowWhileIdleWakeupBasePrice));
mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
- new Action(ACTION_ALARM_WAKEUP_INEXACT, arcToNarc(3), arcToNarc(3)));
+ new Action(ACTION_ALARM_WAKEUP_INEXACT,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE))));
+
+ final long exactAllowWhileIdleNonWakeupBasePrice =
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
- arcToNarc(1), arcToNarc(3)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP)),
+ exactAllowWhileIdleNonWakeupBasePrice));
mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
- new Action(ACTION_ALARM_NONWAKEUP_EXACT, arcToNarc(1), arcToNarc(2)));
+ new Action(ACTION_ALARM_NONWAKEUP_EXACT,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE))));
+
+ final long inexactAllowWhileIdleNonWakeupBasePrice =
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- arcToNarc(1), arcToNarc(2)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP)),
+ inexactAllowWhileIdleNonWakeupBasePrice));
mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT,
- new Action(ACTION_ALARM_NONWAKEUP_INEXACT, arcToNarc(1), arcToNarc(1)));
+ new Action(ACTION_ALARM_NONWAKEUP_INEXACT,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE))));
mActions.put(ACTION_ALARM_CLOCK,
- new Action(ACTION_ALARM_CLOCK, arcToNarc(5), arcToNarc(10)));
- }
+ new Action(ACTION_ALARM_CLOCK,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE))));
- private void loadRewards() {
- mRewards.put(REWARD_TOP_ACTIVITY,
- new Reward(REWARD_TOP_ACTIVITY,
- arcToNarc(0), /* .01 arcs */ arcToNarc(1) / 100, arcToNarc(500)));
- mRewards.put(REWARD_NOTIFICATION_SEEN,
- new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(3), arcToNarc(0), arcToNarc(60)));
+ mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT)),
+ (long) (arcToNarc(1) * mParser.getFloat(KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_MAX,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX))));
+ mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_MAX,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX))));
mRewards.put(REWARD_NOTIFICATION_INTERACTION,
new Reward(REWARD_NOTIFICATION_INTERACTION,
- arcToNarc(5), arcToNarc(0), arcToNarc(500)));
- mRewards.put(REWARD_WIDGET_INTERACTION,
- new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING,
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX,
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX))));
+ mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_MAX,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX))));
mRewards.put(REWARD_OTHER_USER_INTERACTION,
new Reward(REWARD_OTHER_USER_INTERACTION,
- arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING,
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX,
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX))));
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_ALARM_MANAGER_CONSTANTS));
+ }
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index 8c56c61..f05e5c9 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -67,6 +67,14 @@
}
@Override
+ void setup() {
+ super.setup();
+ for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+ mEnabledEconomicPolicies.valueAt(i).setup();
+ }
+ }
+
+ @Override
public long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
long min = 0;
for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index a2ba75c..b435c9e 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -19,12 +19,15 @@
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.server.tare.TareUtils.appToString;
import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.tare.IEconomyManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -161,6 +164,18 @@
}
};
+ private final UsageStatsManagerInternal.UsageEventListener mSurveillanceAgent =
+ new UsageStatsManagerInternal.UsageEventListener() {
+ /**
+ * Callback to inform listeners of a new event.
+ */
+ @Override
+ public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
+ mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event)
+ .sendToTarget();
+ }
+ };
+
private final AlarmManager.OnAlarmListener mUnusedWealthReclamationListener =
new AlarmManager.OnAlarmListener() {
@Override
@@ -175,6 +190,7 @@
private static final int MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER = 0;
private static final int MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT = 1;
+ private static final int MSG_PROCESS_USAGE_EVENT = 2;
private static final String ALARM_TAG_WEALTH_RECLAMATION = "*tare.reclamation*";
private static final String KEY_PKG = "pkg";
@@ -374,6 +390,42 @@
}
@GuardedBy("mLock")
+ private void processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event) {
+ if (!mIsEnabled) {
+ return;
+ }
+ final String pkgName = event.getPackageName();
+ if (DEBUG) {
+ Slog.d(TAG, "Processing event " + event.getEventType()
+ + " for " + appToString(userId, pkgName));
+ }
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ switch (event.getEventType()) {
+ case UsageEvents.Event.ACTIVITY_RESUMED:
+ mAgent.noteOngoingEventLocked(userId, pkgName,
+ EconomicPolicy.REWARD_TOP_ACTIVITY, null, nowElapsed);
+ break;
+ case UsageEvents.Event.ACTIVITY_PAUSED:
+ case UsageEvents.Event.ACTIVITY_STOPPED:
+ case UsageEvents.Event.ACTIVITY_DESTROYED:
+ final long now = getCurrentTimeMillis();
+ mAgent.stopOngoingActionLocked(userId, pkgName,
+ EconomicPolicy.REWARD_TOP_ACTIVITY, null, nowElapsed, now);
+ break;
+ case UsageEvents.Event.USER_INTERACTION:
+ case UsageEvents.Event.CHOOSER_ACTION:
+ mAgent.noteInstantaneousEventLocked(userId, pkgName,
+ EconomicPolicy.REWARD_OTHER_USER_INTERACTION, null);
+ break;
+ case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+ case UsageEvents.Event.NOTIFICATION_SEEN:
+ mAgent.noteInstantaneousEventLocked(userId, pkgName,
+ EconomicPolicy.REWARD_NOTIFICATION_SEEN, null);
+ break;
+ }
+ }
+
+ @GuardedBy("mLock")
private void scheduleUnusedWealthReclamationLocked() {
final long now = getCurrentTimeMillis();
final long nextReclamationTime =
@@ -418,7 +470,7 @@
mPkgCache = mPackageManager.getInstalledPackages(0);
}
- private void registerReceivers() {
+ private void registerListeners() {
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
@@ -435,6 +487,9 @@
userFilter.addAction(Intent.ACTION_USER_ADDED);
getContext()
.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+
+ UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
+ usmi.registerListener(mSurveillanceAgent);
}
/** Perform long-running and/or heavy setup work. This should be called off the main thread. */
@@ -454,7 +509,7 @@
return;
}
synchronized (mLock) {
- registerReceivers();
+ registerListeners();
mCurrentBatteryLevel = getCurrentBatteryLevel();
mHandler.post(this::setupHeavyWork);
scheduleUnusedWealthReclamationLocked();
@@ -479,6 +534,9 @@
mPkgCache.clear();
mUidToPackageCache.clear();
getContext().unregisterReceiver(mBroadcastReceiver);
+ UsageStatsManagerInternal usmi =
+ LocalServices.getService(UsageStatsManagerInternal.class);
+ usmi.unregisterListener(mSurveillanceAgent);
}
synchronized (mPackageToUidCache) {
mPackageToUidCache.clear();
@@ -507,6 +565,15 @@
}
break;
+ case MSG_PROCESS_USAGE_EVENT: {
+ final int userId = msg.arg1;
+ final UsageEvents.Event event = (UsageEvents.Event) msg.obj;
+ synchronized (mLock) {
+ processUsageEventLocked(userId, event);
+ }
+ }
+ break;
+
case MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT: {
removeMessages(MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT);
synchronized (mLock) {
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 ff008a2..e339650 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -16,6 +16,88 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
+
import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
@@ -24,6 +106,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
import android.util.SparseArray;
/**
@@ -31,6 +120,8 @@
* JobScheduler.
*/
public class JobSchedulerEconomicPolicy extends EconomicPolicy {
+ private static final String TAG = "TARE- " + JobSchedulerEconomicPolicy.class.getSimpleName();
+
public static final int ACTION_JOB_MAX_START = TYPE_ACTION | POLICY_JS | 0;
public static final int ACTION_JOB_MAX_RUNNING = TYPE_ACTION | POLICY_JS | 1;
public static final int ACTION_JOB_HIGH_START = TYPE_ACTION | POLICY_JS | 2;
@@ -50,29 +141,50 @@
COST_MODIFIER_PROCESS_STATE
};
+ private long mMinSatiatedBalance;
+ private long mMaxSatiatedBalance;
+ private long mMaxSatiatedCirculation;
+
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+ private final SettingsObserver mSettingsObserver;
+ private final InternalResourceService mInternalResourceService;
+
private final SparseArray<Action> mActions = new SparseArray<>();
private final SparseArray<Reward> mRewards = new SparseArray<>();
JobSchedulerEconomicPolicy(InternalResourceService irs) {
super(irs);
- loadActions();
- loadRewards();
+ mInternalResourceService = irs;
+ mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
+ loadConstants("");
+ }
+
+ @Override
+ void setup() {
+ super.setup();
+ ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
+ resolver.registerContentObserver(
+ Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_JOB_SCHEDULER_CONSTANTS));
}
@Override
long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
// TODO: incorporate time since usage
- return arcToNarc(2000);
+ return mMinSatiatedBalance;
}
@Override
long getMaxSatiatedBalance() {
- return arcToNarc(60000);
+ return mMaxSatiatedBalance;
}
@Override
long getMaxSatiatedCirculation() {
- return arcToNarc(691200);
+ return mMaxSatiatedCirculation;
}
@NonNull
@@ -93,45 +205,134 @@
return mRewards.get(rewardId);
}
- private void loadActions() {
- mActions.put(ACTION_JOB_MAX_START,
- new Action(ACTION_JOB_MAX_START, arcToNarc(3), arcToNarc(10)));
- mActions.put(ACTION_JOB_MAX_RUNNING,
- new Action(ACTION_JOB_MAX_RUNNING, arcToNarc(2), arcToNarc(5)));
- mActions.put(ACTION_JOB_HIGH_START,
- new Action(ACTION_JOB_HIGH_START, arcToNarc(3), arcToNarc(8)));
- mActions.put(ACTION_JOB_HIGH_RUNNING,
- new Action(ACTION_JOB_HIGH_RUNNING, arcToNarc(2), arcToNarc(4)));
- mActions.put(ACTION_JOB_DEFAULT_START,
- new Action(ACTION_JOB_DEFAULT_START, arcToNarc(3), arcToNarc(6)));
- mActions.put(ACTION_JOB_DEFAULT_RUNNING,
- new Action(ACTION_JOB_DEFAULT_RUNNING, arcToNarc(2), arcToNarc(3)));
- mActions.put(ACTION_JOB_LOW_START,
- new Action(ACTION_JOB_LOW_START, arcToNarc(3), arcToNarc(4)));
- mActions.put(ACTION_JOB_LOW_RUNNING,
- new Action(ACTION_JOB_LOW_RUNNING, arcToNarc(2), arcToNarc(2)));
- mActions.put(ACTION_JOB_MIN_START,
- new Action(ACTION_JOB_MIN_START, arcToNarc(3), arcToNarc(2)));
- mActions.put(ACTION_JOB_MIN_RUNNING,
- new Action(ACTION_JOB_MIN_RUNNING, arcToNarc(2), arcToNarc(1)));
- mActions.put(ACTION_JOB_TIMEOUT,
- new Action(ACTION_JOB_TIMEOUT, arcToNarc(30), arcToNarc(60)));
- }
+ private void loadConstants(String policyValuesString) {
+ mActions.clear();
+ mRewards.clear();
- private void loadRewards() {
- mRewards.put(REWARD_TOP_ACTIVITY,
- new Reward(REWARD_TOP_ACTIVITY,
- arcToNarc(0), /* .5 arcs */ arcToNarc(5) / 10, arcToNarc(15000)));
- mRewards.put(REWARD_NOTIFICATION_SEEN,
- new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(1), arcToNarc(0), arcToNarc(10)));
+ try {
+ mParser.setString(policyValuesString);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Global setting key incorrect: ", e);
+ }
+
+ mMinSatiatedBalance = arcToNarc(
+ mParser.getInt(KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP,
+ DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP));
+ mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_JS_MAX_SATIATED_BALANCE,
+ DEFAULT_JS_MAX_SATIATED_BALANCE));
+ mMaxSatiatedCirculation = arcToNarc(mParser.getInt(KEY_JS_MAX_CIRCULATION,
+ DEFAULT_JS_MAX_CIRCULATION));
+
+ mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_CTP,
+ DEFAULT_JS_ACTION_JOB_MAX_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_MAX_RUNNING, new Action(ACTION_JOB_MAX_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_HIGH_START, new Action(ACTION_JOB_HIGH_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_CTP,
+ DEFAULT_JS_ACTION_JOB_HIGH_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_HIGH_RUNNING, new Action(ACTION_JOB_HIGH_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_DEFAULT_START, new Action(ACTION_JOB_DEFAULT_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_CTP,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_DEFAULT_RUNNING, new Action(ACTION_JOB_DEFAULT_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_LOW_START, new Action(ACTION_JOB_LOW_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_CTP,
+ DEFAULT_JS_ACTION_JOB_LOW_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_LOW_RUNNING, new Action(ACTION_JOB_LOW_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_MIN_START, new Action(ACTION_JOB_MIN_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_CTP,
+ DEFAULT_JS_ACTION_JOB_MIN_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_MIN_RUNNING, new Action(ACTION_JOB_MIN_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_TIMEOUT, new Action(ACTION_JOB_TIMEOUT,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP,
+ DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE))));
+
+ mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_INSTANT,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT)),
+ (long) (arcToNarc(1) * mParser.getFloat(KEY_JS_REWARD_TOP_ACTIVITY_ONGOING,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_MAX,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX))));
+ mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_MAX,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX))));
mRewards.put(REWARD_NOTIFICATION_INTERACTION,
new Reward(REWARD_NOTIFICATION_INTERACTION,
- arcToNarc(5), arcToNarc(0), arcToNarc(5000)));
- mRewards.put(REWARD_WIDGET_INTERACTION,
- new Reward(REWARD_WIDGET_INTERACTION,
- arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING,
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX,
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX))));
+ mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_MAX,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX))));
mRewards.put(REWARD_OTHER_USER_INTERACTION,
new Reward(REWARD_OTHER_USER_INTERACTION,
- arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING,
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX,
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX))));
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_JOB_SCHEDULER_CONSTANTS));
+ }
}
}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 1bf732b..d963e68 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -120,7 +120,7 @@
srcs: [
"java/android/media/ApplicationMediaCapabilities.java",
"java/android/media/MediaFeature.java",
- "java/android/media/MediaTranscodeManager.java",
+ "java/android/media/MediaTranscodingManager.java",
],
path: "java",
}
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index ce68447..6eea769 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -1,15 +1,15 @@
// Signature format: 2.0
package android.media {
- public final class MediaTranscodeManager {
- method @Nullable public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener);
+ public final class MediaTranscodingManager {
+ method @Nullable public android.media.MediaTranscodingManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodingManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodingManager.OnTranscodingFinishedListener);
}
- @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
- method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingSession);
+ @java.lang.FunctionalInterface public static interface MediaTranscodingManager.OnTranscodingFinishedListener {
+ method public void onTranscodingFinished(@NonNull android.media.MediaTranscodingManager.TranscodingSession);
}
- public abstract static class MediaTranscodeManager.TranscodingRequest {
+ public abstract static class MediaTranscodingManager.TranscodingRequest {
method public int getClientPid();
method public int getClientUid();
method @Nullable public android.os.ParcelFileDescriptor getDestinationFileDescriptor();
@@ -18,13 +18,13 @@
method @NonNull public android.net.Uri getSourceUri();
}
- public static class MediaTranscodeManager.TranscodingRequest.VideoFormatResolver {
- ctor public MediaTranscodeManager.TranscodingRequest.VideoFormatResolver(@NonNull android.media.ApplicationMediaCapabilities, @NonNull android.media.MediaFormat);
+ public static class MediaTranscodingManager.TranscodingRequest.VideoFormatResolver {
+ ctor public MediaTranscodingManager.TranscodingRequest.VideoFormatResolver(@NonNull android.media.ApplicationMediaCapabilities, @NonNull android.media.MediaFormat);
method @Nullable public android.media.MediaFormat resolveVideoFormat();
method public boolean shouldTranscode();
}
- public static final class MediaTranscodeManager.TranscodingSession {
+ public static final class MediaTranscodingManager.TranscodingSession {
method public boolean addClientUid(int);
method public void cancel();
method @NonNull public java.util.List<java.lang.Integer> getClientUids();
@@ -33,7 +33,7 @@
method public int getResult();
method public int getSessionId();
method public int getStatus();
- method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
+ method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener);
field public static final int ERROR_DROPPED_BY_SERVICE = 1; // 0x1
field public static final int ERROR_NONE = 0; // 0x0
field public static final int ERROR_SERVICE_DIED = 2; // 0x2
@@ -47,21 +47,21 @@
field public static final int STATUS_RUNNING = 2; // 0x2
}
- @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener {
- method public void onProgressUpdate(@NonNull android.media.MediaTranscodeManager.TranscodingSession, @IntRange(from=0, to=100) int);
+ @java.lang.FunctionalInterface public static interface MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener {
+ method public void onProgressUpdate(@NonNull android.media.MediaTranscodingManager.TranscodingSession, @IntRange(from=0, to=100) int);
}
- public static final class MediaTranscodeManager.VideoTranscodingRequest extends android.media.MediaTranscodeManager.TranscodingRequest {
+ public static final class MediaTranscodingManager.VideoTranscodingRequest extends android.media.MediaTranscodingManager.TranscodingRequest {
method @NonNull public android.media.MediaFormat getVideoTrackFormat();
}
- public static final class MediaTranscodeManager.VideoTranscodingRequest.Builder {
- ctor public MediaTranscodeManager.VideoTranscodingRequest.Builder(@NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.media.MediaFormat);
- method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest build();
- method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setClientPid(int);
- method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setClientUid(int);
- method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setDestinationFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
- method @NonNull public android.media.MediaTranscodeManager.VideoTranscodingRequest.Builder setSourceFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
+ public static final class MediaTranscodingManager.VideoTranscodingRequest.Builder {
+ ctor public MediaTranscodingManager.VideoTranscodingRequest.Builder(@NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.media.MediaFormat);
+ method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientPid(int);
+ method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientUid(int);
+ method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setDestinationFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
+ method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setSourceFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
}
}
diff --git a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
index de2924e..75a56b72 100644
--- a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
+++ b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
@@ -75,8 +75,8 @@
public static void registerServiceWrappers() {
SystemServiceRegistry.registerContextAwareService(
Context.MEDIA_TRANSCODING_SERVICE,
- MediaTranscodeManager.class,
- context -> new MediaTranscodeManager(context)
+ MediaTranscodingManager.class,
+ context -> new MediaTranscodingManager(context)
);
if (SdkLevel.isAtLeastS()) {
SystemServiceRegistry.registerContextAwareService(
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodingManager.java
similarity index 98%
rename from apex/media/framework/java/android/media/MediaTranscodeManager.java
rename to apex/media/framework/java/android/media/MediaTranscodingManager.java
index 5742d43..93d58d0 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodingManager.java
@@ -54,7 +54,7 @@
/**
Android 12 introduces Compatible media transcoding feature. See
<a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding">
- Compatible media transcoding</a>. MediaTranscodeManager provides an interface to the system's media
+ Compatible media transcoding</a>. MediaTranscodingManager provides an interface to the system's media
transcoding service and can be used to transcode media files, e.g. transcoding a video from HEVC to
AVC.
@@ -69,7 +69,7 @@
<p>
To transcode a media file, first create a {@link TranscodingRequest} through its builder class
{@link VideoTranscodingRequest.Builder}. Transcode requests are then enqueue to the manager through
- {@link MediaTranscodeManager#enqueueRequest(
+ {@link MediaTranscodingManager#enqueueRequest(
TranscodingRequest, Executor, OnTranscodingFinishedListener)}
TranscodeRequest are processed based on client process's priority and request priority. When a
transcode operation is completed the caller is notified via its
@@ -87,8 +87,8 @@
*/
@MinSdk(Build.VERSION_CODES.S)
@SystemApi
-public final class MediaTranscodeManager {
- private static final String TAG = "MediaTranscodeManager";
+public final class MediaTranscodingManager {
+ private static final String TAG = "MediaTranscodingManager";
/** Maximum number of retry to connect to the service. */
private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
@@ -127,7 +127,7 @@
private final Object mLock = new Object();
@GuardedBy("mLock")
@NonNull private ITranscodingClient mTranscodingClient = null;
- private static MediaTranscodeManager sMediaTranscodeManager;
+ private static MediaTranscodingManager sMediaTranscodingManager;
private void handleTranscodingFinished(int sessionId, TranscodingResultParcel result) {
synchronized (mPendingTranscodingSessions) {
@@ -306,7 +306,7 @@
}
try {
- // Do not set hasRetried for retry initiated by MediaTranscodeManager.
+ // Do not set hasRetried for retry initiated by MediaTranscodingManager.
session.retryInternal(false /*setHasRetried*/);
} catch (Exception re) {
// TODO(hkuang): Return correct error code to the client.
@@ -423,7 +423,7 @@
/**
* @hide
*/
- public MediaTranscodeManager(@NonNull Context context) {
+ public MediaTranscodingManager(@NonNull Context context) {
mContext = context;
mContentResolver = mContext.getContentResolver();
mPackageName = mContext.getPackageName();
@@ -1348,7 +1348,7 @@
@IntRange(from = 0, to = 100) int progress);
}
- private final MediaTranscodeManager mManager;
+ private final MediaTranscodingManager mManager;
private Executor mListenerExecutor;
private OnTranscodingFinishedListener mListener;
private int mSessionId = -1;
@@ -1374,7 +1374,7 @@
private final TranscodingRequest mRequest;
private TranscodingSession(
- @NonNull MediaTranscodeManager manager,
+ @NonNull MediaTranscodingManager manager,
@NonNull TranscodingRequest request,
@NonNull TranscodingSessionParcel parcel,
@NonNull @CallbackExecutor Executor executor,
@@ -1675,10 +1675,10 @@
/**
* Enqueues a TranscodingRequest for execution.
- * <p> Upon successfully accepting the request, MediaTranscodeManager will return a
+ * <p> Upon successfully accepting the request, MediaTranscodingManager will return a
* {@link TranscodingSession} to the client. Client should use {@link TranscodingSession} to
* track the progress and get the result.
- * <p> MediaTranscodeManager will return null if fails to accept the request due to service
+ * <p> MediaTranscodingManager will return null if fails to accept the request due to service
* rebooting. Client could retry again after receiving null.
*
* @param transcodingRequest The TranscodingRequest to enqueue.
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 6e27aff..929e63e 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -107,9 +107,13 @@
static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
static constexpr size_t TEXT_POS_LEN_MAX = 16;
+static const int DYNAMIC_COLOR_COUNT = 4;
static const char U_TEXTURE[] = "uTexture";
static const char U_FADE[] = "uFade";
static const char U_CROP_AREA[] = "uCropArea";
+static const char U_START_COLOR_PREFIX[] = "uStartColor";
+static const char U_END_COLOR_PREFIX[] = "uEndColor";
+static const char U_COLOR_PROGRESS[] = "uColorProgress";
static const char A_UV[] = "aUv";
static const char A_POSITION[] = "aPosition";
static const char VERTEX_SHADER_SOURCE[] = R"(
@@ -121,6 +125,28 @@
gl_Position = aPosition;
vUv = aUv;
})";
+static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
+ precision mediump float;
+ uniform sampler2D uTexture;
+ uniform float uFade;
+ uniform float uColorProgress;
+ uniform vec4 uStartColor0;
+ uniform vec4 uStartColor1;
+ uniform vec4 uStartColor2;
+ uniform vec4 uStartColor3;
+ uniform vec4 uEndColor0;
+ uniform vec4 uEndColor1;
+ uniform vec4 uEndColor2;
+ uniform vec4 uEndColor3;
+ varying highp vec2 vUv;
+ void main() {
+ vec4 mask = texture2D(uTexture, vUv);
+ vec4 color = mask.r * mix(uStartColor0, uEndColor0, uColorProgress)
+ + mask.g * mix(uStartColor1, uEndColor1, uColorProgress)
+ + mask.b * mix(uStartColor2, uEndColor2, uColorProgress)
+ + mask.a * mix(uStartColor3, uEndColor3, uColorProgress);
+ gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
+ })";
static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
uniform sampler2D uTexture;
@@ -128,7 +154,7 @@
varying highp vec2 vUv;
void main() {
vec4 color = texture2D(uTexture, vUv);
- gl_FragColor = vec4(color.x, color.y, color.z, 1.0 - uFade);
+ gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
})";
static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
@@ -226,6 +252,10 @@
outInfo->stride = AImageDecoder_getMinimumStride(decoder);
outInfo->flags = 0;
+ // Set decoding option to alpha unpremultiplied so that the R, G, B channels
+ // of transparent pixels are preserved.
+ AImageDecoder_setUnpremultipliedRequired(decoder, true);
+
const size_t size = outInfo->stride * outInfo->height;
void* pixels = malloc(size);
int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
@@ -675,9 +705,12 @@
}
void BootAnimation::initShaders() {
+ bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled;
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
GLuint imageFragmentShader =
- compileShader(GL_FRAGMENT_SHADER, (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
+ compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled
+ ? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE
+ : (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
GLuint textFragmentShader =
compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE);
@@ -692,6 +725,22 @@
glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
glEnableVertexAttribArray(uvLocation);
+ if (dynamicColoringEnabled) {
+ glUseProgram(mImageShader);
+ SLOGI("[BootAnimation] Dynamically coloring boot animation.");
+ for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+ float *startColor = mAnimation->startColors[i];
+ float *endColor = mAnimation->endColors[i];
+ glUniform4f(glGetUniformLocation(mImageShader,
+ (U_START_COLOR_PREFIX + std::to_string(i)).c_str()),
+ startColor[0], startColor[1], startColor[2], 1 /* alpha */);
+ glUniform4f(glGetUniformLocation(mImageShader,
+ (U_END_COLOR_PREFIX + std::to_string(i)).c_str()),
+ endColor[0], endColor[1], endColor[2], 1 /* alpha */);
+ }
+ mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS);
+ }
+
// Initialize text shader.
mTextShader = linkShader(vertexShader, textFragmentShader);
positionLocation = glGetAttribLocation(mTextShader, A_POSITION);
@@ -869,6 +918,20 @@
return true;
}
+// Parse a color represented as a signed decimal int string.
+// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6).
+// If the input color string is empty, set color with values in defaultColor.
+static void parseColorDecimalString(const std::string& colorString,
+ float color[3], float defaultColor[3]) {
+ if (colorString == "") {
+ memcpy(color, defaultColor, sizeof(float) * 3);
+ return;
+ }
+ int colorInt = atoi(colorString.c_str());
+ color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r
+ color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g
+ color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b
+}
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
ZipEntryRO entry = zip->findEntryByName(name);
@@ -1010,6 +1073,8 @@
return false;
}
char const* s = desString.string();
+ std::string dynamicColoringPartName = "";
+ bool postDynamicColoring = false;
// Parse the description file
for (;;) {
@@ -1028,7 +1093,13 @@
char color[7] = "000000"; // default to black if unspecified
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
+ char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
char pathType;
+ // start colors default to black if unspecified
+ char start_color_0[7] = "000000";
+ char start_color_1[7] = "000000";
+ char start_color_2[7] = "000000";
+ char start_color_3[7] = "000000";
int nextReadPos;
@@ -1043,6 +1114,15 @@
} else {
animation.progressEnabled = false;
}
+ } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s",
+ dynamicColoringPartNameBuffer,
+ start_color_0, start_color_1, start_color_2, start_color_3)) {
+ animation.dynamicColoringEnabled = true;
+ parseColor(start_color_0, animation.startColors[0]);
+ parseColor(start_color_1, animation.startColors[1]);
+ parseColor(start_color_2, animation.startColors[2]);
+ parseColor(start_color_3, animation.startColors[3]);
+ dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
} else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
&pathType, &count, &pause, path, &nextReadPos) >= 4) {
if (pathType == 'f') {
@@ -1055,6 +1135,16 @@
// "clockPos1=%s, clockPos2=%s",
// pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
Animation::Part part;
+ if (path == dynamicColoringPartName) {
+ // Part is specified to use dynamic coloring.
+ part.useDynamicColoring = true;
+ part.postDynamicColoring = false;
+ postDynamicColoring = true;
+ } else {
+ // Part does not use dynamic coloring.
+ part.useDynamicColoring = false;
+ part.postDynamicColoring = postDynamicColoring;
+ }
part.playUntilComplete = pathType == 'c';
part.framesToFadeCount = framesToFadeCount;
part.count = count;
@@ -1086,6 +1176,12 @@
s = ++endl;
}
+ for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+ parseColorDecimalString(
+ android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""),
+ animation.endColors[i], animation.startColors[i]);
+ }
+
return true;
}
@@ -1357,6 +1453,14 @@
for (size_t j=0 ; j<fcount ; j++) {
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
+ // Color progress is
+ // - the normalized animation progress between [0, 1] for the dynamic coloring part,
+ // - 0 for parts that come before,
+ // - 1 for parts that come after.
+ float colorProgress = part.useDynamicColoring
+ ? (float)j / fcount
+ : (part.postDynamicColoring ? 1 : 0);
+
processDisplayEvents();
const int animationX = (mWidth - animation.width) / 2;
@@ -1376,19 +1480,7 @@
const int xc = animationX + frame.trimX;
const int yc = animationY + frame.trimY;
- Region clearReg(Rect(mWidth, mHeight));
- clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
- if (!clearReg.isEmpty()) {
- Region::const_iterator head(clearReg.begin());
- Region::const_iterator tail(clearReg.end());
- glEnable(GL_SCISSOR_TEST);
- while (head != tail) {
- const Rect& r2(*head++);
- glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
- glClear(GL_COLOR_BUFFER_BIT);
- }
- glDisable(GL_SCISSOR_TEST);
- }
+ glClear(GL_COLOR_BUFFER_BIT);
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
// which is equivalent to mHeight - (yc + frame.trimHeight)
const int frameDrawY = mHeight - (yc + frame.trimHeight);
@@ -1404,6 +1496,9 @@
glUseProgram(mImageShader);
glUniform1i(mImageTextureLocation, 0);
glUniform1f(mImageFadeLocation, fade);
+ if (animation.dynamicColoringEnabled) {
+ glUniform1f(mImageColorProgressLocation, colorProgress);
+ }
glEnable(GL_BLEND);
drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
glDisable(GL_BLEND);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 7b616d9..2c861eb 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -90,6 +90,10 @@
uint8_t* audioData;
int audioLength;
Animation* animation;
+ // Controls if dynamic coloring is enabled for this part.
+ bool useDynamicColoring = false;
+ // Defines if this part is played after the dynamic coloring part.
+ bool postDynamicColoring = false;
bool hasFadingPhase() const {
return !playUntilComplete && framesToFadeCount > 0;
@@ -105,6 +109,10 @@
ZipFileRO* zip;
Font clockFont;
Font progressFont;
+ // Controls if dynamic coloring is enabled for the whole animation.
+ bool dynamicColoringEnabled = false;
+ float startColors[4][3]; // Start colors of dynamic color transition.
+ float endColors[4][3]; // End colors of dynamic color transition.
};
// All callbacks will be called from this class's internal thread.
@@ -226,6 +234,7 @@
GLuint mImageTextureLocation;
GLuint mTextCropAreaLocation;
GLuint mTextTextureLocation;
+ GLuint mImageColorProgressLocation;
};
// ---------------------------------------------------------------------------
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ae812ec..bff1e57 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1105,18 +1105,17 @@
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
- CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
+ CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,
SharedMemory serializedSystemFontMap) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
- for (Object oname : services.keySet()) {
- if (services.get(oname) == null) {
+ for (String name : services.keySet()) {
+ if (services.get(name) == null) {
continue; // AM just passed in a null service.
}
- String name = (String) oname;
// See b/79378449 about the following exemption.
switch (name) {
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index d6ff6d3..2afd98e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -77,7 +77,7 @@
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
int debugMode, boolean enableBinderTracking, boolean trackAllocation,
boolean restrictedBackupMode, boolean persistent, in Configuration config,
- in CompatibilityInfo compatInfo, in Map services,
+ in CompatibilityInfo compatInfo, in Map<String, IBinder> services,
in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges,
in SharedMemory serializedSystemFontMap);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4b401a5..7102314 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3270,22 +3270,6 @@
}
/**
- * Returns true if the Profile Challenge is available to use for the given profile user.
- *
- * @hide
- */
- public boolean isSeparateProfileChallengeAllowed(int userHandle) {
- if (mService != null) {
- try {
- return mService.isSeparateProfileChallengeAllowed(userHandle);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- return false;
- }
-
- /**
* Constant for {@link #setPasswordQuality}: the policy has no requirements
* for the password. Note that quality constants are ordered so that higher
* values are more restrictive.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b6c48a1..8cf1f80 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -373,8 +373,6 @@
CharSequence getShortSupportMessageForUser(in ComponentName admin, int userHandle);
CharSequence getLongSupportMessageForUser(in ComponentName admin, int userHandle);
- boolean isSeparateProfileChallengeAllowed(int userHandle);
-
void setOrganizationColor(in ComponentName admin, in int color);
void setOrganizationColorForUser(in int color, in int userId);
int getOrganizationColor(in ComponentName admin);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2ed26a9f..2b28c11 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -64,6 +64,8 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -78,6 +80,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
+import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -715,10 +718,21 @@
private final IBluetoothManager mManagerService;
private final AttributionSource mAttributionSource;
+ // Yeah, keeping both mService and sService isn't pretty, but it's too late
+ // in the current release for a major refactoring, so we leave them both
+ // intact until this can be cleaned up in a future release
+
@UnsupportedAppUsage
+ @GuardedBy("mServiceLock")
private IBluetooth mService;
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("sServiceLock")
+ private static boolean sServiceRegistered;
+ @GuardedBy("sServiceLock")
+ private static IBluetooth sService;
+ private static final Object sServiceLock = new Object();
+
private final Object mLock = new Object();
private final Map<LeScanCallback, ScanCallback> mLeScanClients;
private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
@@ -792,19 +806,11 @@
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
*/
BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
- if (managerService == null) {
- throw new IllegalArgumentException("bluetooth manager service is null");
- }
- try {
- mServiceLock.writeLock().lock();
- mService = managerService.registerAdapter(mManagerCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.writeLock().unlock();
- }
mManagerService = Objects.requireNonNull(managerService);
mAttributionSource = Objects.requireNonNull(attributionSource);
+ synchronized (mServiceLock.writeLock()) {
+ mService = getBluetoothService(mManagerCallback);
+ }
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
mToken = new Binder(DESCRIPTOR);
}
@@ -3162,21 +3168,16 @@
}
}
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothManagerCallback mManagerCallback =
+ private static final IBluetoothManagerCallback sManagerCallback =
new IBluetoothManagerCallback.Stub() {
- @SuppressLint("AndroidFrameworkRequiresPermission")
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
if (DBG) {
Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
}
- mServiceLock.writeLock().lock();
- mService = bluetoothService;
- mServiceLock.writeLock().unlock();
-
- synchronized (mProxyServiceStateCallbacks) {
- for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
+ synchronized (sServiceLock) {
+ sService = bluetoothService;
+ for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
try {
if (cb != null) {
cb.onBluetoothServiceUp(bluetoothService);
@@ -3188,6 +3189,56 @@
}
}
}
+ }
+
+ public void onBluetoothServiceDown() {
+ if (DBG) {
+ Log.d(TAG, "onBluetoothServiceDown");
+ }
+
+ synchronized (sServiceLock) {
+ sService = null;
+ for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
+ try {
+ if (cb != null) {
+ cb.onBluetoothServiceDown();
+ } else {
+ Log.d(TAG, "onBluetoothServiceDown: cb is null!");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+ }
+
+ public void onBrEdrDown() {
+ if (VDBG) {
+ Log.i(TAG, "onBrEdrDown");
+ }
+
+ synchronized (sServiceLock) {
+ for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
+ try {
+ if (cb != null) {
+ cb.onBrEdrDown();
+ } else {
+ Log.d(TAG, "onBrEdrDown: cb is null!");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+ }
+ };
+
+ private final IBluetoothManagerCallback mManagerCallback =
+ new IBluetoothManagerCallback.Stub() {
+ public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+ synchronized (mServiceLock.writeLock()) {
+ mService = bluetoothService;
+ }
synchronized (mMetadataListeners) {
mMetadataListeners.forEach((device, pair) -> {
try {
@@ -3212,12 +3263,7 @@
}
public void onBluetoothServiceDown() {
- if (DBG) {
- Log.d(TAG, "onBluetoothServiceDown: " + mService);
- }
-
- try {
- mServiceLock.writeLock().lock();
+ synchronized (mServiceLock.writeLock()) {
mService = null;
if (mLeScanClients != null) {
mLeScanClients.clear();
@@ -3228,29 +3274,10 @@
if (mBluetoothLeScanner != null) {
mBluetoothLeScanner.cleanup();
}
- } finally {
- mServiceLock.writeLock().unlock();
- }
-
- synchronized (mProxyServiceStateCallbacks) {
- for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
- try {
- if (cb != null) {
- cb.onBluetoothServiceDown();
- } else {
- Log.d(TAG, "onBluetoothServiceDown: cb is null!");
- }
- } catch (Exception e) {
- Log.e(TAG, "", e);
- }
- }
}
}
public void onBrEdrDown() {
- if (VDBG) {
- Log.i(TAG, "onBrEdrDown: " + mService);
- }
}
};
@@ -3485,15 +3512,12 @@
protected void finalize() throws Throwable {
try {
- mManagerService.unregisterAdapter(mManagerCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
+ removeServiceStateCallback(mManagerCallback);
} finally {
super.finalize();
}
}
-
/**
* Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
* <p>Alphabetic characters must be uppercase to be valid.
@@ -3557,24 +3581,64 @@
return mAttributionSource;
}
- private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks =
- new ArrayList<IBluetoothManagerCallback>();
+ @GuardedBy("sServiceLock")
+ private static final WeakHashMap<IBluetoothManagerCallback, Void> sProxyServiceStateCallbacks =
+ new WeakHashMap<>();
+
+ /*package*/ IBluetooth getBluetoothService() {
+ synchronized (sServiceLock) {
+ if (sProxyServiceStateCallbacks.isEmpty()) {
+ throw new IllegalStateException(
+ "Anonymous service access requires at least one lifecycle in process");
+ }
+ return sService;
+ }
+ }
@UnsupportedAppUsage
/*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
- synchronized (mProxyServiceStateCallbacks) {
- if (cb == null) {
- Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
- } else if (!mProxyServiceStateCallbacks.contains(cb)) {
- mProxyServiceStateCallbacks.add(cb);
- }
+ Objects.requireNonNull(cb);
+ synchronized (sServiceLock) {
+ sProxyServiceStateCallbacks.put(cb, null);
+ registerOrUnregisterAdapterLocked();
+ return sService;
}
- return mService;
}
/*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
- synchronized (mProxyServiceStateCallbacks) {
- mProxyServiceStateCallbacks.remove(cb);
+ Objects.requireNonNull(cb);
+ synchronized (sServiceLock) {
+ sProxyServiceStateCallbacks.remove(cb);
+ registerOrUnregisterAdapterLocked();
+ }
+ }
+
+ /**
+ * Handle registering (or unregistering) a single process-wide
+ * {@link IBluetoothManagerCallback} based on the presence of local
+ * {@link #sProxyServiceStateCallbacks} clients.
+ */
+ @GuardedBy("sServiceLock")
+ private void registerOrUnregisterAdapterLocked() {
+ final boolean isRegistered = sServiceRegistered;
+ final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty();
+
+ if (isRegistered != wantRegistered) {
+ if (wantRegistered) {
+ try {
+ sService = mManagerService.registerAdapter(sManagerCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ try {
+ mManagerService.unregisterAdapter(sManagerCallback);
+ sService = null;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ sServiceRegistered = wantRegistered;
}
}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index bb409d5..1655b62 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -399,7 +399,7 @@
try {
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
IBluetooth bluetoothProxy =
- BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ BluetoothAdapter.getDefaultAdapter().getBluetoothService();
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
mUuid, mPort, getSecurityFlags());
@@ -438,7 +438,7 @@
/*package*/ int bindListen() {
int ret;
if (mSocketState == SocketState.CLOSED) return EBADFD;
- IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
if (bluetoothProxy == null) {
Log.e(TAG, "bindListen fail, reason: bluetooth is off");
return -1;
@@ -706,7 +706,7 @@
throw new IOException("socket closed");
}
IBluetooth bluetoothProxy =
- BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ BluetoothAdapter.getDefaultAdapter().getBluetoothService();
if (bluetoothProxy == null) {
throw new IOException("Bluetooth is off");
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 31a84ed..ad1163f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4470,11 +4470,11 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link
- * android.media.MediaTranscodeManager} for transcoding media.
+ * android.media.MediaTranscodingManager} for transcoding media.
*
* @hide
* @see #getSystemService(String)
- * @see android.media.MediaTranscodeManager
+ * @see android.media.MediaTranscodingManager
*/
@SystemApi
public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a5cd331..19db0ba 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1077,8 +1077,7 @@
public static final int ROLLBACK_DATA_POLICY_WIPE = 1;
/**
- * User data won't be backed up during install and won't be restored during rollback.
- * TODO: Not implemented yet.
+ * User data won't be backed up during install and will remain unchanged during rollback.
*
* @hide
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7a031e3..57fd736 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10221,6 +10221,13 @@
"device_state_rotation_lock";
/**
+ * Control whether communal mode is allowed on this device.
+ *
+ * @hide
+ */
+ public static final String COMMUNAL_MODE_ENABLED = "communal_mode_enabled";
+
+ /**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
*/
@@ -10367,6 +10374,14 @@
"enable_accessibility_global_gesture_enabled";
/**
+ * Whether select sound track with audio description by default.
+ * @hide
+ */
+ @Readable
+ public static final String ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT =
+ "enable_accessibility_audio_description_by_default";
+
+ /**
* Whether Airplane Mode is on.
*/
@Readable
@@ -16895,6 +16910,14 @@
* @hide
*/
public static final String COMBINED_LOCATION_ENABLED = "combined_location_enable";
+
+ /**
+ * The wrist orientation mode of the device
+ * Valid values - LEFT_WRIST_ROTATION_0 = "0" (default), LEFT_WRIST_ROTATION_180 = "1",
+ * RIGHT_WRIST_ROTATION_0 = "2", RIGHT_WRIST_ROTATION_180 = "3"
+ * @hide
+ */
+ public static final String WRIST_ORIENTATION_MODE = "wear_wrist_orientation_mode";
}
}
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 4edff27..f50b51b 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -27,6 +27,7 @@
import java.util.ConcurrentModificationException;
import java.util.Map;
import java.util.Set;
+import java.util.function.BiConsumer;
/**
* ArrayMap is a generic key->value mapping data structure that is
@@ -980,6 +981,28 @@
}
/**
+ * Performs the given action for all elements in the stored order. This implementation overrides
+ * the default implementation to avoid iterating using the {@link #entrySet()} and iterates in
+ * the key-value order consistent with {@link #keyAt(int)} and {@link #valueAt(int)}.
+ *
+ * @param action The action to be performed for each element
+ */
+ @Override
+ public void forEach(BiConsumer<? super K, ? super V> action) {
+ if (action == null) {
+ throw new NullPointerException("action must not be null");
+ }
+
+ final int size = mSize;
+ for (int i = 0; i < size; ++i) {
+ if (size != mSize) {
+ throw new ConcurrentModificationException();
+ }
+ action.accept(keyAt(i), valueAt(i));
+ }
+ }
+
+ /**
* Perform a {@link #put(Object, Object)} of all key/value pairs in <var>map</var>
* @param map The map whose contents are to be retrieved.
*/
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index c16ee42..7d2cb50 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -789,6 +789,9 @@
} else {
mDisplayResolveInfo.setDisplayIcon(d);
mHolder.bindIcon(mDisplayResolveInfo);
+ // Notify in case view is already bound to resolve the race conditions on
+ // low end devices
+ notifyDataSetChanged();
}
}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 10750b6..0c56c67 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -64,8 +64,7 @@
public static final String LIB_DIR_NAME = "lib";
public static final String LIB64_DIR_NAME = "lib64";
- // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate
- // that the cpuAbiOverride must be clear.
+ // Special value for indicating that the cpuAbiOverride must be clear.
public static final String CLEAR_ABI_OVERRIDE = "-";
/**
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 498505c..dbf4528 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -846,14 +846,6 @@
return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
}
- /**
- * Retrieves whether the current DPM allows use of the Profile Challenge.
- */
- public boolean isSeparateProfileChallengeAllowed(int userHandle) {
- return isManagedProfile(userHandle)
- && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
- }
-
private boolean hasSeparateChallenge(int userHandle) {
try {
return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 4fc135c..627381c 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -66,15 +66,15 @@
private float[] mTraceY = new float[32];
private boolean[] mTraceCurrent = new boolean[32];
private int mTraceCount;
-
+
// True if the pointer is down.
@UnsupportedAppUsage
private boolean mCurDown;
-
+
// Most recent coordinates.
private PointerCoords mCoords = new PointerCoords();
private int mToolType;
-
+
// Most recent velocity.
private float mXVelocity;
private float mYVelocity;
@@ -107,7 +107,7 @@
float[] newTraceX = new float[traceCapacity];
System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount);
mTraceX = newTraceX;
-
+
float[] newTraceY = new float[traceCapacity];
System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount);
mTraceY = newTraceY;
@@ -116,7 +116,7 @@
System.arraycopy(mTraceCurrent, 0, newTraceCurrent, 0, mTraceCount);
mTraceCurrent= newTraceCurrent;
}
-
+
mTraceX[mTraceCount] = x;
mTraceY[mTraceCount] = y;
mTraceCurrent[mTraceCount] = current;
@@ -162,7 +162,7 @@
@UnsupportedAppUsage
private boolean mPrintCoords = true;
-
+
public PointerLocationView(Context c) {
super(c);
setFocusableInTouchMode(true);
@@ -211,7 +211,7 @@
PointerState ps = new PointerState();
mPointers.add(ps);
mActivePointerId = 0;
-
+
mVelocity = VelocityTracker.obtain();
String altStrategy = SystemProperties.get(ALT_STRATEGY_PROPERY_KEY);
@@ -252,7 +252,7 @@
+ " bottom=" + mTextMetrics.bottom);
}
}
-
+
// Draw an oval. When angle is 0 radians, orients the major axis vertically,
// angles less than or greater than 0 radians rotate the major axis left or right.
private RectF mReusableOvalRect = new RectF();
@@ -399,7 +399,7 @@
}
private void drawLabels(Canvas canvas) {
- if (mActivePointerId < 0) {
+ if (mActivePointerId < 0 || mActivePointerId >= mPointers.size()) {
return;
}
@@ -614,8 +614,8 @@
NP++;
}
- if (mActivePointerId < 0 ||
- !mPointers.get(mActivePointerId).mCurDown) {
+ if (mActivePointerId < 0 || mActivePointerId >= NP
+ || !mPointers.get(mActivePointerId).mCurDown) {
mActivePointerId = id;
}
@@ -710,7 +710,7 @@
invalidate();
}
-
+
@Override
public boolean onTouchEvent(MotionEvent event) {
onPointerEvent(event);
@@ -862,16 +862,16 @@
private static final class FasterStringBuilder {
private char[] mChars;
private int mLength;
-
+
public FasterStringBuilder() {
mChars = new char[64];
}
-
+
public FasterStringBuilder clear() {
mLength = 0;
return this;
}
-
+
public FasterStringBuilder append(String value) {
final int valueLength = value.length();
final int index = reserve(valueLength);
@@ -879,11 +879,11 @@
mLength += valueLength;
return this;
}
-
+
public FasterStringBuilder append(int value) {
return append(value, 0);
}
-
+
public FasterStringBuilder append(int value, int zeroPadWidth) {
final boolean negative = value < 0;
if (negative) {
@@ -893,16 +893,16 @@
return this;
}
}
-
+
int index = reserve(11);
final char[] chars = mChars;
-
+
if (value == 0) {
chars[index++] = '0';
mLength += 1;
return this;
}
-
+
if (negative) {
chars[index++] = '-';
}
@@ -916,18 +916,18 @@
chars[index++] = '0';
}
}
-
+
do {
int digit = value / divisor;
value -= digit * divisor;
divisor /= 10;
chars[index++] = (char) (digit + '0');
} while (divisor != 0);
-
+
mLength = index;
return this;
}
-
+
public FasterStringBuilder append(float value, int precision) {
int scale = 1;
for (int i = 0; i < precision; i++) {
@@ -947,15 +947,15 @@
value -= Math.floor(value);
append((int) (value * scale), precision);
}
-
+
return this;
}
-
+
@Override
public String toString() {
return new String(mChars, 0, mLength);
}
-
+
private int reserve(int length) {
final int oldLength = mLength;
final int newLength = mLength + length;
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index 45f8c132..97097ff 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -72,6 +72,7 @@
optional bool adb_enabled = 14;
optional string kernel_state = 15;
optional string kernel_function_list = 16;
+ optional string uevent = 17;
}
message UsbAccessoryProto {
@@ -315,6 +316,7 @@
optional int32 parent_user_id = 1;
repeated UsbSettingsDevicePreferenceProto device_preferences = 2;
repeated UsbSettingsAccessoryPreferenceProto accessory_preferences = 3;
+ optional string intent = 4;
}
message UsbSettingsDevicePreferenceProto {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 29e9917..363a4b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -375,7 +375,7 @@
if (options == null) {
options = new Bundle();
}
- updateActivityOptions(options, position, wct);
+ updateActivityOptions(options, position);
break;
}
case STAGE_TYPE_MAIN: {
@@ -390,7 +390,7 @@
if (options == null) {
options = new Bundle();
}
- updateActivityOptions(options, position, wct);
+ updateActivityOptions(options, position);
break;
}
default:
@@ -491,22 +491,8 @@
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
}
- void updateActivityOptions(Bundle opts, @SplitPosition int position,
- @Nullable WindowContainerTransaction wct) {
+ void updateActivityOptions(Bundle opts, @SplitPosition int position) {
addActivityOptions(opts, position == mSideStagePosition ? mSideStage : mMainStage);
-
- if (!mMainStage.isActive()) {
- // Activate the main stage in anticipation of an app launch.
- boolean needsApply = wct == null;
- if (needsApply) {
- wct = new WindowContainerTransaction();
- }
- mMainStage.activate(getMainStageBounds(), wct);
- mSideStage.setBounds(getSideStageBounds(), wct);
- if (needsApply) {
- mTaskOrganizer.applyTransaction(wct);
- }
- }
}
void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index c09fdc2..050beb3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -31,7 +31,10 @@
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
+import org.junit.Assume.assumeFalse
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,6 +54,12 @@
private val imeApp = ImeAppHelper(instrumentation)
private val testApp = FixedAppHelper(instrumentation)
+ @Before
+ open fun setup() {
+ // Legacy split is having some issue with Shell transition, and will be deprecated soon.
+ assumeFalse(isShellTransitionsEnabled())
+ }
+
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
withTestName { testSpec.name }
diff --git a/location/java/android/location/CorrelationVector.java b/location/java/android/location/CorrelationVector.java
index 718977f..5493e25 100644
--- a/location/java/android/location/CorrelationVector.java
+++ b/location/java/android/location/CorrelationVector.java
@@ -94,8 +94,6 @@
"FrequencyOffsetMetersPerSecond must be non-negative (greater than or equal to 0)");
Preconditions.checkArgument(builder.mSamplingWidthMeters > 0.0,
"SamplingWidthMeters must be positive (greater than 0)");
- Preconditions.checkArgument(builder.mSamplingStartMeters >= 0.0,
- "SamplingStartMeters must be non-negative (greater than or equal to 0)");
mMagnitude = builder.mMagnitude;
mFrequencyOffsetMetersPerSecond = builder.mFrequencyOffsetMetersPerSecond;
mSamplingWidthMeters = builder.mSamplingWidthMeters;
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index d1c4b34..a90a38b 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -641,7 +641,7 @@
if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0) {
sp<MediaEvent> mediaEventSp =
- new MediaEvent(mFilterClient, makeFromAidl(mediaEvent.avMemory),
+ new MediaEvent(mFilterClient, dupFromAidl(mediaEvent.avMemory),
mediaEvent.avDataId, dataLength + offset, obj);
mediaEventSp->mAvHandleRefCnt++;
env->SetLongField(obj, eventContext, (jlong)mediaEventSp.get());
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index eea27ea..d4d8837 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -160,7 +160,7 @@
Result FilterClient::releaseAvHandle(native_handle_t* handle, uint64_t avDataId) {
if (mTunerFilter != nullptr) {
- Status s = mTunerFilter->releaseAvHandle(makeToAidl(handle), avDataId);
+ Status s = mTunerFilter->releaseAvHandle(dupToAidl(handle), avDataId);
return ClientHelper::getServiceSpecificErrorCode(s);
}
@@ -308,7 +308,7 @@
NativeHandle avMemory;
Status s = mTunerFilter->getAvSharedHandle(&avMemory, &size);
if (s.isOk()) {
- mAvSharedHandle = native_handle_clone(makeFromAidl(avMemory));
+ mAvSharedHandle = dupFromAidl(avMemory);
mAvSharedMemSize = size;
}
}
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
index e74ac44..fede44f 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
@@ -33,18 +33,18 @@
<style name="Banner.Title.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textSize">20sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="Banner.Subtitle.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
<style name="Banner.Summary.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
@@ -58,4 +58,4 @@
parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
index df47c64..4c6ed58 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
@@ -17,14 +17,13 @@
<resources>
<style name="Banner.Text.Title"
- parent="@android:style/TextAppearance.Material.Subhead">
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textSize">16sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="Banner.Text.Summary"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
index 92514ad..1c44207 100644
--- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -87,9 +87,9 @@
</style>
<style name="BarChart.Text"
- parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">16sp</item>
</style>
<style name="BarChart.Text.HeaderTitle">
@@ -101,7 +101,7 @@
</style>
<style name="BarChart.Text.Summary"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">12sp</item>
</style>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 2f911c4..238e65e 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -19,6 +19,7 @@
"com.google.android.material_material",
"SettingsLibSettingsTransition",
"SettingsLibUtils",
+ "SettingsLibSettingsTheme",
],
sdk_version: "system_current",
min_sdk_version: "29",
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
index 5950656..907863e 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
@@ -16,7 +16,6 @@
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content_parent"
android:layout_width="match_parent"
@@ -40,7 +39,7 @@
android:clipToPadding="false"
app:forceApplySystemWindowInsetTop="true"
app:extraMultilineHeightEnabled="true"
- app:contentScrim="?androidprv:attr/colorSurfaceHeader"
+ app:contentScrim="@color/settingslib_colorSurfaceHeader"
app:maxLines="3"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:scrimAnimationDuration="50"
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
similarity index 83%
rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
index 878275a..c20beaf 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
@@ -18,7 +18,7 @@
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
- <item name="colorPrimary">@*android:color/primary_dark_device_default_settings</item>
- <item name="colorAccent">@*android:color/accent_device_default_dark</item>
+ <item name="colorPrimary">@color/settingslib_primary_dark_device_default_settings</item>
+ <item name="colorAccent">@color/settingslib_accent_device_default_dark</item>
</style>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml
similarity index 100%
rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml
rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
similarity index 91%
rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
index 63d397c..bda51b5 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
@@ -16,7 +16,7 @@
-->
<resources>
<style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20dp</item>
</style>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
similarity index 82%
copy from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
copy to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
index 878275a..9ecc297 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
@@ -18,7 +18,7 @@
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
- <item name="colorPrimary">@*android:color/primary_dark_device_default_settings</item>
- <item name="colorAccent">@*android:color/accent_device_default_dark</item>
+ <item name="colorPrimary">@color/settingslib_primary_device_default_settings_light</item>
+ <item name="colorAccent">@color/settingslib_accent_device_default_light</item>
</style>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml
deleted file mode 100644
index 2e7a6a9..0000000
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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.
--->
-<resources>
- <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
- <item name="elevationOverlayEnabled">true</item>
- <item name="elevationOverlayColor">?attr/colorPrimary</item>
- <item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
- <item name="colorAccent">@*android:color/accent_device_default_light</item>
- </style>
-</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/res/values/styles.xml b/packages/SettingsLib/FooterPreference/res/values/styles.xml
index 08dd359..5a3bada 100644
--- a/packages/SettingsLib/FooterPreference/res/values/styles.xml
+++ b/packages/SettingsLib/FooterPreference/res/values/styles.xml
@@ -17,9 +17,8 @@
<resources>
<style name="TextAppearance.Footer.Title.SettingsLib"
- parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textSize">14sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/LayoutPreference/res/values/styles.xml b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
index 4a99e84..2ffe6d9 100644
--- a/packages/SettingsLib/LayoutPreference/res/values/styles.xml
+++ b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
@@ -24,14 +24,13 @@
</style>
<style name="TextAppearance.EntityHeaderTitle"
- parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">20sp</item>
</style>
<style name="TextAppearance.EntityHeaderSummary"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textAlignment">viewStart</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:singleLine">true</item>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_disabled.xml
similarity index 100%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_disabled.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_off.xml
similarity index 100%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_off.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_on.xml
similarity index 100%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_on.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 6e5911c..30748e6 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -50,7 +50,7 @@
android:tint="?android:attr/colorAccent"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@*android:drawable/ic_info"
+ android:src="@android:drawable/ic_info"
android:visibility="gone" />
<Switch
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
index 306145a..d0c2d0b 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -28,7 +28,7 @@
android:layout_gravity="center_vertical"
android:maxLines="2"
android:ellipsize="end"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimaryInverse"
android:layout_marginStart="@dimen/settingslib_switchbar_subsettings_margin_start"
@@ -42,7 +42,7 @@
android:theme="@android:style/Theme.Material"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@*android:drawable/ic_info"
+ android:src="@android:drawable/ic_info"
android:visibility="gone"/>
<Switch
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
new file mode 100644
index 0000000..2272a37
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources>
+
+ <!-- Size of layout margin -->
+ <dimen name="settingslib_switchbar_margin">16dp</dimen>
+
+ <!-- Size of layout margin left -->
+ <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
+
+ <!-- Size of layout margin right -->
+ <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
+
+ <!-- Minimum width of switch -->
+ <dimen name="settingslib_min_switch_width">52dp</dimen>
+
+ <!-- Minimum width of switch bar -->
+ <dimen name="settingslib_min_switch_bar_height">72dp</dimen>
+
+ <!-- Radius of switch bar -->
+ <dimen name="settingslib_switch_bar_radius">28dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
new file mode 100644
index 0000000..a50fc7c
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<resources>
+
+ <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
+ <item name="android:textSize">20sp</item>
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index 16b8af6..6362882 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2020 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.
@@ -17,30 +17,12 @@
<resources>
- <!-- Size of layout margin -->
- <dimen name="settingslib_switchbar_margin">16dp</dimen>
-
- <!-- Size of layout margin left -->
- <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
-
- <!-- Size of layout margin right -->
- <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
-
- <!-- Minimum width of switch -->
- <dimen name="settingslib_min_switch_width">52dp</dimen>
-
- <!-- Minimum width of switch bar -->
- <dimen name="settingslib_min_switch_bar_height">72dp</dimen>
-
<!-- Restricted icon size in switch bar -->
- <dimen name="settingslib_restricted_icon_size">@*android:dimen/config_restrictedIconSize</dimen>
+ <dimen name="settingslib_restricted_icon_size">@android:dimen/config_restrictedIconSize</dimen>
<!-- Restricted icon in switch bar -->
<dimen name="settingslib_restricted_icon_margin_end">16dp</dimen>
- <!-- Radius of switch bar -->
- <dimen name="settingslib_switch_bar_radius">28dp</dimen>
-
<!-- Size of title margin -->
<dimen name="settingslib_switch_title_margin">16dp</dimen>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
index 3924e30..870812a 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2020 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.
@@ -17,13 +17,6 @@
<resources>
- <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
- <item name="android:textSize">20sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@android:color/black</item>
- </style>
-
-
<style name="SwitchBar.Switch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:trackTint">@color/settingslib_switchbar_switch_track_tint</item>
<item name="android:thumbTint">@color/settingslib_switchbar_switch_thumb_tint</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
new file mode 100644
index 0000000..037b80a
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
@@ -0,0 +1,18 @@
+<?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">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 8c7c7ed..e8fd4b2 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -36,4 +36,9 @@
<color name="settingslib_dialog_colorError">#f28b82</color> <!-- Red 300 -->
<color name="settingslib_colorSurfaceVariant">@android:color/system_neutral1_700</color>
+
+ <color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_700</color>
+
+ <!-- copy from accent_primary_variant_dark_device_default-->
+ <color name="settingslib_accent_primary_variant">@android:color/system_accent1_300</color>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index 77f1bcd..0f20ec3 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -37,9 +37,30 @@
<!-- Dialog accent color -->
<color name="settingslib_dialog_accent">@android:color/system_accent1_600</color>
<!-- Dialog background color -->
- <color name="settingslib_dialog_background">@*android:color/surface_light</color>
+ <color name="settingslib_dialog_background">@color/settingslib_surface_light</color>
<!-- Dialog error color. -->
<color name="settingslib_dialog_colorError">#d93025</color> <!-- Red 600 -->
<color name="settingslib_colorSurfaceVariant">@android:color/system_neutral2_100</color>
+
+ <color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_100</color>
+
+ <color name="settingslib_accent_device_default_dark">@android:color/system_accent1_100</color>
+
+ <color name="settingslib_accent_device_default_light">@android:color/system_accent1_600</color>
+
+ <color name="settingslib_primary_dark_device_default_settings">@android:color/system_neutral1_900</color>
+
+ <color name="settingslib_primary_device_default_settings_light">@android:color/system_neutral1_50</color>
+
+ <color name="settingslib_accent_primary_device_default">@android:color/system_accent1_100</color>
+
+ <!-- copy from accent_primary_variant_light_device_default-->
+ <color name="settingslib_accent_primary_variant">@android:color/system_accent1_600</color>
+
+ <color name="settingslib_accent_secondary_device_default">@android:color/system_accent2_100</color>
+
+ <color name="settingslib_background_device_default_dark">@android:color/system_neutral1_900</color>
+
+ <color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
index ddcc83e..1c33f1a 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
@@ -19,4 +19,5 @@
<dimen name="app_preference_padding_start">20dp</dimen>
<dimen name="app_icon_min_width">52dp</dimen>
<dimen name="settingslib_preferred_minimum_touch_target">48dp</dimen>
+ <dimen name="settingslib_dialogCornerRadius">28dp</dimen>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml
new file mode 100644
index 0000000..6d072a9
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Name of a font family to use for headlines in SettingsLib. -->
+ <string name="settingslib_config_headlineFontFamily" translatable="false">
+ @*android:string/config_headlineFontFamily
+ </string>
+
+ <!-- Name of a font family to use for headlines-medium in SettingsLib. -->
+ <string name="settingslib_config_headlineFontFamilyMedium" translatable="false">
+ @*android:string/config_headlineFontFamilyMedium
+ </string>
+
+ <!-- Name of a font family to use for body in SettingsLib. -->
+ <string name="settingslib_config_bodyFontFamily" translatable="false">
+ @*android:string/config_bodyFontFamily
+ </string>
+
+ <!-- Name of a font family to use for body-medium in SettingsLib. -->
+ <string name="settingslib_config_bodyFontFamilyMedium" translatable="false">
+ @*android:string/config_bodyFontFamilyMedium
+ </string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 46f1e03..5800636 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -16,12 +16,16 @@
-->
<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.ListItem">
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
<style name="TextAppearance.CategoryTitle.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.Body2" />
+ parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">14sp</item>
+ </style>
<style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:switchMinWidth">52dp</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index 8034710..6bf288b 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -50,6 +50,6 @@
<item name="android:clipToPadding">true</item>
<item name="android:clipChildren">true</item>
- <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+ <item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
</style>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
index 25f9514..18af1f9 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
@@ -20,4 +20,5 @@
<dimen name="app_preference_padding_start">?android:attr/listPreferredItemPaddingStart</dimen>
<dimen name="app_icon_min_width">56dp</dimen>
<dimen name="two_target_min_width">72dp</dimen>
+ <dimen name="settingslib_dialogCornerRadius">8dp</dimen>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/themes.xml b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
index 6f25177..2d881d1 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
@@ -35,7 +35,7 @@
<!-- TODO(b/189308264): fix the crash in Android R if set the attributes:
<item name="colorAccent">@*android:color/accent_device_default_light</item>
<item name="android:colorBackground">@color/settingslib_dialog_background</item>
- <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+ <item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
-->
<item name="android:windowSoftInputMode">adjustResize</item>
<item name="android:clipToPadding">true</item>
diff --git a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
index 65869b5..b6ca41f 100644
--- a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
+++ b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
@@ -16,8 +16,7 @@
-->
<resources>
<style name="TextAppearance.TopIntroText"
- parent="@*android:style/TextAppearance.DeviceDefault">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 183a06c..cab7cee 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -20,68 +20,68 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Toast message when Wi-Fi cannot scan for networks -->
<string name="wifi_fail_to_scan">Can\'t scan for networks</string>
- <!-- Concise terminology for wifi with WEP security -->
- <string name="wifi_security_short_wep" translatable="false">WEP</string>
- <!-- Concise terminology for wifi with WPA security -->
- <string name="wifi_security_short_wpa" translatable="false">WPA</string>
- <!-- Concise terminology for wifi with WPA2 security -->
- <string name="wifi_security_short_wpa2" translatable="false">WPA2</string>
- <!-- Concise terminology for wifi with both WPA/WPA2 security -->
- <string name="wifi_security_short_wpa_wpa2" translatable="false">WPA/WPA2</string>
+ <!-- Concise terminology for wifi with WEP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_wep">WEP</string>
+ <!-- Concise terminology for wifi with WPA security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_wpa">WPA</string>
+ <!-- Concise terminology for wifi with WPA2 security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_wpa2">WPA2</string>
+ <!-- Concise terminology for wifi with both WPA/WPA2 security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
<!-- Concise terminology for wifi with unknown PSK type -->
<string name="wifi_security_short_psk_generic" translatable="false">@string/wifi_security_short_wpa_wpa2</string>
- <!-- Concise terminology for wifi with 802.1x EAP security -->
- <string name="wifi_security_short_eap" translatable="false">802.1x</string>
- <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
- <string name="wifi_security_short_eap_wpa" translatable="false">WPA-EAP</string>
- <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
- <string name="wifi_security_short_eap_wpa2_wpa3" translatable="false">RSN-EAP</string>
- <!-- Concise terminology for wifi with WPA3 security -->
- <string name="wifi_security_short_sae" translatable="false">WPA3</string>
- <!-- Concise terminology for wifi with WPA2/WPA3 transition security -->
- <string name="wifi_security_short_psk_sae" translatable="false">WPA2/WPA3</string>
- <!-- Concise terminology for Wi-Fi with None/OWE transition mode security -->
- <string name="wifi_security_short_none_owe" translatable="false">None/OWE</string>
- <!-- Concise terminology for wifi with OWE security -->
- <string name="wifi_security_short_owe" translatable="false">OWE</string>
- <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
- <string name="wifi_security_short_eap_suiteb" translatable="false">Suite-B-192</string>
+ <!-- Concise terminology for wifi with 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_eap">802.1x</string>
+ <!-- Concise terminology for wifi with WPA 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_eap_wpa">WPA-EAP</string>
+ <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_eap_wpa2_wpa3">RSN-EAP</string>
+ <!-- Concise terminology for wifi with WPA3 security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_sae">WPA3</string>
+ <!-- Concise terminology for wifi with WPA2/WPA3 transition security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_psk_sae">WPA2/WPA3</string>
+ <!-- Concise terminology for Wi-Fi with None/OWE transition mode security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_none_owe">None/OWE</string>
+ <!-- Concise terminology for wifi with OWE security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_owe">OWE</string>
+ <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security [CHAR LIMIT=40] -->
+ <string name="wifi_security_short_eap_suiteb">Suite-B-192</string>
<!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. [CHAR LIMIT=40] -->
<string name="wifi_security_none">None</string>
- <!-- Terminology for wifi with WEP security -->
- <string name="wifi_security_wep" translatable="false">WEP</string>
- <!-- Terminology for wifi with WPA security -->
- <string name="wifi_security_wpa" translatable="false">WPA-Personal</string>
- <!-- Terminology for wifi with WPA2 security -->
- <string name="wifi_security_wpa2" translatable="false">WPA2-Personal</string>
- <!-- Terminology for wifi with both WPA/WPA2 security, or unknown -->
- <string name="wifi_security_wpa_wpa2" translatable="false">WPA/WPA2-Personal</string>
+ <!-- Terminology for wifi with WEP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_wep">WEP</string>
+ <!-- Terminology for wifi with WPA security [CHAR LIMIT=40] -->
+ <string name="wifi_security_wpa">WPA-Personal</string>
+ <!-- Terminology for wifi with WPA2 security [CHAR LIMIT=40] -->
+ <string name="wifi_security_wpa2">WPA2-Personal</string>
+ <!-- Terminology for wifi with both WPA/WPA2 security, or unknown [CHAR LIMIT=40] -->
+ <string name="wifi_security_wpa_wpa2">WPA/WPA2-Personal</string>
<!-- Terminology for wifi with unknown PSK type -->
<string name="wifi_security_psk_generic" translatable="false">@string/wifi_security_wpa_wpa2</string>
- <!-- Concise terminology for wifi with 802.1x EAP security -->
- <string name="wifi_security_eap" translatable="false">WPA/WPA2/WPA3-Enterprise</string>
- <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
- <string name="wifi_security_eap_wpa" translatable="false">WPA-Enterprise</string>
- <!-- Concise terminology for wifi with 802.1x EAP security -->
- <string name="wifi_security_eap_wpa_wpa2" translatable="false">WPA/WPA2-Enterprise</string>
- <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
- <string name="wifi_security_eap_wpa2_wpa3" translatable="false">WPA2/WPA3-Enterprise</string>
- <!-- Concise terminology for wifi with WPA3 802.1x EAP security -->
- <string name="wifi_security_eap_wpa3" translatable="false">WPA3-Enterprise</string>
- <!-- Concise terminology for Passpoint network -->
- <string name="wifi_security_passpoint" translatable="false">Passpoint</string>
- <!-- Terminology for wifi with WPA3 security -->
- <string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
- <!-- Terminology for wifi with WPA2/WPA3 Transition mode security -->
- <string name="wifi_security_psk_sae" translatable="false">WPA2/WPA3-Personal</string>
- <!-- Terminology for Wi-Fi with None/OWE transition mode security -->
- <string name="wifi_security_none_owe" translatable="false">None/Enhanced Open</string>
- <!-- Terminology for wifi with OWE security -->
- <string name="wifi_security_owe" translatable="false">Enhanced Open</string>
- <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
- <string name="wifi_security_eap_suiteb" translatable="false">WPA3-Enterprise 192-bit</string>
+ <!-- Concise terminology for wifi with 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_eap">WPA/WPA2/WPA3-Enterprise</string>
+ <!-- Concise terminology for wifi with WPA 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_eap_wpa">WPA-Enterprise</string>
+ <!-- Concise terminology for wifi with 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_eap_wpa_wpa2">WPA/WPA2-Enterprise</string>
+ <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_eap_wpa2_wpa3">WPA2/WPA3-Enterprise</string>
+ <!-- Concise terminology for wifi with WPA3 802.1x EAP security [CHAR LIMIT=40] -->
+ <string name="wifi_security_eap_wpa3">WPA3-Enterprise</string>
+ <!-- Concise terminology for Passpoint network [CHAR LIMIT=40] -->
+ <string name="wifi_security_passpoint">Passpoint</string>
+ <!-- Terminology for wifi with WPA3 security [CHAR LIMIT=40] -->
+ <string name="wifi_security_sae">WPA3-Personal</string>
+ <!-- Terminology for wifi with WPA2/WPA3 Transition mode security [CHAR LIMIT=40] -->
+ <string name="wifi_security_psk_sae">WPA2/WPA3-Personal</string>
+ <!-- Terminology for Wi-Fi with None/OWE transition mode security [CHAR LIMIT=40] -->
+ <string name="wifi_security_none_owe">None/Enhanced Open</string>
+ <!-- Terminology for wifi with OWE security [CHAR LIMIT=40] -->
+ <string name="wifi_security_owe">Enhanced Open</string>
+ <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security [CHAR LIMIT=40] -->
+ <string name="wifi_security_eap_suiteb">WPA3-Enterprise 192-bit</string>
<!-- Summary for the remembered network. -->
<string name="wifi_remembered">Saved</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
index 364698f..2c0162f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
@@ -68,7 +68,6 @@
Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component);
final Intent intent = new Intent(ACTION_LEARN_MORE)
.putExtra(EXTRA_SETTING_KEY, EXTRA_SETTING_VALUE)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setPackage(enforcedAdmin.component.getPackageName());
context.startActivity(intent);
};
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index fe48575..3ff1e48 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -317,6 +317,8 @@
NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.BURN_IN_PROTECTION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.COMBINED_LOCATION_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.WRIST_ORIENTATION_MODE,
+ new DiscreteValueValidator(new String[] {"0", "1", "2", "3"}));
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index b210062..4f27de1 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -272,6 +272,7 @@
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
+ Settings.Global.ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT,
Settings.Global.ENABLE_MULTI_SLOT_TIMEOUT_MILLIS,
Settings.Global.ENHANCED_4G_MODE_ENABLED,
@@ -665,7 +666,8 @@
Settings.Global.Wearable.MASTER_GESTURES_ENABLED,
Settings.Global.Wearable.UNGAZE_ENABLED,
Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
- Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED);
+ Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED,
+ Settings.Global.Wearable.WRIST_ORIENTATION_MODE);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index ea769c6..871b1c4 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -62,8 +62,8 @@
<item name="android:src">@drawable/ic_backspace_24dp</item>
</style>
<style name="NumPadKey.Enter">
- <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
- <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
+ <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
+ <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
</style>
<style name="Widget.TextView.NumPadKey.Klondike"
parent="@android:style/Widget.DeviceDefault.TextView">
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 5b58fe8..3aa2e5a 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -191,6 +191,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
+ android:id="@+id/wifi_toggle_title"
android:text="@string/turn_on_wifi"
android:textDirection="locale"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a4c1d94..38af659 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -69,6 +69,9 @@
<!-- Shadows under the clock, date and other keyguard text fields -->
<color name="keyguard_shadow_color">#B2000000</color>
+ <!-- Color for the images in keyguard number pad buttons -->
+ <color name="keyguard_keypad_image_color">@android:color/background_light</color>
+
<!-- Color for rounded background for activated user in keyguard user switcher -->
<color name="kg_user_switcher_activated_background_color">#26000000</color>
<!-- Icon color for user avatars in keyguard user switcher -->
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 509ac8a..aa8cbd7 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -46,6 +46,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.biometrics.UdfpsController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
@@ -99,6 +100,7 @@
@NonNull private CharSequence mUnlockedLabel;
@NonNull private CharSequence mLockedLabel;
@Nullable private final Vibrator mVibrator;
+ @Nullable private final AuthRippleController mAuthRippleController;
private boolean mIsDozing;
private boolean mIsBouncerShowing;
@@ -135,7 +137,8 @@
@NonNull AccessibilityManager accessibilityManager,
@NonNull ConfigurationController configurationController,
@NonNull @Main DelayableExecutor executor,
- @Nullable Vibrator vibrator
+ @Nullable Vibrator vibrator,
+ @Nullable AuthRippleController authRippleController
) {
super(view);
mStatusBarStateController = statusBarStateController;
@@ -148,6 +151,7 @@
mConfigurationController = configurationController;
mExecutor = executor;
mVibrator = vibrator;
+ mAuthRippleController = authRippleController;
final Context context = view.getContext();
mUnlockIcon = mView.getContext().getResources().getDrawable(
@@ -538,6 +542,9 @@
// pre-emptively set to true to hide view
mIsBouncerShowing = true;
+ if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
+ mAuthRippleController.showRipple(FINGERPRINT);
+ }
updateVisibility();
mKeyguardViewController.showBouncer(/* scrim */ true);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 99f9558..c659bf7 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -26,7 +26,7 @@
import androidx.annotation.Nullable;
-import com.android.settingslib.Utils;
+import com.android.systemui.R;
/**
* Similar to the {@link NumPadKey}, but displays an image.
@@ -92,8 +92,7 @@
public void reloadColors() {
if (mAnimator != null) mAnimator.reloadColors(getContext());
- int textColor = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.colorBackground);
- ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(textColor));
+ int imageColor = getContext().getColor(R.color.keyguard_keypad_image_color);
+ ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
index 81a13a2..4082015 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java
@@ -57,7 +57,9 @@
public void run() {
mView.removeCallbacks(this);
mView.show(false /* show */, true /* animate */, () -> {
- mWindowManager.removeView(mView);
+ if (mView.isAttachedToWindow()) {
+ mWindowManager.removeView(mView);
+ }
});
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 4664423..b7e2982 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -107,12 +107,6 @@
@Override
protected void onViewDetached() {
- destroy();
- }
-
- @Override
- public void destroy() {
- super.destroy();
mConfigurationController.removeCallback(mConfigurationListener);
unsubscribeFromTunerUpdates();
mCurrentUserTracker.stopTracking();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 1df8ad5..66b45e5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -79,7 +79,7 @@
notificationShadeWindowController.setForcePluginOpen(false, this)
}
- private fun showRipple(biometricSourceType: BiometricSourceType?) {
+ fun showRipple(biometricSourceType: BiometricSourceType?) {
if (!keyguardUpdateMonitor.isKeyguardVisible ||
keyguardUpdateMonitor.userNeedsStrongAuth()) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index bfa4780..5b327bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -34,7 +34,7 @@
* See [DumpHandler] for more information on how and when this information is dumped.
*/
@SysUISingleton
-class DumpManager @Inject constructor() {
+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/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
index 28f63b0..6561bd5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
@@ -25,8 +25,12 @@
* Proxy to make {@link SystemProperties} easily testable.
*/
@SysUISingleton
-class SystemPropertiesHelper @Inject constructor() {
+open class SystemPropertiesHelper @Inject constructor() {
fun getBoolean(name: String, default: Boolean): Boolean {
return SystemProperties.getBoolean(name, default)
}
+
+ fun set(name: String, value: Int) {
+ SystemProperties.set(name, value.toString())
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index e1e0ba7..8a3f983 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -111,6 +111,7 @@
private LinearLayout mMobileNetworkLayout;
private LinearLayout mMobileNetworkList;
private LinearLayout mTurnWifiOnLayout;
+ private TextView mWifiToggleTitleText;
private LinearLayout mSeeAllLayout;
private RecyclerView mWifiRecyclerView;
private ImageView mConnectedWifiIcon;
@@ -215,6 +216,7 @@
mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list);
mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+ mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list);
mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
@@ -368,6 +370,12 @@
private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
mWiFiToggle.setChecked(isWifiEnabled);
+ if (isDeviceLocked && mInternetDialogController.isNightMode()) {
+ int titleColor = mConnectedWifiEntry != null ? mContext.getColor(
+ R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+ mContext, android.R.attr.textColorPrimary);
+ mWifiToggleTitleText.setTextColor(titleColor);
+ }
mTurnWifiOnLayout.setBackground(
(isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
index 4a467ce..d01fc93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
@@ -104,7 +104,7 @@
// the active effect area. Values here should be kept in sync with the
// animation implementation in the ripple shader.
val maskRadius = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) *
- (1 - rippleShader.progress)) * radius * 1.5f
+ (1 - rippleShader.progress)) * radius * 2
canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 8770e86..796df55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -159,17 +159,6 @@
@Override
protected void onViewDetached() {
- destroy();
- }
-
- @Override
- public void destroy() {
- // Don't receive future #onViewAttached calls so that we don't accidentally have two
- // controllers registered for the same view.
- // TODO(b/194181195): This shouldn't be necessary.
- super.destroy();
- mBatteryMeterViewController.destroy();
-
mConfigurationController.removeCallback(mConfigurationListener);
mAnimationScheduler.removeCallback(mAnimationCallback);
mUserInfoController.removeCallback(mOnUserInfoChangedListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 50db240..ee242f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -928,10 +928,14 @@
}
}
+ mKeyguardStatusBarViewController =
+ mKeyguardStatusBarViewComponentFactory.build(mKeyguardStatusBar)
+ .getKeyguardStatusBarViewController();
+ mKeyguardStatusBarViewController.init();
+
updateViewControllers(
mView.findViewById(R.id.keyguard_status_view),
userAvatarView,
- mKeyguardStatusBar,
keyguardUserSwitcherView,
mCommunalView,
mView.findViewById(R.id.idle_host_view));
@@ -1025,7 +1029,6 @@
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
UserAvatarView userAvatarView,
- KeyguardStatusBarView keyguardStatusBarView,
KeyguardUserSwitcherView keyguardUserSwitcherView,
CommunalHostView communalView,
IdleHostView idleHostView) {
@@ -1039,16 +1042,6 @@
mIdleHostViewController = idleViewComponent.getIdleHostViewController();
mIdleHostViewController.init();
- KeyguardStatusBarViewComponent statusBarViewComponent =
- mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView);
- if (mKeyguardStatusBarViewController != null) {
- // TODO(b/194181195): This shouldn't be necessary.
- mKeyguardStatusBarViewController.destroy();
- }
- mKeyguardStatusBarViewController =
- statusBarViewComponent.getKeyguardStatusBarViewController();
- mKeyguardStatusBarViewController.init();
-
if (communalView != null) {
CommunalViewComponent communalViewComponent =
mCommunalViewComponentFactory.build(communalView);
@@ -1217,7 +1210,7 @@
mBigClockContainer.removeAllViews();
updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
- mKeyguardStatusBar, keyguardUserSwitcherView, mCommunalView,
+ keyguardUserSwitcherView, mCommunalView,
mView.findViewById(R.id.idle_host_view));
// Update keyguard bottom area
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index cfd82f5..377a7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -535,6 +535,10 @@
mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
managedProfiles);
}
+ onOverlaysApplied();
+ }
+
+ protected void onOverlaysApplied() {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 32bbe1c..0dd5788 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -110,16 +110,6 @@
}
/**
- * Destroys this controller so that it never receives view attach and detach events again.
- * Does nothing if the view is null.
- */
- public void destroy() {
- if (mView != null) {
- mView.removeOnAttachStateChangeListener(mOnAttachStateListener);
- }
- }
-
- /**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
protected abstract void onViewAttached();
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index d5ea5bf..3a03573 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -1021,7 +1021,15 @@
}
}
- return upgradeAndInit(version, map);
+ try {
+ return upgradeAndInit(version, map);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Failed to upgrade and set sensor privacy state,"
+ + " resetting to default.", e);
+ mEnabled = new SparseBooleanArray();
+ mIndividualEnabled = new SparseArray<>();
+ return true;
+ }
}
private boolean upgradeAndInit(int version, SparseArray map) {
@@ -1037,22 +1045,22 @@
final int[] users = getLocalService(UserManagerInternal.class).getUserIds();
if (version == 0) {
final boolean enabled = (boolean) map.get(VER0_ENABLED);
- final SparseBooleanArray individualEnabled =
- (SparseBooleanArray) map.get(VER0_INDIVIDUAL_ENABLED);
+ final SparseArray<SensorState> individualEnabled =
+ (SparseArray<SensorState>) map.get(VER0_INDIVIDUAL_ENABLED);
final SparseBooleanArray perUserEnabled = new SparseBooleanArray();
- final SparseArray<SparseBooleanArray> perUserIndividualEnabled =
+ final SparseArray<SparseArray<SensorState>> perUserIndividualEnabled =
new SparseArray<>();
// Copy global state to each user
for (int i = 0; i < users.length; i++) {
int user = users[i];
perUserEnabled.put(user, enabled);
- SparseBooleanArray userIndividualSensorEnabled = new SparseBooleanArray();
+ SparseArray<SensorState> userIndividualSensorEnabled = new SparseArray<>();
perUserIndividualEnabled.put(user, userIndividualSensorEnabled);
for (int j = 0; j < individualEnabled.size(); j++) {
final int sensor = individualEnabled.keyAt(j);
- final boolean isSensorEnabled = individualEnabled.valueAt(j);
+ final SensorState isSensorEnabled = individualEnabled.valueAt(j);
userIndividualSensorEnabled.put(sensor, isSensorEnabled);
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2483fb8..317775f2 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -6567,10 +6567,17 @@
final String msg = "Background started FGS: "
+ ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
+ r.mInfoAllowStartForeground;
- Slog.wtfQuiet(TAG, msg);
if (r.mAllowStartForeground != REASON_DENIED) {
+ if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
+ mAm.mConstants.mFgsStartAllowedLogSampleRate)) {
+ Slog.wtfQuiet(TAG, msg);
+ }
Slog.i(TAG, msg);
} else {
+ if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
+ mAm.mConstants.mFgsStartDeniedLogSampleRate)) {
+ Slog.wtfQuiet(TAG, msg);
+ }
Slog.w(TAG, msg);
}
r.mLoggedInfoAllowStartForeground = true;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index eb37e2d..9a755da 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -112,6 +112,8 @@
static final String KEY_FG_TO_BG_FGS_GRACE_DURATION = "fg_to_bg_fgs_grace_duration";
static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate";
+ static final String KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE = "fgs_start_allowed_log_sample_rate";
+ static final String KEY_FGS_START_DENIED_LOG_SAMPLE_RATE = "fgs_start_denied_log_sample_rate";
static final String KEY_FGS_ALLOW_OPT_OUT = "fgs_allow_opt_out";
static final String KEY_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE =
"extra_delay_svc_restart_mem_pressure";
@@ -160,6 +162,8 @@
private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000;
private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
+ private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
+ private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%
/**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
@@ -523,6 +527,20 @@
volatile float mFgsAtomSampleRate = DEFAULT_FGS_ATOM_SAMPLE_RATE;
/**
+ * Sample rate for the allowed FGS start WTF logs.
+ *
+ * If the value is 0.1, 10% of the logs would be sampled.
+ */
+ volatile float mFgsStartAllowedLogSampleRate = DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE;
+
+ /**
+ * Sample rate for the denied FGS start WTF logs.
+ *
+ * If the value is 0.1, 10% of the logs would be sampled.
+ */
+ volatile float mFgsStartDeniedLogSampleRate = DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE;
+
+ /**
* Whether to allow "opt-out" from the foreground service restrictions.
* (https://developer.android.com/about/versions/12/foreground-services)
*/
@@ -752,6 +770,12 @@
case KEY_FGS_ATOM_SAMPLE_RATE:
updateFgsAtomSamplePercent();
break;
+ case KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE:
+ updateFgsStartAllowedLogSamplePercent();
+ break;
+ case KEY_FGS_START_DENIED_LOG_SAMPLE_RATE:
+ updateFgsStartDeniedLogSamplePercent();
+ break;
case KEY_FGS_ALLOW_OPT_OUT:
updateFgsAllowOptOut();
break;
@@ -1104,6 +1128,20 @@
DEFAULT_FGS_ATOM_SAMPLE_RATE);
}
+ private void updateFgsStartAllowedLogSamplePercent() {
+ mFgsStartAllowedLogSampleRate = DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE,
+ DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE);
+ }
+
+ private void updateFgsStartDeniedLogSamplePercent() {
+ mFgsStartDeniedLogSampleRate = DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_START_DENIED_LOG_SAMPLE_RATE,
+ DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE);
+ }
+
private void updateFgsAllowOptOut() {
mFgsAllowOptOut = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1377,6 +1415,10 @@
pw.print("="); pw.println(mFgsStartRestrictionCheckCallerTargetSdk);
pw.print(" "); pw.print(KEY_FGS_ATOM_SAMPLE_RATE);
pw.print("="); pw.println(mFgsAtomSampleRate);
+ pw.print(" "); pw.print(KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE);
+ pw.print("="); pw.println(mFgsStartAllowedLogSampleRate);
+ pw.print(" "); pw.print(KEY_FGS_START_DENIED_LOG_SAMPLE_RATE);
+ pw.print("="); pw.println(mFgsStartDeniedLogSampleRate);
pw.print(" "); pw.print(KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR);
pw.print("="); pw.println(mPushMessagingOverQuotaBehavior);
pw.print(" "); pw.print(KEY_FGS_ALLOW_OPT_OUT);
diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
index afe6bb2..d0ca9d84 100644
--- a/services/core/java/com/android/server/pm/PackageInstalledInfo.java
+++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
@@ -18,7 +18,6 @@
import static com.android.server.pm.PackageManagerService.TAG;
-import android.content.pm.PackageParser;
import android.util.ExceptionUtils;
import android.util.Slog;
@@ -59,12 +58,6 @@
Slog.w(TAG, msg);
}
- public void setError(String msg, PackageParser.PackageParserException e) {
- setReturnCode(e.error);
- setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
- Slog.w(TAG, msg, e);
- }
-
public void setError(String msg, PackageManagerException e) {
mReturnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index fe419a6..b34a3a2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -261,6 +261,10 @@
new Lifecycle(context, this));
}
+ StagingManager getStagingManager() {
+ return mStagingManager;
+ }
+
boolean okToSendBroadcasts() {
return mOkToSendBroadcasts;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d2c15ab..94306ce 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -163,6 +163,7 @@
import android.content.pm.IPackageManagerNative;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
@@ -202,6 +203,7 @@
import android.content.pm.SigningDetails;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
import android.content.pm.SigningInfo;
+import android.content.pm.StagedApexInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
@@ -23074,6 +23076,29 @@
public boolean hasSystemFeature(String featureName, int version) {
return PackageManagerService.this.hasSystemFeature(featureName, version);
}
+
+ @Override
+ public void registerStagedApexObserver(IStagedApexObserver observer) {
+ mInstallerService.getStagingManager().registerStagedApexObserver(observer);
+ }
+
+ @Override
+ public void unregisterStagedApexObserver(IStagedApexObserver observer) {
+ mInstallerService.getStagingManager().unregisterStagedApexObserver(observer);
+ }
+
+ @Override
+ public String[] getStagedApexModuleNames() {
+ return mInstallerService.getStagingManager()
+ .getStagedApexModuleNames().toArray(new String[0]);
+ }
+
+ @Override
+ @Nullable
+ public StagedApexInfo getStagedApexInfo(String moduleName) {
+ return mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
+ }
+
}
private AndroidPackage getPackage(String packageName) {
@@ -25049,5 +25074,3 @@
}
}
}
-
-
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9dcae3d..4dfb6b8 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
@@ -28,6 +29,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.ApexStagedEvent;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
@@ -36,6 +39,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
+import android.content.pm.StagedApexInfo;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
@@ -52,6 +56,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
@@ -80,7 +85,9 @@
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
@@ -99,7 +106,8 @@
private final ApexManager mApexManager;
private final PowerManager mPowerManager;
private final Context mContext;
- private final PreRebootVerificationHandler mPreRebootVerificationHandler;
+ @VisibleForTesting
+ final PreRebootVerificationHandler mPreRebootVerificationHandler;
private final Supplier<PackageParser2> mPackageParserSupplier;
private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
@@ -115,6 +123,9 @@
@GuardedBy("mSuccessfulStagedSessionIds")
private final List<Integer> mSuccessfulStagedSessionIds = new ArrayList<>();
+ @GuardedBy("mStagedApexObservers")
+ private final List<IStagedApexObserver> mStagedApexObservers = new ArrayList<>();
+
private final CompletableFuture<Void> mBootCompleted = new CompletableFuture<>();
interface StagedSession {
@@ -204,6 +215,35 @@
mApexManager.markBootCompleted();
}
+ void registerStagedApexObserver(IStagedApexObserver observer) {
+ if (observer == null) {
+ return;
+ }
+ if (observer.asBinder() != null) {
+ try {
+ observer.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mStagedApexObservers) {
+ mStagedApexObservers.remove(observer);
+ }
+ }
+ }, 0);
+ } catch (RemoteException re) {
+ Slog.w(TAG, re.getMessage());
+ }
+ }
+ synchronized (mStagedApexObservers) {
+ mStagedApexObservers.add(observer);
+ }
+ }
+
+ void unregisterStagedApexObserver(IStagedApexObserver observer) {
+ synchronized (mStagedApexObservers) {
+ mStagedApexObservers.remove(observer);
+ }
+ }
+
/**
* Validates the signature used to sign the container of the new apex package
*
@@ -808,6 +848,9 @@
// Also, cleaning up the stageDir prevents the apex from being activated.
Slog.e(TAG, "Failed to abort apex session " + session.sessionId());
}
+ if (session.containsApexSession()) {
+ notifyStagedApexObservers();
+ }
}
// Session was successfully aborted from apexd (if required) and pre-reboot verification
@@ -1093,7 +1136,107 @@
return session;
}
- private final class PreRebootVerificationHandler extends Handler {
+ /**
+ * Returns ApexInfo about APEX contained inside the session as a {@code Map<String, ApexInfo>},
+ * where the key of the map is the module name of the ApexInfo.
+ *
+ * Returns an empty map if there is any error.
+ */
+ @VisibleForTesting
+ @NonNull
+ Map<String, ApexInfo> getStagedApexInfos(@NonNull StagedSession session) {
+ Preconditions.checkArgument(session != null, "Session is null");
+ Preconditions.checkArgument(!session.hasParentSessionId(),
+ session.sessionId() + " session has parent session");
+ Preconditions.checkArgument(session.containsApexSession(),
+ session.sessionId() + " session does not contain apex");
+
+ // Even if caller calls this method on ready session, the session could be abandoned
+ // right after this method is called.
+ if (!session.isSessionReady() || session.isDestroyed()) {
+ return Collections.emptyMap();
+ }
+
+ ApexSessionParams params = new ApexSessionParams();
+ params.sessionId = session.sessionId();
+ final IntArray childSessionIds = new IntArray();
+ if (session.isMultiPackage()) {
+ for (StagedSession s : session.getChildSessions()) {
+ if (s.isApexSession()) {
+ childSessionIds.add(s.sessionId());
+ }
+ }
+ }
+ params.childSessionIds = childSessionIds.toArray();
+
+ ApexInfo[] infos = mApexManager.getStagedApexInfos(params);
+ Map<String, ApexInfo> result = new ArrayMap<>();
+ for (ApexInfo info : infos) {
+ result.put(info.moduleName, info);
+ }
+ return result;
+ }
+
+ /**
+ * Returns apex module names of all packages that are staged ready
+ */
+ List<String> getStagedApexModuleNames() {
+ List<String> result = new ArrayList<>();
+ synchronized (mStagedSessions) {
+ for (int i = 0; i < mStagedSessions.size(); i++) {
+ final StagedSession session = mStagedSessions.valueAt(i);
+ if (!session.isSessionReady() || session.isDestroyed()
+ || session.hasParentSessionId() || !session.containsApexSession()) {
+ continue;
+ }
+ result.addAll(getStagedApexInfos(session).keySet());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns ApexInfo of the {@code moduleInfo} provided if it is staged, otherwise returns null.
+ */
+ @Nullable
+ StagedApexInfo getStagedApexInfo(String moduleName) {
+ synchronized (mStagedSessions) {
+ for (int i = 0; i < mStagedSessions.size(); i++) {
+ final StagedSession session = mStagedSessions.valueAt(i);
+ if (!session.isSessionReady() || session.isDestroyed()
+ || session.hasParentSessionId() || !session.containsApexSession()) {
+ continue;
+ }
+ ApexInfo ai = getStagedApexInfos(session).get(moduleName);
+ if (ai != null) {
+ StagedApexInfo info = new StagedApexInfo();
+ info.moduleName = ai.moduleName;
+ info.diskImagePath = ai.modulePath;
+ info.versionCode = ai.versionCode;
+ info.versionName = ai.versionName;
+ return info;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void notifyStagedApexObservers() {
+ synchronized (mStagedApexObservers) {
+ for (IStagedApexObserver observer : mStagedApexObservers) {
+ ApexStagedEvent event = new ApexStagedEvent();
+ event.stagedApexModuleNames = getStagedApexModuleNames().toArray(new String[0]);
+ try {
+ observer.onApexStaged(event);
+ } catch (RemoteException re) {
+ Slog.w(TAG, "Failed to contact the observer " + re.getMessage());
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ final class PreRebootVerificationHandler extends Handler {
PreRebootVerificationHandler(Looper looper) {
super(looper);
@@ -1114,7 +1257,8 @@
*/
private static final int MSG_PRE_REBOOT_VERIFICATION_START = 1;
private static final int MSG_PRE_REBOOT_VERIFICATION_APEX = 2;
- private static final int MSG_PRE_REBOOT_VERIFICATION_END = 3;
+ @VisibleForTesting
+ static final int MSG_PRE_REBOOT_VERIFICATION_END = 3;
@Override
public void handleMessage(Message msg) {
@@ -1314,6 +1458,7 @@
if (hasApex) {
try {
mApexManager.markStagedSessionReady(session.sessionId());
+ notifyStagedApexObservers();
} catch (PackageManagerException e) {
session.setSessionFailed(e.error, e.getMessage());
return;
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 8a8a302..4334bf6 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -21,7 +21,7 @@
import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsingPackage;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -82,7 +82,7 @@
boolean hasClass = false;
String className = "android.content.pm.AndroidTestBaseUpdater";
try {
- Class clazz = (PackageParser.class.getClassLoader().loadClass(className));
+ Class clazz = ParsingPackage.class.getClassLoader().loadClass(className);
hasClass = clazz != null;
Log.i(TAG, "Loaded " + className);
} catch (ClassNotFoundException e) {
diff --git a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
index bdcd2cd..3524d7f 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
@@ -44,8 +44,8 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ScreenState {}
- private @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
- private Long mLastChanged = null;
+ private volatile @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
+ private volatile Long mLastChanged = null;
private static final int LOG_SUBTYPE_UNFOLDED = 0;
private static final int LOG_SUBTYPE_FOLDED = 1;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 75b66b3..2ac87a3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2798,9 +2798,11 @@
mInputManagerInternal.toggleCapsLock(event.getDeviceId());
mPendingCapsLockToggle = false;
} else if (mPendingMetaAction) {
- launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
- event.getDeviceId(),
- event.getEventTime(), AssistUtils.INVOCATION_TYPE_UNKNOWN);
+ if (!canceled) {
+ launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
+ event.getDeviceId(),
+ event.getEventTime(), AssistUtils.INVOCATION_TYPE_UNKNOWN);
+ }
mPendingMetaAction = false;
}
}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 2a95416..06253a0 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -124,12 +124,8 @@
@Override
public void read(InputStream in) throws IOException {
while (in.available() > 0) {
- try {
- DataElement dataElement = new DataElement(in);
- mCallback.onReadDataElement(dataElement.getData());
- } catch (IOException e) {
- Slog.e(TAG, "Failed to read from storage. " + e.getMessage());
- }
+ DataElement dataElement = new DataElement(in);
+ mCallback.onReadDataElement(dataElement.getData());
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3a5d771..ed2c3b6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8644,8 +8644,9 @@
if (imeTargetWindowTask == null) {
return false;
}
- final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId,
- false /* isLowResolution */);
+ final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId,
+ imeTargetWindowTask.mUserId, false /* isLowResolution */,
+ false /* restoreFromDisk */);
return snapshot != null && snapshot.hasImeSurface();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 65b065a..620c287 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -945,7 +945,7 @@
final int displayId = r.getDisplayId();
final Context c = root.getDisplayUiContext(displayId);
- if (r.mVisibleRequested && !displayContexts.contains(c)) {
+ if (c != null && r.mVisibleRequested && !displayContexts.contains(c)) {
displayContexts.add(c);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6a25965..e38d8dc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3804,17 +3804,6 @@
}
}
- @Override
- public boolean isSeparateProfileChallengeAllowed(int userHandle) {
- Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()),
- String.format(NOT_SYSTEM_CALLER_MSG, "query separate challenge support"));
-
- ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
- // Profile challenge is supported on N or newer release.
- return profileOwner != null &&
- getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
- }
-
private boolean canSetPasswordQualityOnParent(String packageName, final CallerIdentity caller) {
return !mInjector.isChangeEnabled(
PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT, packageName, caller.getUserId())
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 21964dd..09a831e 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -51,7 +51,6 @@
// classes generated by netd_aidl_interfaces-platform-java above.
"netd_aidl_interface-V3-java",
"networkstack-client",
- "modules-utils-build_system",
],
apex_available: [
"com.android.wifi",
diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file6.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file6.xml
new file mode 100644
index 0000000..b3c14228
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file6.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<sensor-privacy enabled="false">
+</sensor-privacy>
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 0fcda81..6a25560 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -678,6 +678,7 @@
private void markImplicitConstraintsSatisfied(JobStatus job, boolean isSatisfied) {
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
+ job.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
job.setDeviceNotDozingConstraintSatisfied(
sElapsedRealtimeClock.millis(), isSatisfied, false);
job.setBackgroundNotRestrictedConstraintSatisfied(
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index dd70c87..4738159 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -389,6 +389,8 @@
/* state */ true, /* allowlisted */false);
js.setBackgroundNotRestrictedConstraintSatisfied(
sElapsedRealtimeClock.millis(), true, false);
+ js.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+ js.setExpeditedJobTareApproved(sElapsedRealtimeClock.millis(), true);
return js;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index ba5a58f..b60e0c3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -30,17 +31,23 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
+import android.apex.ApexInfo;
import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
import android.content.Context;
import android.content.IntentSender;
+import android.content.pm.ApexStagedEvent;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
+import android.content.pm.StagedApexInfo;
+import android.os.Message;
import android.os.SystemProperties;
import android.os.storage.IStorageManager;
import android.platform.test.annotations.Presubmit;
+import android.util.IntArray;
import android.util.SparseArray;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -55,15 +62,20 @@
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import org.mockito.invocation.InvocationOnMock;
import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.function.Predicate;
@Presubmit
@@ -527,6 +539,281 @@
assertThat(mStagingManager.getSessionIdByPackageName("com.bar")).isEqualTo(-1);
}
+ @Test
+ public void getStagedApexInfos_validatePreConditions() throws Exception {
+ // Invalid session: null session
+ {
+ // Call and verify
+ IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+ () -> mStagingManager.getStagedApexInfos(null));
+ assertThat(thrown).hasMessageThat().contains("Session is null");
+ }
+ // Invalid session: has parent
+ {
+ FakeStagedSession session = new FakeStagedSession(241);
+ session.setParentSessionId(239);
+ session.setSessionReady();
+ // Call and verify
+ IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+ () -> mStagingManager.getStagedApexInfos(session));
+ assertThat(thrown).hasMessageThat().contains("241 session has parent");
+ }
+
+ // Invalid session: does not contain apex
+ {
+ FakeStagedSession session = new FakeStagedSession(241);
+ session.setSessionReady();
+ // Call and verify
+ IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+ () -> mStagingManager.getStagedApexInfos(session));
+ assertThat(thrown).hasMessageThat().contains("241 session does not contain apex");
+ }
+ // Invalid session: not ready
+ {
+ FakeStagedSession session = new FakeStagedSession(239);
+ session.setIsApex(true);
+ // Call and verify
+ Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(session);
+ assertThat(result).isEmpty();
+ }
+ // Invalid session: destroyed
+ {
+ FakeStagedSession session = new FakeStagedSession(240);
+ session.setSessionReady();
+ session.setIsApex(true);
+ session.setDestroyed(true);
+ // Call and verify
+ Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(session);
+ assertThat(result).isEmpty();
+ }
+ }
+
+ private ApexInfo[] getFakeApexInfo(List<String> moduleNames) {
+ List<ApexInfo> result = new ArrayList<>();
+ for (String moduleName : moduleNames) {
+ ApexInfo info = new ApexInfo();
+ info.moduleName = moduleName;
+ result.add(info);
+ }
+ return result.toArray(new ApexInfo[0]);
+ }
+
+ @Test
+ public void getStagedApexInfos_nonParentSession() throws Exception {
+ FakeStagedSession validSession = new FakeStagedSession(239);
+ validSession.setIsApex(true);
+ validSession.setSessionReady();
+ ApexInfo[] fakeApexInfos = getFakeApexInfo(Arrays.asList("module1"));
+ when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
+
+ // Call and verify
+ Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(validSession);
+ assertThat(result).containsExactly(fakeApexInfos[0].moduleName, fakeApexInfos[0]);
+
+ ArgumentCaptor<ApexSessionParams> argumentCaptor =
+ ArgumentCaptor.forClass(ApexSessionParams.class);
+ verify(mApexManager, times(1)).getStagedApexInfos(argumentCaptor.capture());
+ ApexSessionParams params = argumentCaptor.getValue();
+ assertThat(params.sessionId).isEqualTo(239);
+ }
+
+ @Test
+ public void getStagedApexInfos_parentSession() throws Exception {
+ FakeStagedSession childSession1 = new FakeStagedSession(201);
+ childSession1.setIsApex(true);
+ FakeStagedSession childSession2 = new FakeStagedSession(202);
+ childSession2.setIsApex(true);
+ FakeStagedSession nonApexChild = new FakeStagedSession(203);
+ FakeStagedSession parentSession = new FakeStagedSession(239,
+ Arrays.asList(childSession1, childSession2, nonApexChild));
+ parentSession.setSessionReady();
+ ApexInfo[] fakeApexInfos = getFakeApexInfo(Arrays.asList("module1", "module2"));
+ when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
+
+ // Call and verify
+ Map<String, ApexInfo> result = mStagingManager.getStagedApexInfos(parentSession);
+ assertThat(result).containsExactly(fakeApexInfos[0].moduleName, fakeApexInfos[0],
+ fakeApexInfos[1].moduleName, fakeApexInfos[1]);
+
+ ArgumentCaptor<ApexSessionParams> argumentCaptor =
+ ArgumentCaptor.forClass(ApexSessionParams.class);
+ verify(mApexManager, times(1)).getStagedApexInfos(argumentCaptor.capture());
+ ApexSessionParams params = argumentCaptor.getValue();
+ assertThat(params.sessionId).isEqualTo(239);
+ assertThat(params.childSessionIds).asList().containsExactly(201, 202);
+ }
+
+ @Test
+ public void getStagedApexModuleNames_returnsStagedApexModules() throws Exception {
+ FakeStagedSession validSession1 = new FakeStagedSession(239);
+ validSession1.setIsApex(true);
+ validSession1.setSessionReady();
+ mStagingManager.createSession(validSession1);
+
+ FakeStagedSession childSession1 = new FakeStagedSession(123);
+ childSession1.setIsApex(true);
+ FakeStagedSession childSession2 = new FakeStagedSession(124);
+ childSession2.setIsApex(true);
+ FakeStagedSession nonApexChild = new FakeStagedSession(125);
+ FakeStagedSession parentSession = new FakeStagedSession(240,
+ Arrays.asList(childSession1, childSession2, nonApexChild));
+ parentSession.setSessionReady();
+ mStagingManager.createSession(parentSession);
+
+ mockApexManagerGetStagedApexInfoWithSessionId();
+
+ List<String> result = mStagingManager.getStagedApexModuleNames();
+ assertThat(result).containsExactly("239", "123", "124");
+ verify(mApexManager, times(2)).getStagedApexInfos(any());
+ }
+
+ // Make mApexManager return ApexInfo with same module name as the sessionId
+ // of the parameter that was passed into it
+ private void mockApexManagerGetStagedApexInfoWithSessionId() {
+ when(mApexManager.getStagedApexInfos(any())).thenAnswer(new Answer<ApexInfo[]>() {
+ @Override
+ public ApexInfo[] answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ApexSessionParams params = (ApexSessionParams) args[0];
+ IntArray sessionsToProcess = new IntArray();
+ if (params.childSessionIds.length == 0) {
+ sessionsToProcess.add(params.sessionId);
+ } else {
+ sessionsToProcess.addAll(params.childSessionIds);
+ }
+ List<ApexInfo> result = new ArrayList<>();
+ for (int session : sessionsToProcess.toArray()) {
+ ApexInfo info = new ApexInfo();
+ info.moduleName = String.valueOf(session);
+ result.add(info);
+ }
+ return result.toArray(new ApexInfo[0]);
+ }
+ });
+ }
+
+ @Test
+ public void getStagedApexInfo() throws Exception {
+ FakeStagedSession validSession1 = new FakeStagedSession(239);
+ validSession1.setIsApex(true);
+ validSession1.setSessionReady();
+ mStagingManager.createSession(validSession1);
+ ApexInfo[] fakeApexInfos = getFakeApexInfo(Arrays.asList("module1"));
+ when(mApexManager.getStagedApexInfos(any())).thenReturn(fakeApexInfos);
+
+ // Verify null is returned if module name is not found
+ StagedApexInfo result = mStagingManager.getStagedApexInfo("not found");
+ assertThat(result).isNull();
+ verify(mApexManager, times(1)).getStagedApexInfos(any());
+ // Otherwise, the correct object is returned
+ result = mStagingManager.getStagedApexInfo("module1");
+ assertThat(result.moduleName).isEqualTo(fakeApexInfos[0].moduleName);
+ assertThat(result.diskImagePath).isEqualTo(fakeApexInfos[0].modulePath);
+ assertThat(result.versionCode).isEqualTo(fakeApexInfos[0].versionCode);
+ assertThat(result.versionName).isEqualTo(fakeApexInfos[0].versionName);
+ verify(mApexManager, times(2)).getStagedApexInfos(any());
+ }
+
+ @Test
+ public void registeredStagedApexObserverIsNotifiedOnPreRebootVerificationCompletion()
+ throws Exception {
+ // Register observer
+ IStagedApexObserver observer = Mockito.mock(IStagedApexObserver.class);
+ mStagingManager.registerStagedApexObserver(observer);
+
+ // Create one staged session and trigger end of pre-reboot verification
+ {
+ FakeStagedSession session = new FakeStagedSession(239);
+ session.setIsApex(true);
+ mStagingManager.createSession(session);
+
+ mockApexManagerGetStagedApexInfoWithSessionId();
+ triggerEndOfPreRebootVerification(session);
+
+ assertThat(session.isSessionReady()).isTrue();
+ ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
+ ApexStagedEvent.class);
+ verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
+ assertThat(argumentCaptor.getValue().stagedApexModuleNames).isEqualTo(
+ new String[]{"239"});
+ }
+
+ // Create another staged session and verify observers are notified of union
+ {
+ Mockito.clearInvocations(observer);
+ FakeStagedSession session = new FakeStagedSession(240);
+ session.setIsApex(true);
+ mStagingManager.createSession(session);
+
+ triggerEndOfPreRebootVerification(session);
+
+ assertThat(session.isSessionReady()).isTrue();
+ ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
+ ApexStagedEvent.class);
+ verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
+ assertThat(argumentCaptor.getValue().stagedApexModuleNames).isEqualTo(
+ new String[]{"239", "240"});
+ }
+
+ // Finally, verify that once unregistered, observer is not notified
+ mStagingManager.unregisterStagedApexObserver(observer);
+ {
+ Mockito.clearInvocations(observer);
+ FakeStagedSession session = new FakeStagedSession(241);
+ session.setIsApex(true);
+ mStagingManager.createSession(session);
+
+ triggerEndOfPreRebootVerification(session);
+
+ assertThat(session.isSessionReady()).isTrue();
+ verify(observer, never()).onApexStaged(any());
+ }
+ }
+
+ @Test
+ public void registeredStagedApexObserverIsNotifiedOnSessionAbandon() throws Exception {
+ // Register observer
+ IStagedApexObserver observer = Mockito.mock(IStagedApexObserver.class);
+ mStagingManager.registerStagedApexObserver(observer);
+
+ // Create a ready session and abandon it
+ FakeStagedSession session = new FakeStagedSession(239);
+ session.setIsApex(true);
+ session.setSessionReady();
+ session.setDestroyed(true);
+ mStagingManager.createSession(session);
+
+ mStagingManager.abortCommittedSession(session);
+
+ assertThat(session.isSessionReady()).isTrue();
+ ArgumentCaptor<ApexStagedEvent> argumentCaptor = ArgumentCaptor.forClass(
+ ApexStagedEvent.class);
+ verify(observer, times(1)).onApexStaged(argumentCaptor.capture());
+ assertThat(argumentCaptor.getValue().stagedApexModuleNames).hasLength(0);
+ }
+
+ @Test
+ public void stagedApexObserverIsOnlyCalledForApexSessions() throws Exception {
+ IStagedApexObserver observer = Mockito.mock(IStagedApexObserver.class);
+ mStagingManager.registerStagedApexObserver(observer);
+
+ // Trigger end of pre-reboot verification
+ FakeStagedSession session = new FakeStagedSession(239);
+ mStagingManager.createSession(session);
+
+ triggerEndOfPreRebootVerification(session);
+ assertThat(session.isSessionReady()).isTrue();
+ verify(observer, never()).onApexStaged(any());
+ }
+
+ private void triggerEndOfPreRebootVerification(StagingManager.StagedSession session) {
+ StagingManager.PreRebootVerificationHandler handler =
+ mStagingManager.mPreRebootVerificationHandler;
+ Message msg = handler.obtainMessage(
+ handler.MSG_PRE_REBOOT_VERIFICATION_END, session.sessionId(), -1, session);
+ handler.handleMessage(msg);
+ }
+
private StagingManager.StagedSession createSession(int sessionId, String packageName,
long committedMillis) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
@@ -591,10 +878,16 @@
private String mPackageName;
private boolean mIsAbandonded = false;
private boolean mVerificationStarted = false;
- private final List<StagingManager.StagedSession> mChildSessions = new ArrayList<>();
+ private final List<StagingManager.StagedSession> mChildSessions;
private FakeStagedSession(int sessionId) {
mSessionId = sessionId;
+ mChildSessions = new ArrayList<>();
+ }
+
+ private FakeStagedSession(int sessionId, List<StagingManager.StagedSession> childSessions) {
+ mSessionId = sessionId;
+ mChildSessions = childSessions;
}
private void setParentSessionId(int parentSessionId) {
@@ -777,9 +1070,7 @@
}
@Override
- public void notifyEndPreRebootVerification() {
- throw new UnsupportedOperationException();
- }
+ public void notifyEndPreRebootVerification() {}
@Override
public void verifySession() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java
index 844687f..ba79a76 100644
--- a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java
@@ -60,6 +60,8 @@
String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 4);
public static final String PERSISTENCE_FILE5 =
String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 5);
+ public static final String PERSISTENCE_FILE6 =
+ String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 6);
private Context mContext;
@Mock
@@ -111,6 +113,7 @@
initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE3);
initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE4);
initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE5);
+ initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE6);
// Try all files with two known users
doReturn(new int[]{0, 10}).when(mMockedUserManagerInternal).getUserIds();
@@ -124,6 +127,7 @@
initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE3);
initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE4);
initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE5);
+ initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE6);
} finally {
mockitoSession.finishMocking();
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 5a00e0d..8f9eb22 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -95,6 +95,8 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
/**
@@ -696,10 +698,12 @@
VibratorManagerService.OnSyncedVibrationCompleteListener.class);
verify(mNativeWrapperMock).init(listenerCaptor.capture());
- // Mock trigger callback on registered listener.
+ CountDownLatch triggerCountDown = new CountDownLatch(1);
+ // Mock trigger callback on registered listener right after the synced vibration starts.
when(mNativeWrapperMock.prepareSynced(eq(new int[]{1, 2}))).thenReturn(true);
when(mNativeWrapperMock.triggerSynced(anyLong())).then(answer -> {
listenerCaptor.getValue().onComplete(answer.getArgument(0));
+ triggerCountDown.countDown();
return true;
});
@@ -708,20 +712,19 @@
.compose();
CombinedVibration effect = CombinedVibration.createParallel(composed);
- // Wait for vibration to start, it should finish right away with trigger callback.
vibrate(service, effect, ALARM_ATTRS);
-
- // VibrationThread will start this vibration async, so wait until callback is triggered.
- assertTrue(waitUntil(s -> !listenerCaptor.getAllValues().isEmpty(), service,
- TEST_TIMEOUT_MILLIS));
+ // VibrationThread will start this vibration async, so wait until vibration is triggered.
+ triggerCountDown.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
verify(mNativeWrapperMock).prepareSynced(eq(new int[]{1, 2}));
verify(mNativeWrapperMock).triggerSynced(anyLong());
-
PrimitiveSegment expected = new PrimitiveSegment(
VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 100);
assertEquals(Arrays.asList(expected), mVibratorProviders.get(1).getEffectSegments());
assertEquals(Arrays.asList(expected), mVibratorProviders.get(2).getEffectSegments());
+
+ // VibrationThread needs some time to react to native callbacks and stop the vibrator.
+ assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
}
@Test
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceLogger.java b/services/usb/java/com/android/server/usb/UsbDeviceLogger.java
new file mode 100644
index 0000000..fab00bc
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbDeviceLogger.java
@@ -0,0 +1,143 @@
+/*
+ * 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.usb;
+
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.dump.DualDumpOutputStream;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.LinkedList;
+
+/**
+* Constructor UsbDeviceLogger class
+*/
+public class UsbDeviceLogger {
+ private final Object mLock = new Object();
+
+ // ring buffer of events to log.
+ @GuardedBy("mLock")
+ private final LinkedList<Event> mEvents;
+
+ private final String mTitle;
+
+ // the maximum number of events to keep in log
+ private final int mMemSize;
+
+ /**
+ * Constructor for Event class.
+ */
+ public abstract static class Event {
+ // formatter for timestamps
+ private static final SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
+
+ private final Calendar mCalendar;
+
+ Event() {
+ mCalendar = Calendar.getInstance();
+ }
+
+ /**
+ * Convert event to String
+ * @return StringBuilder
+ */
+ public String toString() {
+ return (new StringBuilder(String.format("%tm-%td %tH:%tM:%tS.%tL",
+ mCalendar, mCalendar, mCalendar, mCalendar, mCalendar, mCalendar)))
+ .append(" ").append(eventToString()).toString();
+ }
+
+ /**
+ * Causes the string message for the event to appear in the logcat.
+ * Here is an example of how to create a new event (a StringEvent), adding it to the logger
+ * (an instance of UsbDeviceLoggerr) while also making it show in the logcat:
+ * <pre>
+ * myLogger.log(
+ * (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) );
+ * </pre>
+ * @param tag the tag for the android.util.Log.v
+ * @return the same instance of the event
+ */
+ public Event printLog(String tag) {
+ Log.i(tag, eventToString());
+ return this;
+ }
+
+ /**
+ * Convert event to String.
+ * This method is only called when the logger history is about to the dumped,
+ * so this method is where expensive String conversions should be made, not when the Event
+ * subclass is created.
+ * Timestamp information will be automatically added, do not include it.
+ * @return a string representation of the event that occurred.
+ */
+ public abstract String eventToString();
+ }
+
+ /**
+ * Constructor StringEvent class
+ */
+ public static class StringEvent extends Event {
+ private final String mMsg;
+
+ public StringEvent(String msg) {
+ mMsg = msg;
+ }
+
+ @Override
+ public String eventToString() {
+ return mMsg;
+ }
+ }
+
+ /**
+ * Constructor for logger.
+ * @param size the maximum number of events to keep in log
+ * @param title the string displayed before the recorded log
+ */
+ public UsbDeviceLogger(int size, String title) {
+ mEvents = new LinkedList<Event>();
+ mMemSize = size;
+ mTitle = title;
+ }
+
+ /**
+ * Constructor for logger.
+ * @param evt the maximum number of events to keep in log
+ */
+ public synchronized void log(Event evt) {
+ synchronized (mLock) {
+ if (mEvents.size() >= mMemSize) {
+ mEvents.removeFirst();
+ }
+ mEvents.add(evt);
+ }
+ }
+
+ /**
+ * Constructor for logger.
+ * @param dump the maximum number of events to keep in log
+ * @param id the category of events
+ */
+ public synchronized void dump(DualDumpOutputStream dump, long id) {
+ dump.write("USB Event Log", id, mTitle);
+ for (Event evt : mEvents) {
+ dump.write("USB Event", id, evt.toString());
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b966643..27aabb5 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -191,6 +191,8 @@
*/
private static final int ACCESSORY_HANDSHAKE_TIMEOUT = 10 * 1000;
+ private static final int DUMPSYS_LOG_BUFFER = 200;
+
private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";
@@ -210,6 +212,8 @@
private static Set<Integer> sDenyInterfaces;
private HashMap<Long, FileDescriptor> mControlFds;
+ private static UsbDeviceLogger sEventLogger;
+
static {
sDenyInterfaces = new HashSet<>();
sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
@@ -232,9 +236,11 @@
@Override
public void onUEvent(UEventObserver.UEvent event) {
if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
+ sEventLogger.log(new UsbDeviceLogger.StringEvent("USB UEVENT: " + event.toString()));
String state = event.get("USB_STATE");
String accessory = event.get("ACCESSORY");
+
if (state != null) {
mHandler.updateState(state);
} else if ("GETPROTOCOL".equals(accessory)) {
@@ -382,6 +388,8 @@
mUEventObserver = new UsbUEventObserver();
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+
+ sEventLogger = new UsbDeviceLogger(DUMPSYS_LOG_BUFFER, "UsbDeviceManager activity");
}
UsbProfileGroupSettingsManager getCurrentSettings() {
@@ -814,6 +822,7 @@
protected void sendStickyBroadcast(Intent intent) {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ sEventLogger.log(new UsbDeviceLogger.StringEvent("USB intent: " + intent));
}
private void updateUsbFunctions() {
@@ -2285,6 +2294,7 @@
if (mHandler != null) {
mHandler.dump(dump, "handler", UsbDeviceManagerProto.HANDLER);
+ sEventLogger.dump(dump, UsbHandlerProto.UEVENT);
}
dump.end(token);
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index f638660..bb0c4e9 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -60,7 +60,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Immutable;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
@@ -75,7 +74,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ProtocolException;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -86,6 +84,8 @@
private static final String TAG = UsbProfileGroupSettingsManager.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final int DUMPSYS_LOG_BUFFER = 200;
+
/** Legacy settings file, before multi-user */
private static final File sSingleUserSettingsFile = new File(
"/data/system/usb_device_manager.xml");
@@ -130,6 +130,8 @@
@GuardedBy("mLock")
private boolean mIsWriteSettingsScheduled;
+ private static UsbDeviceLogger sEventLogger;
+
/**
* A package of a user.
*/
@@ -260,6 +262,9 @@
device, false /* showMtpNotification */));
mUsbHandlerManager = usbResolveActivityManager;
+
+ sEventLogger = new UsbDeviceLogger(DUMPSYS_LOG_BUFFER,
+ "UsbProfileGroupSettingsManager activity");
}
/**
@@ -965,6 +970,7 @@
matches, mAccessoryPreferenceMap.get(new AccessoryFilter(accessory)));
}
+ sEventLogger.log(new UsbDeviceLogger.StringEvent("accessoryAttached: " + intent));
resolveActivity(intent, matches, defaultActivity, null, accessory);
}
@@ -1518,6 +1524,7 @@
}
}
+ sEventLogger.dump(dump, UsbProfileGroupSettingsManagerProto.INTENT);
dump.end(token);
}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index cac14a7..558798d 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -37,6 +37,7 @@
":test.rebootless_apex_v1",
":test.rebootless_apex_v2",
],
+ platform_apis: true,
}
java_test_host {
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 4684f01..c610641 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -17,16 +17,27 @@
package com.android.tests.stagedinstallinternal;
import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
+import static com.android.cts.install.lib.InstallUtils.waitForSessionReady;
import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
import android.Manifest;
+import android.content.pm.ApexStagedEvent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManagerNative;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
+import android.content.pm.StagedApexInfo;
+import android.os.IBinder;
+import android.os.ServiceManager;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -39,6 +50,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -401,9 +414,73 @@
AssertionError.class,
"Staged session " + sessionId + " already contains " + SHIM_APEX_PACKAGE_NAME,
Install.single(APEX_V2));
-
}
+ @Test
+ public void testGetStagedModuleNames() throws Exception {
+ // Before staging a session
+ String[] result = getPackageManagerNative().getStagedApexModuleNames();
+ assertThat(result).hasLength(0);
+ // Stage an apex
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ waitForSessionReady(sessionId);
+ result = getPackageManagerNative().getStagedApexModuleNames();
+ assertThat(result).hasLength(1);
+ assertThat(result).isEqualTo(new String[]{SHIM_APEX_PACKAGE_NAME});
+ // Abandon the session
+ InstallUtils.openPackageInstallerSession(sessionId).abandon();
+ result = getPackageManagerNative().getStagedApexModuleNames();
+ assertThat(result).hasLength(0);
+ }
+
+ @Test
+ public void testGetStagedApexInfo() throws Exception {
+ // Ask for non-existing module
+ StagedApexInfo result = getPackageManagerNative().getStagedApexInfo("not found");
+ assertThat(result).isNull();
+ // Stage an apex
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ waitForSessionReady(sessionId);
+ // Query proper module name
+ result = getPackageManagerNative().getStagedApexInfo(SHIM_APEX_PACKAGE_NAME);
+ assertThat(result.moduleName).isEqualTo(SHIM_APEX_PACKAGE_NAME);
+ InstallUtils.openPackageInstallerSession(sessionId).abandon();
+ }
+
+ public static class MockStagedApexObserver extends IStagedApexObserver.Stub {
+ @Override
+ public void onApexStaged(ApexStagedEvent event) {
+ assertThat(event).isNotNull();
+ }
+ }
+
+ @Test
+ public void testStagedApexObserver() throws Exception {
+ MockStagedApexObserver realObserver = new MockStagedApexObserver();
+ IStagedApexObserver observer = spy(realObserver);
+ assertThat(observer).isNotNull();
+ getPackageManagerNative().registerStagedApexObserver(observer);
+
+ // Stage an apex and verify observer was called
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ waitForSessionReady(sessionId);
+ ArgumentCaptor<ApexStagedEvent> captor = ArgumentCaptor.forClass(ApexStagedEvent.class);
+ verify(observer, timeout(5000)).onApexStaged(captor.capture());
+ assertThat(captor.getValue().stagedApexModuleNames).isEqualTo(
+ new String[] {SHIM_APEX_PACKAGE_NAME});
+
+ // Abandon and verify observer is called
+ Mockito.clearInvocations(observer);
+ InstallUtils.openPackageInstallerSession(sessionId).abandon();
+ verify(observer, timeout(5000)).onApexStaged(captor.capture());
+ assertThat(captor.getValue().stagedApexModuleNames).hasLength(0);
+ }
+
+ private IPackageManagerNative getPackageManagerNative() {
+ IBinder binder = ServiceManager.waitForService("package_native");
+ assertThat(binder).isNotNull();
+ return IPackageManagerNative.Stub.asInterface(binder);
+ }
private static void assertSessionApplied(int sessionId) {
assertSessionState(sessionId, (session) -> {
assertThat(session.isStagedSessionApplied()).isTrue();
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 5021009..3102103 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -478,6 +478,21 @@
runPhase("testRebootlessUpdate_hasStagedSessionWithSameApex_fails");
}
+ @Test
+ public void testGetStagedModuleNames() throws Exception {
+ runPhase("testGetStagedModuleNames");
+ }
+
+ @Test
+ public void testGetStagedApexInfo() throws Exception {
+ runPhase("testGetStagedApexInfo");
+ }
+
+ @Test
+ public void testStagedApexObserver() throws Exception {
+ runPhase("testStagedApexObserver");
+ }
+
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {