Merge "WM: Clean up InputTarget interface"
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
index 98a39a6..aca381f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
@@ -113,7 +113,6 @@
userFilter.addAction(Intent.ACTION_USER_STOPPED);
mContext.registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
-
}
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/Package.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/Package.java
new file mode 100644
index 0000000..78a77fe
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/Package.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job.controllers;
+
+import java.util.Objects;
+
+/** Wrapper class to represent a userId-pkgName combo. */
+final class Package {
+ public final String packageName;
+ public final int userId;
+
+ Package(int userId, String packageName) {
+ this.userId = userId;
+ this.packageName = packageName;
+ }
+
+ @Override
+ public String toString() {
+ return packageToString(userId, packageName);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Package)) {
+ return false;
+ }
+ Package other = (Package) obj;
+ return userId == other.userId && Objects.equals(packageName, other.packageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return packageName.hashCode() + userId;
+ }
+
+ /**
+ * Standardize the output of userId-packageName combo.
+ */
+ static String packageToString(int userId, String packageName) {
+ return "<" + userId + ">" + packageName;
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
index 725092c..6232dfb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
@@ -20,9 +20,13 @@
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;
+import static com.android.server.job.controllers.Package.packageToString;
import android.annotation.CurrentTimeMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Looper;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
@@ -36,6 +40,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.job.JobSchedulerService;
+import com.android.server.utils.AlarmQueue;
import java.util.function.Predicate;
@@ -57,6 +62,7 @@
*/
@GuardedBy("mLock")
private final SparseArrayMap<String, Long> mEstimatedLaunchTimes = new SparseArrayMap<>();
+ private final ThresholdAlarmListener mThresholdAlarmListener;
/**
* The cutoff point to decide if a prefetch job is worth running or not. If the app is expected
@@ -69,6 +75,8 @@
public PrefetchController(JobSchedulerService service) {
super(service);
mPcConstants = new PcConstants();
+ mThresholdAlarmListener = new ThresholdAlarmListener(
+ mContext, JobSchedulerBackgroundThread.get().getLooper());
}
@Override
@@ -82,9 +90,13 @@
jobs = new ArraySet<>();
mTrackedJobs.add(userId, pkgName, jobs);
}
- jobs.add(jobStatus);
- updateConstraintLocked(jobStatus,
- sSystemClock.millis(), sElapsedRealtimeClock.millis());
+ final long now = sSystemClock.millis();
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (jobs.add(jobStatus) && jobs.size() == 1
+ && !willBeLaunchedSoonLocked(userId, pkgName, now)) {
+ updateThresholdAlarmLocked(userId, pkgName, now, nowElapsed);
+ }
+ updateConstraintLocked(jobStatus, now, nowElapsed);
}
}
@@ -92,10 +104,11 @@
@GuardedBy("mLock")
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean forUpdate) {
- final ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUserId(),
- jobStatus.getSourcePackageName());
- if (jobs != null) {
- jobs.remove(jobStatus);
+ final int userId = jobStatus.getSourceUserId();
+ final String pkgName = jobStatus.getSourcePackageName();
+ final ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
+ if (jobs != null && jobs.remove(jobStatus) && jobs.size() == 0) {
+ mThresholdAlarmListener.removeAlarmForKey(new Package(userId, pkgName));
}
}
@@ -109,6 +122,7 @@
final int userId = UserHandle.getUserId(uid);
mTrackedJobs.delete(userId, packageName);
mEstimatedLaunchTimes.delete(userId, packageName);
+ mThresholdAlarmListener.removeAlarmForKey(new Package(userId, packageName));
}
@Override
@@ -116,6 +130,7 @@
public void onUserRemovedLocked(int userId) {
mTrackedJobs.delete(userId);
mEstimatedLaunchTimes.delete(userId);
+ mThresholdAlarmListener.removeAlarmsForUserId(userId);
}
/** Return the app's next estimated launch time. */
@@ -124,8 +139,14 @@
public long getNextEstimatedLaunchTimeLocked(@NonNull JobStatus jobStatus) {
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
+ return getNextEstimatedLaunchTimeLocked(userId, pkgName, sSystemClock.millis());
+ }
+
+ @GuardedBy("mLock")
+ @CurrentTimeMillisLong
+ private long getNextEstimatedLaunchTimeLocked(int userId, @NonNull String pkgName,
+ @CurrentTimeMillisLong long now) {
Long nextEstimatedLaunchTime = mEstimatedLaunchTimes.get(userId, pkgName);
- final long now = sSystemClock.millis();
if (nextEstimatedLaunchTime == null || nextEstimatedLaunchTime < now) {
// TODO(194532703): get estimated time from UsageStats
nextEstimatedLaunchTime = now + 2 * HOUR_IN_MILLIS;
@@ -135,8 +156,8 @@
}
@GuardedBy("mLock")
- private boolean maybeUpdateConstraintForPkgLocked(long now, long nowElapsed, int userId,
- String pkgName) {
+ private boolean maybeUpdateConstraintForPkgLocked(@CurrentTimeMillisLong long now,
+ @ElapsedRealtimeLong long nowElapsed, int userId, String pkgName) {
final ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
if (jobs == null) {
return false;
@@ -150,10 +171,43 @@
}
@GuardedBy("mLock")
- private boolean updateConstraintLocked(@NonNull JobStatus jobStatus, long now,
- long nowElapsed) {
+ private boolean updateConstraintLocked(@NonNull JobStatus jobStatus,
+ @CurrentTimeMillisLong long now, @ElapsedRealtimeLong long nowElapsed) {
return jobStatus.setPrefetchConstraintSatisfied(nowElapsed,
- getNextEstimatedLaunchTimeLocked(jobStatus) <= now + mLaunchTimeThresholdMs);
+ willBeLaunchedSoonLocked(
+ jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), now));
+ }
+
+ @GuardedBy("mLock")
+ private void updateThresholdAlarmLocked(int userId, @NonNull String pkgName,
+ @CurrentTimeMillisLong long now, @ElapsedRealtimeLong long nowElapsed) {
+ final ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
+ if (jobs == null || jobs.size() == 0) {
+ mThresholdAlarmListener.removeAlarmForKey(new Package(userId, pkgName));
+ return;
+ }
+
+ final long nextEstimatedLaunchTime = getNextEstimatedLaunchTimeLocked(userId, pkgName, now);
+ if (nextEstimatedLaunchTime - now > mLaunchTimeThresholdMs) {
+ // Set alarm to be notified when this crosses the threshold.
+ final long timeToCrossThresholdMs =
+ nextEstimatedLaunchTime - (now + mLaunchTimeThresholdMs);
+ mThresholdAlarmListener.addAlarm(new Package(userId, pkgName),
+ nowElapsed + timeToCrossThresholdMs);
+ } else {
+ mThresholdAlarmListener.removeAlarmForKey(new Package(userId, pkgName));
+ }
+ }
+
+ /**
+ * Returns true if the app is expected to be launched soon, where "soon" is within the next
+ * {@link #mLaunchTimeThresholdMs} time.
+ */
+ @GuardedBy("mLock")
+ private boolean willBeLaunchedSoonLocked(int userId, @NonNull String pkgName,
+ @CurrentTimeMillisLong long now) {
+ return getNextEstimatedLaunchTimeLocked(userId, pkgName, now)
+ <= now + mLaunchTimeThresholdMs;
}
@Override
@@ -186,6 +240,9 @@
now, nowElapsed, userId, packageName)) {
changedJobs.addAll(mTrackedJobs.valueAt(u, p));
}
+ if (!willBeLaunchedSoonLocked(userId, packageName, now)) {
+ updateThresholdAlarmLocked(userId, packageName, now, nowElapsed);
+ }
}
}
}
@@ -196,6 +253,42 @@
}
}
+ /** Track when apps will cross the "will run soon" threshold. */
+ private class ThresholdAlarmListener extends AlarmQueue<Package> {
+ private ThresholdAlarmListener(Context context, Looper looper) {
+ super(context, looper, "*job.prefetch*", "Prefetch threshold", false,
+ PcConstants.DEFAULT_LAUNCH_TIME_THRESHOLD_MS / 10);
+ }
+
+ @Override
+ protected boolean isForUser(@NonNull Package key, int userId) {
+ return key.userId == userId;
+ }
+
+ @Override
+ protected void processExpiredAlarms(@NonNull ArraySet<Package> expired) {
+ final ArraySet<JobStatus> changedJobs = new ArraySet<>();
+ synchronized (mLock) {
+ final long now = sSystemClock.millis();
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ for (int i = 0; i < expired.size(); ++i) {
+ Package p = expired.valueAt(i);
+ if (!willBeLaunchedSoonLocked(p.userId, p.packageName, now)) {
+ Slog.e(TAG, "Alarm expired for "
+ + packageToString(p.userId, p.packageName) + " at the wrong time");
+ updateThresholdAlarmLocked(p.userId, p.packageName, now, nowElapsed);
+ } else if (maybeUpdateConstraintForPkgLocked(
+ now, nowElapsed, p.userId, p.packageName)) {
+ changedJobs.addAll(mTrackedJobs.get(p.userId, p.packageName));
+ }
+ }
+ }
+ if (changedJobs.size() > 0) {
+ mStateChangedListener.onControllerStateChanged(changedJobs);
+ }
+ }
+ }
+
@VisibleForTesting
class PcConstants {
private boolean mShouldReevaluateConstraints = false;
@@ -225,6 +318,9 @@
if (mLaunchTimeThresholdMs != newLaunchTimeThresholdMs) {
mLaunchTimeThresholdMs = newLaunchTimeThresholdMs;
mShouldReevaluateConstraints = true;
+ // Give a leeway of 10% of the launch time threshold between alarms.
+ mThresholdAlarmListener.setMinTimeBetweenAlarmsMs(
+ mLaunchTimeThresholdMs / 10);
}
break;
}
@@ -294,6 +390,9 @@
pw.println();
}
});
+
+ pw.println();
+ mThresholdAlarmListener.dump(pw);
}
@Override
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 1016294..31da526 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
@@ -27,6 +27,7 @@
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.controllers.Package.packageToString;
import android.Manifest;
import android.annotation.NonNull;
@@ -79,7 +80,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -123,52 +123,6 @@
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.GET_PERMISSIONS | PackageManager.MATCH_KNOWN_PACKAGES;
- /**
- * Standardize the output of userId-packageName combo.
- */
- private static String string(int userId, String packageName) {
- return "<" + userId + ">" + packageName;
- }
-
- private static final class Package {
- public final String packageName;
- public final int userId;
-
- Package(int userId, String packageName) {
- this.userId = userId;
- this.packageName = packageName;
- }
-
- @Override
- public String toString() {
- return string(userId, packageName);
- }
-
- public void dumpDebug(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
-
- proto.write(StateControllerProto.QuotaController.Package.USER_ID, userId);
- proto.write(StateControllerProto.QuotaController.Package.NAME, packageName);
-
- proto.end(token);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof Package) {
- Package other = (Package) obj;
- return userId == other.userId && Objects.equals(packageName, other.packageName);
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- return packageName.hashCode() + userId;
- }
- }
-
private static int hashLong(long val) {
return (int) (val ^ (val >>> 32));
}
@@ -1741,7 +1695,6 @@
return;
}
- final String pkgString = string(userId, packageName);
ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
final boolean isUnderJobCountQuota = isUnderJobCountQuotaLocked(stats, standbyBucket);
final boolean isUnderTimingSessionCountQuota = isUnderSessionCountQuotaLocked(stats,
@@ -1755,7 +1708,8 @@
if (inRegularQuota && remainingEJQuota > 0) {
// Already in quota. Why was this method called?
if (DEBUG) {
- Slog.e(TAG, "maybeScheduleStartAlarmLocked called for " + pkgString
+ Slog.e(TAG, "maybeScheduleStartAlarmLocked called for "
+ + packageToString(userId, packageName)
+ " even though it already has "
+ getRemainingExecutionTimeLocked(userId, packageName, standbyBucket)
+ "ms in its quota.");
@@ -1811,8 +1765,8 @@
// In some strange cases, an app may end be in the NEVER bucket but could have run
// some regular jobs. This results in no EJ timing sessions and QC having a bad
// time.
- Slog.wtf(TAG,
- string(userId, packageName) + " has 0 EJ quota without running anything");
+ Slog.wtf(TAG, packageToString(userId, packageName)
+ + " has 0 EJ quota without running anything");
return;
}
}
@@ -2272,7 +2226,6 @@
public void dump(ProtoOutputStream proto, long fieldId, Predicate<JobStatus> predicate) {
final long token = proto.start(fieldId);
- mPkg.dumpDebug(proto, StateControllerProto.QuotaController.Timer.PKG);
proto.write(StateControllerProto.QuotaController.Timer.IS_ACTIVE, isActive());
proto.write(StateControllerProto.QuotaController.Timer.START_TIME_ELAPSED,
mStartTimeElapsed);
@@ -2381,7 +2334,6 @@
public void dump(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- mPkg.dumpDebug(proto, StateControllerProto.QuotaController.TopAppTimer.PKG);
proto.write(StateControllerProto.QuotaController.TopAppTimer.IS_ACTIVE, isActive());
proto.write(StateControllerProto.QuotaController.TopAppTimer.START_TIME_ELAPSED,
mStartTimeElapsed);
@@ -2413,7 +2365,7 @@
void updateStandbyBucket(
final int userId, final @NonNull String packageName, final int bucketIndex) {
if (DEBUG) {
- Slog.i(TAG, "Moving pkg " + string(userId, packageName)
+ Slog.i(TAG, "Moving pkg " + packageToString(userId, packageName)
+ " to bucketIndex " + bucketIndex);
}
List<JobStatus> restrictedChanges = new ArrayList<>();
@@ -2641,7 +2593,7 @@
String packageName = (String) msg.obj;
int userId = msg.arg1;
if (DEBUG) {
- Slog.d(TAG, "Checking pkg " + string(userId, packageName));
+ Slog.d(TAG, "Checking pkg " + packageToString(userId, packageName));
}
if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
userId, packageName)) {
@@ -2722,7 +2674,7 @@
final String pkgName = event.getPackageName();
if (DEBUG) {
Slog.d(TAG, "Processing event " + event.getEventType()
- + " for " + string(userId, pkgName));
+ + " for " + packageToString(userId, pkgName));
}
switch (event.getEventType()) {
case UsageEvents.Event.ACTIVITY_RESUMED:
@@ -4119,7 +4071,7 @@
final String pkgName = mExecutionStatsCache.keyAt(u, p);
ExecutionStats[] stats = mExecutionStatsCache.valueAt(u, p);
- pw.println(string(userId, pkgName));
+ pw.println(packageToString(userId, pkgName));
pw.increaseIndent();
for (int i = 0; i < stats.length; ++i) {
ExecutionStats executionStats = stats[i];
@@ -4143,7 +4095,7 @@
final String pkgName = mEJStats.keyAt(u, p);
ShrinkableDebits debits = mEJStats.valueAt(u, p);
- pw.print(string(userId, pkgName));
+ pw.print(packageToString(userId, pkgName));
pw.print(": ");
debits.dumpLocked(pw);
}
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 e9fa926..a39fd47 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -537,10 +537,11 @@
private void setupHeavyWork() {
synchronized (mLock) {
loadInstalledPackageListLocked();
- // TODO: base on if we have anything persisted
- final boolean isFirstSetup = true;
+ final boolean isFirstSetup = !mScribe.recordExists();
if (isFirstSetup) {
mAgent.grantBirthrightsLocked();
+ } else {
+ mScribe.loadFromDiskLocked();
}
scheduleUnusedWealthReclamationLocked();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
index f2b78c0..a234ae6 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
@@ -61,6 +61,11 @@
Ledger() {
}
+ Ledger(long currentBalance, @NonNull List<Transaction> transactions) {
+ mCurrentBalance = currentBalance;
+ mTransactions.addAll(transactions);
+ }
+
long getCurrentBalance() {
return mCurrentBalance;
}
@@ -73,6 +78,11 @@
return null;
}
+ @NonNull
+ List<Transaction> getTransactions() {
+ return mTransactions;
+ }
+
void recordTransaction(@NonNull Transaction transaction) {
mTransactions.add(transaction);
mCurrentBalance += transaction.delta;
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index 2c133dcb..48a373b 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -21,11 +21,34 @@
import static com.android.server.tare.TareUtils.appToString;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.biometrics.face.V1_0.UserHandle;
+import android.os.Environment;
+import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
import android.util.SparseArrayMap;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
* Maintains the current TARE state and handles writing it to disk and reading it back from disk.
@@ -44,40 +67,76 @@
*/
private static final long MAX_TRANSACTION_AGE_MS = 24 * HOUR_IN_MILLIS;
+ private static final String XML_TAG_HIGH_LEVEL_STATE = "irs-state";
+ private static final String XML_TAG_LEDGER = "ledger";
+ private static final String XML_TAG_TARE = "tare";
+ private static final String XML_TAG_TRANSACTION = "transaction";
+ private static final String XML_TAG_USER = "user";
+
+ private static final String XML_ATTR_DELTA = "delta";
+ private static final String XML_ATTR_EVENT_ID = "eventId";
+ private static final String XML_ATTR_TAG = "tag";
+ private static final String XML_ATTR_START_TIME = "startTime";
+ private static final String XML_ATTR_END_TIME = "endTime";
+ private static final String XML_ATTR_PACKAGE_NAME = "pkgName";
+ private static final String XML_ATTR_CURRENT_BALANCE = "currentBalance";
+ private static final String XML_ATTR_USER_ID = "userId";
+ private static final String XML_ATTR_VERSION = "version";
+ private static final String XML_ATTR_LAST_RECLAMATION_TIME = "lastReclamationTime";
+
+ /** Version of the file schema. */
+ private static final int STATE_FILE_VERSION = 0;
+ /** Minimum amount of time between consecutive writes. */
+ private static final long WRITE_DELAY = 30_000L;
+
+ private final AtomicFile mStateFile;
private final InternalResourceService mIrs;
- @GuardedBy("mIrs.mLock")
+ @GuardedBy("mIrs.getLock()")
private long mLastReclamationTime;
- @GuardedBy("mIrs.mLock")
+ @GuardedBy("mIrs.getLock()")
private long mNarcsInCirculation;
- @GuardedBy("mIrs.mLock")
+ @GuardedBy("mIrs.getLock()")
private final SparseArrayMap<String, Ledger> mLedgers = new SparseArrayMap<>();
private final Runnable mCleanRunnable = this::cleanupLedgers;
+ private final Runnable mWriteRunnable = this::writeState;
Scribe(InternalResourceService irs) {
- mIrs = irs;
+ this(irs, Environment.getDataSystemDirectory());
}
- @GuardedBy("mIrs.mLock")
+ @VisibleForTesting
+ Scribe(InternalResourceService irs, File dataDir) {
+ mIrs = irs;
+
+ final File tareDir = new File(dataDir, "tare");
+ //noinspection ResultOfMethodCallIgnored
+ tareDir.mkdirs();
+ mStateFile = new AtomicFile(new File(tareDir, "state.xml"), "tare");
+ }
+
+ @GuardedBy("mIrs.getLock()")
void adjustNarcsInCirculationLocked(long delta) {
if (delta != 0) {
// No point doing any work if the change is 0.
mNarcsInCirculation += delta;
+ postWrite();
}
}
- @GuardedBy("mIrs.mLock")
+ @GuardedBy("mIrs.getLock()")
void discardLedgerLocked(final int userId, @NonNull final String pkgName) {
mLedgers.delete(userId, pkgName);
+ postWrite();
}
- @GuardedBy("mIrs.mLock")
+ @GuardedBy("mIrs.getLock()")
long getLastReclamationTimeLocked() {
return mLastReclamationTime;
}
- @GuardedBy("mIrs.mLock")
+ @GuardedBy("mIrs.getLock()")
@NonNull
Ledger getLedgerLocked(final int userId, @NonNull final String pkgName) {
Ledger ledger = mLedgers.get(userId, pkgName);
@@ -89,33 +148,107 @@
}
/** Returns the total amount of narcs currently allocated to apps. */
- @GuardedBy("mIrs.mLock")
+ @GuardedBy("mIrs.getLock()")
long getNarcsInCirculationLocked() {
return mNarcsInCirculation;
}
- @GuardedBy("mIrs.mLock")
- void setLastReclamationTimeLocked(long time) {
- mLastReclamationTime = time;
+ @GuardedBy("mIrs.getLock()")
+ void loadFromDiskLocked() {
+ mLedgers.clear();
+ mNarcsInCirculation = 0;
+ if (!recordExists()) {
+ return;
+ }
+
+ UserManagerInternal userManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+ final int[] userIds = userManagerInternal.getUserIds();
+ Arrays.sort(userIds);
+
+ try (FileInputStream fis = mStateFile.openRead()) {
+ TypedXmlPullParser parser = Xml.resolvePullParser(fis);
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.START_TAG
+ && eventType != XmlPullParser.END_DOCUMENT) {
+ eventType = parser.next();
+ }
+ if (eventType == XmlPullParser.END_DOCUMENT) {
+ if (DEBUG) {
+ Slog.w(TAG, "No persisted state.");
+ }
+ return;
+ }
+
+ String tagName = parser.getName();
+ if (XML_TAG_TARE.equals(tagName)) {
+ final int version = parser.getAttributeInt(null, XML_ATTR_VERSION);
+ if (version < 0 || version > STATE_FILE_VERSION) {
+ Slog.e(TAG, "Invalid version number (" + version + "), aborting file read");
+ return;
+ }
+ }
+
+ final long endTimeCutoff = System.currentTimeMillis() - MAX_TRANSACTION_AGE_MS;
+ long earliestEndTime = Long.MAX_VALUE;
+ for (eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
+ eventType = parser.next()) {
+ if (eventType != XmlPullParser.START_TAG) {
+ continue;
+ }
+ tagName = parser.getName();
+ if (tagName == null) {
+ continue;
+ }
+
+ switch (tagName) {
+ case XML_TAG_HIGH_LEVEL_STATE:
+ mLastReclamationTime =
+ parser.getAttributeLong(null, XML_ATTR_LAST_RECLAMATION_TIME);
+ break;
+ case XML_TAG_USER:
+ earliestEndTime = Math.min(earliestEndTime,
+ readUserFromXmlLocked(parser, userIds, endTimeCutoff));
+ break;
+ default:
+ Slog.e(TAG, "Unexpected tag: " + tagName);
+ break;
+ }
+ }
+ scheduleCleanup(earliestEndTime);
+ } catch (IOException | XmlPullParserException e) {
+ Slog.wtf(TAG, "Error reading state from disk", e);
+ }
}
- @GuardedBy("mIrs.mLock")
+ @VisibleForTesting
+ void postWrite() {
+ TareHandlerThread.getHandler().postDelayed(mWriteRunnable, WRITE_DELAY);
+ }
+
+ boolean recordExists() {
+ return mStateFile.exists();
+ }
+
+ @GuardedBy("mIrs.getLock()")
+ void setLastReclamationTimeLocked(long time) {
+ mLastReclamationTime = time;
+ postWrite();
+ }
+
+ @GuardedBy("mIrs.getLock()")
void tearDownLocked() {
+ TareHandlerThread.getHandler().removeCallbacks(mCleanRunnable);
+ TareHandlerThread.getHandler().removeCallbacks(mWriteRunnable);
mLedgers.clear();
mNarcsInCirculation = 0;
mLastReclamationTime = 0;
}
- private void scheduleCleanup(long earliestEndTime) {
- if (earliestEndTime == Long.MAX_VALUE) {
- return;
- }
- // This is just cleanup to manage memory. We don't need to do it too often or at the exact
- // intended real time, so the delay that comes from using the Handler (and is limited
- // to uptime) should be fine.
- final long delayMs = Math.max(HOUR_IN_MILLIS,
- earliestEndTime + MAX_TRANSACTION_AGE_MS - System.currentTimeMillis());
- TareHandlerThread.getHandler().postDelayed(mCleanRunnable, delayMs);
+ @VisibleForTesting
+ void writeImmediatelyForTesting() {
+ mWriteRunnable.run();
}
private void cleanupLedgers() {
@@ -139,7 +272,206 @@
}
}
- @GuardedBy("mIrs.mLock")
+ /**
+ * @param parser Xml parser at the beginning of a "<ledger/>" tag. The next "parser.next()" call
+ * will take the parser into the body of the ledger tag.
+ * @return Newly instantiated ledger holding all the information we just read out of the xml
+ * tag, and the package name associated with the ledger.
+ */
+ @Nullable
+ private static Pair<String, Ledger> readLedgerFromXml(TypedXmlPullParser parser,
+ long endTimeCutoff) throws XmlPullParserException, IOException {
+ final String pkgName;
+ final long curBalance;
+ final List<Ledger.Transaction> transactions = new ArrayList<>();
+
+ pkgName = parser.getAttributeValue(null, XML_ATTR_PACKAGE_NAME);
+ curBalance = parser.getAttributeLong(null, XML_ATTR_CURRENT_BALANCE);
+
+ for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
+ eventType = parser.next()) {
+ final String tagName = parser.getName();
+ if (eventType == XmlPullParser.END_TAG) {
+ if (XML_TAG_LEDGER.equals(tagName)) {
+ // We've reached the end of the ledger tag.
+ break;
+ }
+ continue;
+ }
+ if (eventType != XmlPullParser.START_TAG || !"transaction".equals(tagName)) {
+ // Expecting only "transaction" tags.
+ Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
+ return null;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Starting ledger tag: " + tagName);
+ }
+ final String tag = parser.getAttributeValue(null, XML_ATTR_TAG);
+ final long startTime = parser.getAttributeLong(null, XML_ATTR_START_TIME);
+ final long endTime = parser.getAttributeLong(null, XML_ATTR_END_TIME);
+ final int eventId = parser.getAttributeInt(null, XML_ATTR_EVENT_ID);
+ final long delta = parser.getAttributeLong(null, XML_ATTR_DELTA);
+ if (endTime <= endTimeCutoff) {
+ if (DEBUG) {
+ Slog.d(TAG, "Skipping event because it's too old.");
+ }
+ continue;
+ }
+ transactions.add(new Ledger.Transaction(startTime, endTime, eventId, tag, delta));
+ }
+
+ return Pair.create(pkgName, new Ledger(curBalance, transactions));
+ }
+
+ /**
+ * @param parser Xml parser at the beginning of a "<user>" tag. The next "parser.next()" call
+ * will take the parser into the body of the user tag.
+ * @return The earliest valid transaction end time found for the user.
+ */
+ @GuardedBy("mIrs.getLock()")
+ private long readUserFromXmlLocked(TypedXmlPullParser parser, int[] validUserIds,
+ long endTimeCutoff) throws XmlPullParserException, IOException {
+ int curUser = parser.getAttributeInt(null, XML_ATTR_USER_ID);
+ if (Arrays.binarySearch(validUserIds, curUser) < 0) {
+ Slog.w(TAG, "Invalid user " + curUser + " is saved to disk");
+ curUser = UserHandle.NONE;
+ // Don't return early since we need to go through all the ledger tags and get to the end
+ // of the user tag.
+ }
+ long earliestEndTime = Long.MAX_VALUE;
+
+ for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
+ eventType = parser.next()) {
+ final String tagName = parser.getName();
+ if (eventType == XmlPullParser.END_TAG) {
+ if (XML_TAG_USER.equals(tagName)) {
+ // We've reached the end of the user tag.
+ break;
+ }
+ continue;
+ }
+ if (XML_TAG_LEDGER.equals(tagName)) {
+ if (curUser == UserHandle.NONE) {
+ continue;
+ }
+ final Pair<String, Ledger> ledgerData = readLedgerFromXml(parser, endTimeCutoff);
+ final Ledger ledger = ledgerData.second;
+ if (ledger != null) {
+ mLedgers.add(curUser, ledgerData.first, ledger);
+ mNarcsInCirculation += Math.max(0, ledger.getCurrentBalance());
+ final Ledger.Transaction transaction = ledger.getEarliestTransaction();
+ if (transaction != null) {
+ earliestEndTime = Math.min(earliestEndTime, transaction.endTimeMs);
+ }
+ }
+ } else {
+ Slog.e(TAG, "Unknown tag: " + tagName);
+ }
+ }
+
+ return earliestEndTime;
+ }
+
+ private void scheduleCleanup(long earliestEndTime) {
+ if (earliestEndTime == Long.MAX_VALUE) {
+ return;
+ }
+ // This is just cleanup to manage memory. We don't need to do it too often or at the exact
+ // intended real time, so the delay that comes from using the Handler (and is limited
+ // to uptime) should be fine.
+ final long delayMs = Math.max(HOUR_IN_MILLIS,
+ earliestEndTime + MAX_TRANSACTION_AGE_MS - System.currentTimeMillis());
+ TareHandlerThread.getHandler().postDelayed(mCleanRunnable, delayMs);
+ }
+
+ private void writeState() {
+ synchronized (mIrs.getLock()) {
+ TareHandlerThread.getHandler().removeCallbacks(mWriteRunnable);
+ // Remove mCleanRunnable callbacks since we're going to clean up the ledgers before
+ // writing anyway.
+ TareHandlerThread.getHandler().removeCallbacks(mCleanRunnable);
+ if (!mIrs.isEnabled()) {
+ // If it's no longer enabled, we would have cleared all the data in memory and would
+ // accidentally write an empty file, thus deleting all the history.
+ return;
+ }
+ long earliestStoredEndTime = Long.MAX_VALUE;
+ try (FileOutputStream fos = mStateFile.startWrite()) {
+ TypedXmlSerializer out = Xml.resolveSerializer(fos);
+ out.startDocument(null, true);
+
+ out.startTag(null, XML_TAG_TARE);
+ out.attributeInt(null, XML_ATTR_VERSION, STATE_FILE_VERSION);
+
+ out.startTag(null, XML_TAG_HIGH_LEVEL_STATE);
+ out.attributeLong(null, XML_ATTR_LAST_RECLAMATION_TIME, mLastReclamationTime);
+ out.endTag(null, XML_TAG_HIGH_LEVEL_STATE);
+
+ for (int uIdx = mLedgers.numMaps() - 1; uIdx >= 0; --uIdx) {
+ final int userId = mLedgers.keyAt(uIdx);
+ earliestStoredEndTime = Math.min(earliestStoredEndTime,
+ writeUserLocked(out, userId));
+ }
+
+ out.endTag(null, XML_TAG_TARE);
+
+ out.endDocument();
+ mStateFile.finishWrite(fos);
+ } catch (IOException e) {
+ Slog.e(TAG, "Error writing state to disk", e);
+ }
+ scheduleCleanup(earliestStoredEndTime);
+ }
+ }
+
+ @GuardedBy("mIrs.getLock()")
+ private long writeUserLocked(@NonNull TypedXmlSerializer out, final int userId)
+ throws IOException {
+ final int uIdx = mLedgers.indexOfKey(userId);
+ long earliestStoredEndTime = Long.MAX_VALUE;
+
+ out.startTag(null, XML_TAG_USER);
+ out.attributeInt(null, XML_ATTR_USER_ID, userId);
+ for (int pIdx = mLedgers.numElementsForKey(userId) - 1; pIdx >= 0; --pIdx) {
+ final String pkgName = mLedgers.keyAt(uIdx, pIdx);
+ final Ledger ledger = mLedgers.get(userId, pkgName);
+ // Remove old transactions so we don't waste space storing them.
+ ledger.removeOldTransactions(MAX_TRANSACTION_AGE_MS);
+
+ out.startTag(null, XML_TAG_LEDGER);
+ out.attribute(null, XML_ATTR_PACKAGE_NAME, pkgName);
+ out.attributeLong(null,
+ XML_ATTR_CURRENT_BALANCE, ledger.getCurrentBalance());
+
+ final List<Ledger.Transaction> transactions = ledger.getTransactions();
+ for (int t = 0; t < transactions.size(); ++t) {
+ Ledger.Transaction transaction = transactions.get(t);
+ if (t == 0) {
+ earliestStoredEndTime = Math.min(earliestStoredEndTime, transaction.endTimeMs);
+ }
+ writeTransaction(out, transaction);
+ }
+ out.endTag(null, XML_TAG_LEDGER);
+ }
+ out.endTag(null, XML_TAG_USER);
+
+ return earliestStoredEndTime;
+ }
+
+ private static void writeTransaction(@NonNull TypedXmlSerializer out,
+ @NonNull Ledger.Transaction transaction) throws IOException {
+ out.startTag(null, XML_TAG_TRANSACTION);
+ out.attributeLong(null, XML_ATTR_START_TIME, transaction.startTimeMs);
+ out.attributeLong(null, XML_ATTR_END_TIME, transaction.endTimeMs);
+ out.attributeInt(null, XML_ATTR_EVENT_ID, transaction.eventId);
+ if (transaction.tag != null) {
+ out.attribute(null, XML_ATTR_TAG, transaction.tag);
+ }
+ out.attributeLong(null, XML_ATTR_DELTA, transaction.delta);
+ out.endTag(null, XML_TAG_TRANSACTION);
+ }
+
+ @GuardedBy("mIrs.getLock()")
void dumpLocked(IndentingPrintWriter pw) {
pw.println("Ledgers:");
pw.increaseIndent();
diff --git a/api/Android.bp b/api/Android.bp
index dbb81a6..7590177 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -437,7 +437,7 @@
}
genrule {
- name: "services-system-server-current.txt",
+ name: "frameworks-base-api-system-server-current.txt",
srcs: [
":service-media-s{.system-server.api.txt}",
":service-permission{.system-server.api.txt}",
@@ -464,7 +464,7 @@
}
genrule {
- name: "services-system-server-removed.txt",
+ name: "frameworks-base-api-system-server-removed.txt",
srcs: [
":service-media-s{.system-server.removed-api.txt}",
":service-permission{.system-server.removed-api.txt}",
diff --git a/core/api/current.txt b/core/api/current.txt
index bc1dc0d..cc17d0c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6257,6 +6257,7 @@
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationListenerAccessGranted(android.content.ComponentName);
method public boolean isNotificationPolicyAccessGranted();
+ method @WorkerThread public boolean matchesCallFilter(@NonNull android.net.Uri);
method public void notify(int, android.app.Notification);
method public void notify(String, int, android.app.Notification);
method public void notifyAsPackage(@NonNull String, @Nullable String, int, @NonNull android.app.Notification);
@@ -6698,13 +6699,13 @@
}
public class StatusBarManager {
- method public int requestAddTileService(@NonNull android.content.ComponentName, @NonNull CharSequence, @NonNull android.graphics.drawable.Icon, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT = 3; // 0x3
- field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE = 1; // 0x1
- field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER = 4; // 0x4
- field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS = 2; // 0x2
- field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON = 5; // 0x5
- field public static final int TILE_ADD_REQUEST_ANSWER_SUCCESS = 0; // 0x0
+ method public void requestAddTileService(@NonNull android.content.ComponentName, @NonNull CharSequence, @NonNull android.graphics.drawable.Icon, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ field public static final int TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND = 1004; // 0x3ec
+ field public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT = 1002; // 0x3ea
+ field public static final int TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE = 1000; // 0x3e8
+ field public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER = 1003; // 0x3eb
+ field public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE = 1005; // 0x3ed
+ field public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS = 1001; // 0x3e9
field public static final int TILE_ADD_REQUEST_RESULT_TILE_ADDED = 2; // 0x2
field public static final int TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED = 1; // 0x1
field public static final int TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED = 0; // 0x0
@@ -13300,6 +13301,7 @@
method public int describeContents();
method public int diff(android.content.res.Configuration);
method public boolean equals(android.content.res.Configuration);
+ method @NonNull public static android.content.res.Configuration generateDelta(@NonNull android.content.res.Configuration, @NonNull android.content.res.Configuration);
method public int getLayoutDirection();
method @NonNull public android.os.LocaleList getLocales();
method public boolean isLayoutSizeAtLeast(int);
@@ -32164,6 +32166,7 @@
field public static final String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
field public static final String DISALLOW_CAMERA_TOGGLE = "disallow_camera_toggle";
+ field public static final String DISALLOW_CHANGE_WIFI_STATE = "no_change_wifi_state";
field public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
field public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
@@ -47032,15 +47035,15 @@
}
@UiThread public interface AttachedSurfaceControl {
- method public default void addOnSurfaceTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener);
+ method public default void addOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction);
method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
- method public default int getSurfaceTransformHint();
- method public default void removeOnSurfaceTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener);
+ method public default int getBufferTransformHint();
+ method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
}
- @UiThread public static interface AttachedSurfaceControl.OnSurfaceTransformHintChangedListener {
- method public void onSurfaceTransformHintChanged(int);
+ @UiThread public static interface AttachedSurfaceControl.OnBufferTransformHintChangedListener {
+ method public void onBufferTransformHintChanged(int);
}
public final class Choreographer {
@@ -48530,6 +48533,12 @@
method public void readFromParcel(android.os.Parcel);
method public void release();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BUFFER_TRANSFORM_IDENTITY = 0; // 0x0
+ field public static final int BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 1; // 0x1
+ field public static final int BUFFER_TRANSFORM_MIRROR_VERTICAL = 2; // 0x2
+ field public static final int BUFFER_TRANSFORM_ROTATE_180 = 3; // 0x3
+ field public static final int BUFFER_TRANSFORM_ROTATE_270 = 7; // 0x7
+ field public static final int BUFFER_TRANSFORM_ROTATE_90 = 4; // 0x4
field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControl> CREATOR;
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 681949a..372ad9d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -26,6 +26,7 @@
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String MANAGE_TOAST_RATE_LIMITING = "android.permission.MANAGE_TOAST_RATE_LIMITING";
field public static final String MODIFY_REFRESH_RATE_SWITCHING_TYPE = "android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE";
+ field public static final String MODIFY_USER_PREFERRED_DISPLAY_MODE = "android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE";
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
@@ -304,10 +305,10 @@
public class NotificationManager {
method public void allowAssistantAdjustment(String);
+ method public void cleanUpCallersAfter(long);
method public void disallowAssistantAdjustment(String);
method public android.content.ComponentName getEffectsSuppressor();
method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
- method public boolean matchesCallFilter(android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean);
method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ef245c7..11a2ede 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -76,7 +76,6 @@
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -8474,9 +8473,7 @@
* the activity is visible after the screen is turned on when the lockscreen is up. In addition,
* if this flag is set and the activity calls {@link
* KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
- * the screen will turn on. If the screen is off and device is not secured, this flag can turn
- * screen on and dismiss keyguard to make this activity visible and resume, which can be used to
- * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}
+ * the screen will turn on.
*
* @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
*
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 098492c..01885b2 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -175,6 +175,7 @@
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
+ void cleanUpCallersAfter(long timeThreshold);
boolean isSystemConditionProviderEnabled(String path);
boolean isNotificationListenerAccessGranted(in ComponentName listener);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index ccf1edb..9be4adc 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.WorkerThread;
import android.app.Notification.Builder;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -1079,7 +1080,6 @@
/**
* @hide
*/
- @TestApi
public boolean matchesCallFilter(Bundle extras) {
INotificationManager service = getService();
try {
@@ -1092,6 +1092,19 @@
/**
* @hide
*/
+ @TestApi
+ public void cleanUpCallersAfter(long timeThreshold) {
+ INotificationManager service = getService();
+ try {
+ service.cleanUpCallersAfter(timeThreshold);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
public boolean isSystemConditionProviderEnabled(String path) {
INotificationManager service = getService();
try {
@@ -2544,6 +2557,46 @@
}
}
+ /**
+ * Returns whether a call from the provided URI is permitted to notify the user.
+ * <p>
+ * A true return value indicates one of the following: Do Not Disturb is not currently active;
+ * or the caller is a repeat caller and the current policy allows interruptions from repeat
+ * callers; or the caller is in the user's set of contacts whose calls are allowed to interrupt
+ * Do Not Disturb.
+ * </p>
+ * <p>
+ * If Do Not Disturb is enabled and either no interruptions or only alarms are allowed, this
+ * method will return false regardless of input.
+ * </p>
+ * <p>
+ * The provided URI must meet the requirements for a URI associated with a
+ * {@link Person}: it may be the {@code String} representation of a
+ * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, or a
+ * <code>mailto:</code> or <code>tel:</code> schema URI matching an entry in the
+ * Contacts database. See also {@link Person.Builder#setUri} and
+ * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
+ * for more information.
+ * </p>
+ * <p>
+ * NOTE: This method calls into Contacts, which may take some time, and should not be called
+ * on the main thread.
+ * </p>
+ *
+ * @param uri A URI representing a caller. Must not be null.
+ * @return A boolean indicating whether a call from the URI provided would be allowed to
+ * interrupt the user given the current filter.
+ */
+ @WorkerThread
+ public boolean matchesCallFilter(@NonNull Uri uri) {
+ Bundle extras = new Bundle();
+ ArrayList<Person> pList = new ArrayList<>();
+ pList.add(new Person.Builder().setUri(uri.toString()).build());
+ extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, pList);
+
+ return matchesCallFilter(extras);
+ }
+
/** @hide */
public static int zenModeToInterruptionFilter(int zen) {
switch (zen) {
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index ee50634..64f89bc 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -228,55 +228,59 @@
/** @hide */
public static final int TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED = 3;
- /** @hide */
- @IntDef(prefix = {"TILE_ADD_REQUEST_RESULT_"}, value = {
- TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED,
- TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED,
- TILE_ADD_REQUEST_RESULT_TILE_ADDED,
- TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RequestResult {}
-
/**
- * Indicates that the request was sent successfully. Does not indicate that the user
- * has accepted the request.
+ * Values greater or equal to this value indicate an error in the request.
*/
- public static final int TILE_ADD_REQUEST_ANSWER_SUCCESS = 0;
+ private static final int TILE_ADD_REQUEST_FIRST_ERROR_CODE = 1000;
+
/**
* Indicates that this package does not match that of the
* {@link android.service.quicksettings.TileService}.
*/
- public static final int TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE = 1;
+ public static final int TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE =
+ TILE_ADD_REQUEST_FIRST_ERROR_CODE;
/**
* Indicates that there's a request in progress for this package.
*/
- public static final int TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS = 2;
+ public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS =
+ TILE_ADD_REQUEST_FIRST_ERROR_CODE + 1;
/**
- * Indicates that the component does not match an enabled
+ * Indicates that the component does not match an enabled exported
* {@link android.service.quicksettings.TileService} for the current user.
*/
- public static final int TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT = 3;
+ public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT =
+ TILE_ADD_REQUEST_FIRST_ERROR_CODE + 2;
/**
* Indicates that the user is not the current user.
*/
- public static final int TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER = 4;
+ public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER =
+ TILE_ADD_REQUEST_FIRST_ERROR_CODE + 3;
/**
- * The request could not be processed due to an unkonwn reason.
+ * Indicates that the requesting application is not in the foreground.
*/
- public static final int TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON = 5;
+ public static final int TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND =
+ TILE_ADD_REQUEST_FIRST_ERROR_CODE + 4;
+ /**
+ * The request could not be processed because no fulfilling service was found. This could be
+ * a temporary issue (for example, SystemUI has crashed).
+ */
+ public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE =
+ TILE_ADD_REQUEST_FIRST_ERROR_CODE + 5;
/** @hide */
- @IntDef(prefix = {"TILE_ADD_REQUEST_ANSWER_"}, value = {
- TILE_ADD_REQUEST_ANSWER_SUCCESS,
- TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE,
- TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS,
- TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT,
- TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER,
- TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON
+ @IntDef(prefix = {"TILE_ADD_REQUEST"}, value = {
+ TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED,
+ TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED,
+ TILE_ADD_REQUEST_RESULT_TILE_ADDED,
+ TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE,
+ TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS,
+ TILE_ADD_REQUEST_ERROR_BAD_COMPONENT,
+ TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER,
+ TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND,
+ TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE
})
@Retention(RetentionPolicy.SOURCE)
- public @interface RequestAnswer {}
+ public @interface RequestResult {}
@UnsupportedAppUsage
private Context mContext;
@@ -618,7 +622,9 @@
* </ul>
* <p>
* The user for which this will be added is determined from the {@link Context} used to retrieve
- * this service, and must match the current user.
+ * this service, and must match the current user. The requesting application must be in the
+ * foreground ({@link ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND}
+ * and the {@link android.service.quicksettings.TileService} must be exported.
*
* @param tileServiceComponentName {@link ComponentName} of the
* {@link android.service.quicksettings.TileService} for the request.
@@ -626,12 +632,10 @@
* @param icon icon to use in the tile shown to the user.
* @param resultExecutor an executor to run the callback on
* @param resultCallback callback to indicate the {@link RequestResult}.
- * @return whether the request was successfully sent.
*
* @see android.service.quicksettings.TileService
*/
- @RequestAnswer
- public int requestAddTileService(
+ public void requestAddTileService(
@NonNull ComponentName tileServiceComponentName,
@NonNull CharSequence tileLabel,
@NonNull Icon icon,
@@ -644,14 +648,16 @@
Objects.requireNonNull(resultExecutor);
Objects.requireNonNull(resultCallback);
if (!tileServiceComponentName.getPackageName().equals(mContext.getPackageName())) {
- return TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE;
+ resultExecutor.execute(
+ () -> resultCallback.accept(TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE));
+ return;
}
int userId = mContext.getUserId();
RequestResultCallback callbackProxy = new RequestResultCallback(resultExecutor,
resultCallback);
IStatusBarService svc = getService();
try {
- return svc.requestAddTile(
+ svc.requestAddTile(
tileServiceComponentName,
tileLabel,
icon,
@@ -661,7 +667,6 @@
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
- return TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON;
}
/** @hide */
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 3ea865b..c30c933 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -199,11 +199,8 @@
*
* <p>
* <ul>
- * <li> {@link #GROUP_STATUS_IDLE} </li>
- * <li> {@link #GROUP_STATUS_STREAMING} </li>
- * <li> {@link #GROUP_STATUS_SUSPENDED} </li>
- * <li> {@link #GROUP_STATUS_RECONFIGURED} </li>
- * <li> {@link #GROUP_STATUS_DESTROYED} </li>
+ * <li> {@link #GROUP_STATUS_ACTIVE} </li>
+ * <li> {@link #GROUP_STATUS_INACTIVE} </li>
* </ul>
* <p>
* @hide
@@ -241,6 +238,19 @@
private final BluetoothAdapter mAdapter;
private final AttributionSource mAttributionSource;
+ /**
+ * Indicating that group is Active ( Audio device is available )
+ * @hide
+ */
+ public static final int GROUP_STATUS_ACTIVE = IBluetoothLeAudio.GROUP_STATUS_ACTIVE;
+
+ /**
+ * Indicating that group is Inactive ( Audio device is not available )
+ * @hide
+ */
+ public static final int GROUP_STATUS_INACTIVE = IBluetoothLeAudio.GROUP_STATUS_INACTIVE;
+
+
private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio",
IBluetoothLeAudio.class.getName()) {
@@ -433,7 +443,7 @@
* <p> This API returns false in scenarios like the profile on the
* device is not connected or Bluetooth is not turned on.
* When this API returns true, it is guaranteed that the
- * {@link #ACTION_LEAUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
+ * {@link #ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
* with the active device.
*
*
@@ -512,6 +522,30 @@
}
/**
+ * Set volume for the streaming devices
+ *
+ * @param volume volume to set
+ * @hide
+ */
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED})
+ public void setVolume(int volume) {
+ if (VDBG) log("setVolume(vol: " + volume + " )");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ service.setVolume(volume, mAttributionSource);
+ return;
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return;
+ }
+ }
+
+ /**
* Set connection policy of the profile
*
* <p> The device should already be paired.
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 67b7252..325a771 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -155,12 +155,11 @@
@SystemApi
public static final ParcelUuid HEARING_AID =
ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
- /** Placeholder until specification is released
- * @hide */
+ /** @hide */
@NonNull
@SystemApi
public static final ParcelUuid LE_AUDIO =
- ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+ ParcelUuid.fromString("0000184E-0000-1000-8000-00805F9B34FB");
/** @hide */
@NonNull
@SystemApi
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index b66f048..7deff7c 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -2620,10 +2620,10 @@
* {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member.
*
* This is fine for device configurations as no member is ever undefined.
- * {@hide}
*/
- @UnsupportedAppUsage
- public static Configuration generateDelta(Configuration base, Configuration change) {
+ @NonNull
+ public static Configuration generateDelta(
+ @NonNull Configuration base, @NonNull Configuration change) {
final Configuration delta = new Configuration();
if (base.fontScale != change.fontScale) {
delta.fontScale = change.fontScale;
diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java
index 20ca4a3..032ed7e 100644
--- a/core/java/android/hardware/camera2/CaptureFailure.java
+++ b/core/java/android/hardware/camera2/CaptureFailure.java
@@ -59,7 +59,7 @@
private final CaptureRequest mRequest;
private final int mReason;
- private final boolean mDropped;
+ private final boolean mWasImageCaptured;
private final int mSequenceId;
private final long mFrameNumber;
private final String mErrorPhysicalCameraId;
@@ -68,10 +68,11 @@
* @hide
*/
public CaptureFailure(CaptureRequest request, int reason,
- boolean dropped, int sequenceId, long frameNumber, String errorPhysicalCameraId) {
+ boolean wasImageCaptured, int sequenceId, long frameNumber,
+ String errorPhysicalCameraId) {
mRequest = request;
mReason = reason;
- mDropped = dropped;
+ mWasImageCaptured = wasImageCaptured;
mSequenceId = sequenceId;
mFrameNumber = frameNumber;
mErrorPhysicalCameraId = errorPhysicalCameraId;
@@ -141,7 +142,7 @@
* @return boolean True if the image was captured, false otherwise.
*/
public boolean wasImageCaptured() {
- return !mDropped;
+ return mWasImageCaptured;
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 8da6551..b8443fb 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -873,21 +873,19 @@
@Override
public int submitBurst(List<Request> requests, IRequestCallback callback) {
int seqId = -1;
- synchronized (mInterfaceLock) {
- try {
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
- for (Request request : requests) {
- captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
- mCameraConfigMap));
- }
- seqId = mCaptureSession.captureBurstRequests(captureRequests,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed to submit capture requests!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
+ try {
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
+ for (Request request : requests) {
+ captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
+ mCameraConfigMap));
}
+ seqId = mCaptureSession.captureBurstRequests(captureRequests,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed to submit capture requests!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
return seqId;
@@ -896,18 +894,16 @@
@Override
public int setRepeating(Request request, IRequestCallback callback) {
int seqId = -1;
- synchronized (mInterfaceLock) {
- try {
- CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
- request, mCameraConfigMap);
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed to enable repeating request!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
- }
+ try {
+ CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
+ request, mCameraConfigMap);
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed to enable repeating request!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
return seqId;
@@ -915,27 +911,23 @@
@Override
public void abortCaptures() {
- synchronized (mInterfaceLock) {
- try {
- mCaptureSession.abortCaptures();
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed during capture abort!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
- }
+ try {
+ mCaptureSession.abortCaptures();
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed during capture abort!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
}
@Override
public void stopRepeating() {
- synchronized (mInterfaceLock) {
- try {
- mCaptureSession.stopRepeating();
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed during repeating capture stop!");
- } catch (IllegalStateException e) {
- Log.e(TAG, "Capture session closed!");
- }
+ try {
+ mCaptureSession.stopRepeating();
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed during repeating capture stop!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Capture session closed!");
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 4708f3e..8864939 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1867,7 +1867,7 @@
final CaptureFailure failure = new CaptureFailure(
request,
reason,
- /*dropped*/ mayHaveBuffers,
+ mayHaveBuffers,
requestId,
frameNumber,
errorPhysicalCameraId);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c6a365e..6999e3d 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -789,11 +789,6 @@
return;
}
- if (Trace.isEnabled()) {
- Binder.enableTracing();
- } else {
- Binder.disableTracing();
- }
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService.InputMethodImpl#showSoftInput", mDumper,
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a16d2ba..43d6e47 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -270,6 +270,24 @@
public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
/**
+ * Specifies if a user is disallowed from enabling/disabling Wi-Fi.
+ *
+ * <p>This restriction can only be set by a device owner,
+ * a profile owner of an organization-owned managed profile on the parent profile.
+ * When it is set by any of these owners, it applies globally - i.e., it disables airplane mode
+ * from changing Wi-Fi state.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CHANGE_WIFI_STATE = "no_change_wifi_state";
+
+ /**
* Specifies if a user is disallowed from changing the device
* language. The default value is <code>false</code>.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cbd405e..dc6e647 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9723,6 +9723,14 @@
public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl";
/**
+ * Whether the app-level notification setting is represented by a manifest permission.
+ *
+ * @hide
+ */
+ public static final String NOTIFICATION_PERMISSION_ENABLED =
+ "notification_permission_enabled";
+
+ /**
* Comma separated list of QS tiles that have been auto-added already.
* @hide
*/
@@ -11050,75 +11058,6 @@
public static final String HDMI_CONTROL_ENABLED = "hdmi_control_enabled";
/**
- * Controls whether volume control commands via HDMI CEC are enabled. (0 = false, 1 =
- * true).
- *
- * <p>Effects on different device types:
- * <table>
- * <tr><th>HDMI CEC device type</th><th>0: disabled</th><th>1: enabled</th></tr>
- * <tr>
- * <td>TV (type: 0)</td>
- * <td>Per CEC specification.</td>
- * <td>TV changes system volume. TV no longer reacts to incoming volume changes
- * via {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio
- * Status>}.</td>
- * </tr>
- * <tr>
- * <td>Playback device (type: 4)</td>
- * <td>Device sends volume commands to TV/Audio system via {@code <User Control
- * Pressed>}</td>
- * <td>Device does not send volume commands via {@code <User Control Pressed>}.</td>
- * </tr>
- * <tr>
- * <td>Audio device (type: 5)</td>
- * <td>Full "System Audio Control" capabilities.</td>
- * <td>Audio device no longer reacts to incoming {@code <User Control Pressed>}
- * volume commands. Audio device no longer reports volume changes via {@code
- * <Report Audio Status>}.</td>
- * </tr>
- * </table>
- *
- * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged.
- *
- * @hide
- * @see android.hardware.hdmi.HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)
- */
- @Readable
- public static final String HDMI_CONTROL_VOLUME_CONTROL_ENABLED =
- "hdmi_control_volume_control_enabled";
-
- /**
- * Whether HDMI System Audio Control feature is enabled. If enabled, TV will try to turn on
- * system audio mode if there's a connected CEC-enabled AV Receiver. Then audio stream will
- * be played on AVR instead of TV spaeker. If disabled, the system audio mode will never be
- * activated.
- * @hide
- */
- @Readable
- public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED =
- "hdmi_system_audio_control_enabled";
-
- /**
- * Whether HDMI Routing Control feature is enabled. If enabled, the switch device will
- * route to the correct input source on receiving Routing Control related messages. If
- * disabled, you can only switch the input via controls on this device.
- * @hide
- */
- @Readable
- public static final String HDMI_CEC_SWITCH_ENABLED =
- "hdmi_cec_switch_enabled";
-
- /**
- * Whether TV will automatically turn on upon reception of the CEC command
- * <Text View On> or <Image View On>. (0 = false, 1 = true)
- *
- * @hide
- */
- @Readable
- public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
- "hdmi_control_auto_wakeup_enabled";
-
- /**
* Whether TV will also turn off other CEC devices when it goes to standby mode.
* (0 = false, 1 = true)
*
@@ -11129,30 +11068,6 @@
"hdmi_control_auto_device_off_enabled";
/**
- * Property to decide which devices the playback device can send a <Standby> message to
- * upon going to sleep. It additionally controls whether a playback device attempts to turn
- * on the connected Audio system when waking up. Supported values are:
- * <ul>
- * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_TV} Upon going to sleep, device
- * sends {@code <Standby>} to TV only. Upon waking up, device does not turn on the Audio
- * system via {@code <System Audio Mode Request>}.</li>
- * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM} Upon going to
- * sleep, sends {@code <Standby>} to TV and Audio system. Upon waking up, device attempts
- * to turn on the Audio system via {@code <System Audio Mode Request>}.</li>
- * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_BROADCAST} Upon going to sleep,
- * device sends {@code <Standby>} to all devices in the network. Upon waking up, device
- * attempts to turn on the Audio system via {@code <System Audio Mode Request>}.</li>
- * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_NONE} Upon going to sleep, device
- * does not send any {@code <Standby>} message. Upon waking up, device does not turn on the
- * Audio system via {@code <System Audio Mode Request>}.</li>
- * </ul>
- *
- * @hide
- */
- public static final String HDMI_CONTROL_SEND_STANDBY_ON_SLEEP =
- "hdmi_control_send_standby_on_sleep";
-
- /**
* Whether or not media is shown automatically when bypassing as a heads up.
* @hide
*/
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index b2fc9a0..69af2a5 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
+import android.hardware.HardwareBuffer;
/**
* Provides an interface to the root-Surface of a View Hierarchy or Window. This
@@ -84,41 +85,43 @@
* Note, when using ANativeWindow APIs in conjunction with a NativeActivity Surface or
* SurfaceView Surface, the buffer producer will already have access to the transform hint and
* no additional work is needed.
+ *
+ * @see HardwareBuffer
*/
- default @Surface.Rotation int getSurfaceTransformHint() {
- return Surface.ROTATION_0;
+ default @SurfaceControl.BufferTransform int getBufferTransformHint() {
+ return SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
}
/**
- * Surface transform hint change listener.
- * @see #getSurfaceTransformHint
+ * Buffer transform hint change listener.
+ * @see #getBufferTransformHint
*/
@UiThread
- interface OnSurfaceTransformHintChangedListener {
+ interface OnBufferTransformHintChangedListener {
/**
* @param hint new surface transform hint
- * @see #getSurfaceTransformHint
+ * @see #getBufferTransformHint
*/
- void onSurfaceTransformHintChanged(@Surface.Rotation int hint);
+ void onBufferTransformHintChanged(@SurfaceControl.BufferTransform int hint);
}
/**
- * Registers a surface transform hint changed listener to receive notifications about when
+ * Registers a {@link OnBufferTransformHintChangedListener} to receive notifications about when
* the transform hint changes.
*
- * @see #getSurfaceTransformHint
- * @see #removeOnSurfaceTransformHintChangedListener
+ * @see #getBufferTransformHint
+ * @see #removeOnBufferTransformHintChangedListener
*/
- default void addOnSurfaceTransformHintChangedListener(
- @NonNull OnSurfaceTransformHintChangedListener listener) {
+ default void addOnBufferTransformHintChangedListener(
+ @NonNull OnBufferTransformHintChangedListener listener) {
}
/**
- * Unregisters a surface transform hint changed listener.
+ * Unregisters a {@link OnBufferTransformHintChangedListener}.
*
- * @see #addOnSurfaceTransformHintChangedListener
+ * @see #addOnBufferTransformHintChangedListener
*/
- default void removeOnSurfaceTransformHintChangedListener(
- @NonNull OnSurfaceTransformHintChangedListener listener) {
+ default void removeOnBufferTransformHintChangedListener(
+ @NonNull OnBufferTransformHintChangedListener listener) {
}
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 1a79e4c..5be85b0 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -249,6 +249,76 @@
private static native void nativeAddTransactionCommittedListener(long nativeObject,
TransactionCommittedListener listener);
+ /**
+ * Transforms that can be applied to buffers as they are displayed to a window.
+ *
+ * Supported transforms are any combination of horizontal mirror, vertical mirror, and
+ * clock-wise 90 degree rotation, in that order. Rotations of 180 and 270 degrees are made up
+ * of those basic transforms.
+ * Mirrors {@code ANativeWindowTransform} definitions.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"BUFFER_TRANSFORM_"},
+ value = {BUFFER_TRANSFORM_IDENTITY, BUFFER_TRANSFORM_MIRROR_HORIZONTAL,
+ BUFFER_TRANSFORM_MIRROR_VERTICAL, BUFFER_TRANSFORM_ROTATE_90,
+ BUFFER_TRANSFORM_ROTATE_180, BUFFER_TRANSFORM_ROTATE_270,
+ BUFFER_TRANSFORM_MIRROR_HORIZONTAL | BUFFER_TRANSFORM_ROTATE_90,
+ BUFFER_TRANSFORM_MIRROR_VERTICAL | BUFFER_TRANSFORM_ROTATE_90})
+ public @interface BufferTransform {
+ }
+
+ /**
+ * Identity transform.
+ *
+ * These transforms that can be applied to buffers as they are displayed to a window.
+ * @see HardwareBuffer
+ *
+ * Supported transforms are any combination of horizontal mirror, vertical mirror, and
+ * clock-wise 90 degree rotation, in that order. Rotations of 180 and 270 degrees are
+ * made up of those basic transforms.
+ */
+ public static final int BUFFER_TRANSFORM_IDENTITY = 0x00;
+ /**
+ * Mirror horizontally. Can be combined with {@link #BUFFER_TRANSFORM_MIRROR_VERTICAL}
+ * and {@link #BUFFER_TRANSFORM_ROTATE_90}.
+ */
+ public static final int BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 0x01;
+ /**
+ * Mirror vertically. Can be combined with {@link #BUFFER_TRANSFORM_MIRROR_HORIZONTAL}
+ * and {@link #BUFFER_TRANSFORM_ROTATE_90}.
+ */
+ public static final int BUFFER_TRANSFORM_MIRROR_VERTICAL = 0x02;
+ /**
+ * Rotate 90 degrees clock-wise. Can be combined with {@link
+ * #BUFFER_TRANSFORM_MIRROR_HORIZONTAL} and {@link #BUFFER_TRANSFORM_MIRROR_VERTICAL}.
+ */
+ public static final int BUFFER_TRANSFORM_ROTATE_90 = 0x04;
+ /**
+ * Rotate 180 degrees clock-wise. Cannot be combined with other transforms.
+ */
+ public static final int BUFFER_TRANSFORM_ROTATE_180 =
+ BUFFER_TRANSFORM_MIRROR_HORIZONTAL | BUFFER_TRANSFORM_MIRROR_VERTICAL;
+ /**
+ * Rotate 270 degrees clock-wise. Cannot be combined with other transforms.
+ */
+ public static final int BUFFER_TRANSFORM_ROTATE_270 =
+ BUFFER_TRANSFORM_ROTATE_180 | BUFFER_TRANSFORM_ROTATE_90;
+
+ /**
+ * @hide
+ */
+ public static @BufferTransform int rotationToBufferTransform(@Surface.Rotation int rotation) {
+ switch (rotation) {
+ case Surface.ROTATION_0: return BUFFER_TRANSFORM_IDENTITY;
+ case Surface.ROTATION_90: return BUFFER_TRANSFORM_ROTATE_90;
+ case Surface.ROTATION_180: return BUFFER_TRANSFORM_ROTATE_180;
+ case Surface.ROTATION_270: return BUFFER_TRANSFORM_ROTATE_270;
+ }
+ Log.e(TAG, "Trying to convert unknown rotation=" + rotation);
+ return BUFFER_TRANSFORM_IDENTITY;
+ }
+
@Nullable
@GuardedBy("mLock")
private ArrayList<OnReparentListener> mReparentListeners;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index e8dfa9b..b5f108c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1104,7 +1104,7 @@
|| mWindowSpaceTop != mLocation[1];
final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
|| getHeight() != mScreenRect.height();
- final boolean hintChanged = (viewRoot.getSurfaceTransformHint() != mTransformHint)
+ final boolean hintChanged = (viewRoot.getBufferTransformHint() != mTransformHint)
&& mRequestedVisible;
if (creating || formatChanged || sizeChanged || visibleChanged ||
@@ -1130,7 +1130,7 @@
mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
mLastWindowVisibility = mWindowVisibility;
- mTransformHint = viewRoot.getSurfaceTransformHint();
+ mTransformHint = viewRoot.getBufferTransformHint();
mScreenRect.left = mWindowSpaceLeft;
mScreenRect.top = mWindowSpaceTop;
@@ -1362,7 +1362,7 @@
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
}
- mTransformHint = viewRoot.getSurfaceTransformHint();
+ mTransformHint = viewRoot.getBufferTransformHint();
mBlastSurfaceControl.setTransformHint(mTransformHint);
mBlastBufferQueue = new BLASTBufferQueue(name, mBlastSurfaceControl, mSurfaceWidth,
mSurfaceHeight, mFormat);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 15d5555..b9c216d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -312,7 +312,7 @@
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>();
static boolean sFirstDrawComplete = false;
- private ArrayList<OnSurfaceTransformHintChangedListener> mTransformHintListeners =
+ private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners =
new ArrayList<>();
private @Surface.Rotation int mPreviousTransformHint = Surface.ROTATION_0;
/**
@@ -7855,7 +7855,8 @@
int transformHint = mSurfaceControl.getTransformHint();
if (mPreviousTransformHint != transformHint) {
mPreviousTransformHint = transformHint;
- dispatchTransformHintChanged(transformHint);
+ dispatchTransformHintChanged(
+ SurfaceControl.rotationToBufferTransform(transformHint));
}
} else {
destroySurface();
@@ -10462,38 +10463,38 @@
}
@Override
- public @Surface.Rotation int getSurfaceTransformHint() {
- return mSurfaceControl.getTransformHint();
+ public @SurfaceControl.BufferTransform int getBufferTransformHint() {
+ return SurfaceControl.rotationToBufferTransform(mSurfaceControl.getTransformHint());
}
@Override
- public void addOnSurfaceTransformHintChangedListener(
- OnSurfaceTransformHintChangedListener listener) {
+ public void addOnBufferTransformHintChangedListener(
+ OnBufferTransformHintChangedListener listener) {
Objects.requireNonNull(listener);
if (mTransformHintListeners.contains(listener)) {
throw new IllegalArgumentException(
- "attempt to call addOnSurfaceTransformHintChangedListener() "
+ "attempt to call addOnBufferTransformHintChangedListener() "
+ "with a previously registered listener");
}
mTransformHintListeners.add(listener);
}
@Override
- public void removeOnSurfaceTransformHintChangedListener(
- OnSurfaceTransformHintChangedListener listener) {
+ public void removeOnBufferTransformHintChangedListener(
+ OnBufferTransformHintChangedListener listener) {
Objects.requireNonNull(listener);
mTransformHintListeners.remove(listener);
}
- private void dispatchTransformHintChanged(@Surface.Rotation int hint) {
+ private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) {
if (mTransformHintListeners.isEmpty()) {
return;
}
- ArrayList<OnSurfaceTransformHintChangedListener> listeners =
- (ArrayList<OnSurfaceTransformHintChangedListener>) mTransformHintListeners.clone();
+ ArrayList<OnBufferTransformHintChangedListener> listeners =
+ (ArrayList<OnBufferTransformHintChangedListener>) mTransformHintListeners.clone();
for (int i = 0; i < listeners.size(); i++) {
- OnSurfaceTransformHintChangedListener listener = listeners.get(i);
- listener.onSurfaceTransformHintChanged(hint);
+ OnBufferTransformHintChangedListener listener = listeners.get(i);
+ listener.onBufferTransformHintChanged(hint);
}
}
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index f58a07f..3db7136 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -428,15 +428,19 @@
continue;
}
mActivity.runOnUiThread(() -> {
+ ViewTranslationCallback callback = view.getViewTranslationCallback();
if (view.getViewTranslationResponse() != null
&& view.getViewTranslationResponse().equals(response)) {
- if (DEBUG) {
- Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
- + ". Ignoring.");
+ if (callback instanceof TextViewTranslationCallback) {
+ if (((TextViewTranslationCallback) callback).isShowingTranslation()) {
+ if (DEBUG) {
+ Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
+ + ". Ignoring.");
+ }
+ return;
+ }
}
- return;
}
- ViewTranslationCallback callback = view.getViewTranslationCallback();
if (callback == null) {
if (view instanceof TextView) {
// developer doesn't provide their override, we set the default TextView
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 152405b..4a78f3e 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -64,6 +64,12 @@
*/
@Override
public boolean onShowTranslation(@NonNull View view) {
+ if (mIsShowingTranslation) {
+ if (DEBUG) {
+ Log.d(TAG, view + " is already showing translated text.");
+ }
+ return false;
+ }
ViewTranslationResponse response = view.getViewTranslationResponse();
if (response == null) {
Log.e(TAG, "onShowTranslation() shouldn't be called before "
@@ -152,7 +158,7 @@
return true;
}
- boolean isShowingTranslation() {
+ public boolean isShowingTranslation() {
return mIsShowingTranslation;
}
diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
index a8003a1..d69a240 100644
--- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
@@ -20,5 +20,4 @@
void onSimSecureStateChanged(boolean simSecure);
void onInputRestrictedStateChanged(boolean inputRestricted);
void onTrustedChanged(boolean trusted);
- void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper);
}
\ No newline at end of file
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 92031b4..49c32be 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -160,5 +160,5 @@
*/
void suppressAmbientDisplay(boolean suppress);
- int requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback);
+ void requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4f8b317..612dfd0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4494,6 +4494,12 @@
<permission android:name="android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE"
android:protectionLevel="signature" />
+ <!-- Allows an application to modify the user preferred display mode.
+ @hide
+ @TestApi -->
+ <permission android:name="android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index bcbf238..368961b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -338,7 +338,7 @@
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Legt die Zoom-Stufe und -Position auf dem Display fest."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Touch-Gesten möglich"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Tippen, Wischen, Zusammenziehen und andere Touch-Gesten möglich."</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesten auf dem Fingerabdrucksensor"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesten auf dem Fingerabdrucksensor"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Erfasst Touch-Gesten auf dem Fingerabdrucksensor des Geräts."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Screenshot erstellen"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Es kann ein Screenshot des Displays erstellt werden."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 5740a61..2e8bf70 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -100,7 +100,7 @@
<string name="peerTtyModeHco" msgid="5626377160840915617">"समवयस्क व्यक्तीने TTY मोड HCO ची विनंती केली"</string>
<string name="peerTtyModeVco" msgid="572208600818270944">"समवयस्क व्यक्तीने TTY मोड VCO ची विनंती केली"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"समवयस्क व्यक्तीने TTY मोड बंद ची विनंती केली"</string>
- <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+ <string name="serviceClassVoice" msgid="2065556932043454987">"व्हॉइस"</string>
<string name="serviceClassData" msgid="4148080018967300248">"डेटा"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"फॅक्स"</string>
<string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -306,7 +306,7 @@
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"आपल्या संपर्कांवर प्रवेश"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"स्थान"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"या डिव्हाइसच्या स्थानावर प्रवेश"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgrouplab_calendar" msgid="6426860926123033230">"कॅलेंडर"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"आपल्या कॅलेंडरवर प्रवेश"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS मेसेज पाठवणे आणि पाहणे हे"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 40bd4ca..2680c31 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2790,6 +2790,9 @@
<item>com.android.inputmethod.latin</item>
</string-array>
+ <!-- Make the IME killable by the lowmemorykiller by raising its oom_score_adj. -->
+ <bool name="config_killableInputMethods">false</bool>
+
<!-- The list of classes that should be added to the notification ranking pipeline.
See {@link com.android.server.notification.NotificationSignalExtractor}
If you add a new extractor to this list make sure to update
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 86cf04e..253cd47 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2229,6 +2229,7 @@
<java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
<java-symbol type="bool" name="config_autoResetAirplaneMode" />
<java-symbol type="string" name="config_notificationAccessConfirmationActivity" />
+ <java-symbol type="bool" name="config_killableInputMethods" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 909ca39..d965351 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2371,12 +2371,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "457951957": {
- "message": "\tNot visible=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_REMOTE_ANIMATIONS",
- "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
- },
"463993897": {
"message": "Aborted waiting for drawn: %s",
"level": "WARN",
@@ -3697,6 +3691,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "2024493888": {
+ "message": "\tWallpaper of display=%s is not visible",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+ "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+ },
"2028163120": {
"message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
"level": "VERBOSE",
@@ -3721,12 +3721,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
- "2057434754": {
- "message": "\tvisible=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_REMOTE_ANIMATIONS",
- "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
- },
"2060978050": {
"message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
"level": "WARN",
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index 06f6228..194b633 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -16,7 +16,8 @@
package androidx.window.extensions.embedding;
-import android.graphics.Point;
+import static android.graphics.Matrix.MSCALE_X;
+
import android.graphics.Rect;
import android.view.Choreographer;
import android.view.RemoteAnimationTarget;
@@ -25,58 +26,151 @@
import android.view.animation.Transformation;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
/**
* Wrapper to handle the TaskFragment animation update in one {@link SurfaceControl.Transaction}.
+ *
+ * The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
*/
class TaskFragmentAnimationAdapter {
- private final Animation mAnimation;
- private final RemoteAnimationTarget mTarget;
- private final SurfaceControl mLeash;
- private final boolean mSizeChanged;
- private final Point mPosition;
- private final Transformation mTransformation = new Transformation();
- private final float[] mMatrix = new float[9];
- private final float[] mVecs = new float[4];
- private final Rect mRect = new Rect();
+ final Animation mAnimation;
+ final RemoteAnimationTarget mTarget;
+ final SurfaceControl mLeash;
+
+ final Transformation mTransformation = new Transformation();
+ final float[] mMatrix = new float[9];
private boolean mIsFirstFrame = true;
TaskFragmentAnimationAdapter(@NonNull Animation animation,
@NonNull RemoteAnimationTarget target) {
- this(animation, target, target.leash, false /* sizeChanged */, null /* position */);
+ this(animation, target, target.leash);
}
/**
- * @param sizeChanged whether the surface size needs to be changed.
+ * @param leash the surface to animate.
*/
TaskFragmentAnimationAdapter(@NonNull Animation animation,
- @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
- boolean sizeChanged, @Nullable Point position) {
+ @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash) {
mAnimation = animation;
mTarget = target;
mLeash = leash;
- mSizeChanged = sizeChanged;
- mPosition = position != null
- ? position
- : new Point(target.localBounds.left, target.localBounds.top);
}
/** Called on frame update. */
- void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
+ final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
if (mIsFirstFrame) {
t.show(mLeash);
mIsFirstFrame = false;
}
- currentPlayTime = Math.min(currentPlayTime, mAnimation.getDuration());
- mAnimation.getTransformation(currentPlayTime, mTransformation);
- mTransformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
+ // Extract the transformation to the current time.
+ mAnimation.getTransformation(Math.min(currentPlayTime, mAnimation.getDuration()),
+ mTransformation);
+ t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ onAnimationUpdateInner(t);
+ }
+
+ /** To be overridden by subclasses to adjust the animation surface change. */
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ mTransformation.getMatrix().postTranslate(
+ mTarget.localBounds.left, mTarget.localBounds.top);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
- t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ }
- if (mSizeChanged) {
+ /** Called after animation finished. */
+ final void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
+ onAnimationUpdate(t, mAnimation.getDuration());
+ }
+
+ final long getDurationHint() {
+ return mAnimation.computeDurationHint();
+ }
+
+ /**
+ * Should be used when the {@link RemoteAnimationTarget} is in split with others, and want to
+ * animate together as one. This adapter will offset the animation leash to make the animate of
+ * two windows look like a single window.
+ */
+ static class SplitAdapter extends TaskFragmentAnimationAdapter {
+ private final boolean mIsLeftHalf;
+ private final int mWholeAnimationWidth;
+
+ /**
+ * @param isLeftHalf whether this is the left half of the animation.
+ * @param wholeAnimationWidth the whole animation windows width.
+ */
+ SplitAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target,
+ boolean isLeftHalf, int wholeAnimationWidth) {
+ super(animation, target);
+ mIsLeftHalf = isLeftHalf;
+ mWholeAnimationWidth = wholeAnimationWidth;
+ if (wholeAnimationWidth == 0) {
+ throw new IllegalArgumentException("SplitAdapter must provide wholeAnimationWidth");
+ }
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ float posX = mTarget.localBounds.left;
+ final float posY = mTarget.localBounds.top;
+ // This window is half of the whole animation window. Offset left/right to make it
+ // look as one with the other half.
+ mTransformation.getMatrix().getValues(mMatrix);
+ final int targetWidth = mTarget.localBounds.width();
+ final float scaleX = mMatrix[MSCALE_X];
+ final float totalOffset = mWholeAnimationWidth * (1 - scaleX) / 2;
+ final float curOffset = targetWidth * (1 - scaleX) / 2;
+ final float offsetDiff = totalOffset - curOffset;
+ if (mIsLeftHalf) {
+ posX += offsetDiff;
+ } else {
+ posX -= offsetDiff;
+ }
+ mTransformation.getMatrix().postTranslate(posX, posY);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+ }
+ }
+
+ /**
+ * Should be used for the animation of the snapshot of a {@link RemoteAnimationTarget} that has
+ * size change.
+ */
+ static class SnapshotAdapter extends TaskFragmentAnimationAdapter {
+
+ SnapshotAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
+ // Start leash is the snapshot of the starting surface.
+ super(animation, target, target.startLeash);
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ // Snapshot should always be placed at the top left of the animation leash.
+ mTransformation.getMatrix().postTranslate(0, 0);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+ }
+ }
+
+ /**
+ * Should be used for the animation of the {@link RemoteAnimationTarget} that has size change.
+ */
+ static class BoundsChangeAdapter extends TaskFragmentAnimationAdapter {
+ private final float[] mVecs = new float[4];
+ private final Rect mRect = new Rect();
+
+ BoundsChangeAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
+ super(animation, target);
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ mTransformation.getMatrix().postTranslate(
+ mTarget.localBounds.left, mTarget.localBounds.top);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+
// The following applies an inverse scale to the clip-rect so that it crops "after" the
// scale instead of before.
mVecs[1] = mVecs[2] = 0;
@@ -92,13 +186,4 @@
t.setWindowCrop(mLeash, mRect);
}
}
-
- /** Called after animation finished. */
- void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
- onAnimationUpdate(t, mAnimation.getDuration());
- }
-
- long getDurationHint() {
- return mAnimation.computeDurationHint();
- }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
index 6579766..535dac1 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
@@ -29,7 +29,6 @@
class TaskFragmentAnimationController {
private static final String TAG = "TaskFragAnimationCtrl";
- // TODO(b/196173550) turn off when finalize
static final boolean DEBUG = false;
private final TaskFragmentOrganizer mOrganizer;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 3980d07..412559e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -23,7 +23,7 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -40,6 +40,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.BiFunction;
/** To run the TaskFragment animations. */
class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
@@ -167,42 +168,86 @@
private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
- for (RemoteAnimationTarget target : targets) {
- final Animation animation =
- mAnimationSpec.loadOpenAnimation(target.mode != MODE_CLOSING /* isEnter */);
- adapters.add(new TaskFragmentAnimationAdapter(animation, target));
- }
- return adapters;
+ return createOpenCloseAnimationAdapters(targets,
+ mAnimationSpec::loadOpenAnimation);
}
private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
+ return createOpenCloseAnimationAdapters(targets,
+ mAnimationSpec::loadCloseAnimation);
+ }
+
+ private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
+ @NonNull RemoteAnimationTarget[] targets,
+ @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
+ // We need to know if the target window is only a partial of the whole animation screen.
+ // If so, we will need to adjust it to make the whole animation screen looks like one.
+ final List<RemoteAnimationTarget> openingTargets = new ArrayList<>();
+ final List<RemoteAnimationTarget> closingTargets = new ArrayList<>();
+ final Rect openingWholeScreenBounds = new Rect();
+ final Rect closingWholeScreenBounds = new Rect();
for (RemoteAnimationTarget target : targets) {
- final Animation animation =
- mAnimationSpec.loadCloseAnimation(target.mode != MODE_CLOSING /* isEnter */);
- adapters.add(new TaskFragmentAnimationAdapter(animation, target));
+ if (target.mode != MODE_CLOSING) {
+ openingTargets.add(target);
+ openingWholeScreenBounds.union(target.localBounds);
+ } else {
+ closingTargets.add(target);
+ closingWholeScreenBounds.union(target.localBounds);
+ }
+ }
+
+ final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
+ for (RemoteAnimationTarget target : openingTargets) {
+ adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
+ openingWholeScreenBounds));
+ }
+ for (RemoteAnimationTarget target : closingTargets) {
+ adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
+ closingWholeScreenBounds));
}
return adapters;
}
+ private TaskFragmentAnimationAdapter createOpenCloseAnimationAdapter(
+ @NonNull RemoteAnimationTarget target,
+ @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
+ @NonNull Rect wholeAnimationBounds) {
+ final Animation animation = animationProvider.apply(target, wholeAnimationBounds);
+ final Rect targetBounds = target.localBounds;
+ if (targetBounds.left == wholeAnimationBounds.left
+ && targetBounds.right != wholeAnimationBounds.right) {
+ // This is the left split of the whole animation window.
+ return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
+ true /* isLeftHalf */, wholeAnimationBounds.width());
+ } else if (targetBounds.left != wholeAnimationBounds.left
+ && targetBounds.right == wholeAnimationBounds.right) {
+ // This is the right split of the whole animation window.
+ return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
+ false /* isLeftHalf */, wholeAnimationBounds.width());
+ }
+ // Open/close window that fills the whole animation.
+ return new TaskFragmentAnimationAdapter(animation, target);
+ }
+
private List<TaskFragmentAnimationAdapter> createChangeAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
for (RemoteAnimationTarget target : targets) {
if (target.startBounds != null) {
+ // This is the target with bounds change.
final Animation[] animations =
mAnimationSpec.createChangeBoundsChangeAnimations(target);
- // The snapshot surface will always be at (0, 0) of its parent.
- adapters.add(new TaskFragmentAnimationAdapter(animations[0], target,
- target.startLeash, false /* sizeChanged */, new Point(0, 0)));
- // The end surface will have size change for scaling.
- adapters.add(new TaskFragmentAnimationAdapter(animations[1], target,
- target.leash, true /* sizeChanged */, null /* position */));
+ // Adapter for the starting snapshot leash.
+ adapters.add(new TaskFragmentAnimationAdapter.SnapshotAdapter(
+ animations[0], target));
+ // Adapter for the ending bounds changed leash.
+ adapters.add(new TaskFragmentAnimationAdapter.BoundsChangeAdapter(
+ animations[1], target));
continue;
}
+ // These are the other targets that don't have bounds change in the same transition.
final Animation animation;
if (target.hasAnimatingParent) {
// No-op if it will be covered by the changing parent window.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index 11a79b2..c0908a5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -176,18 +176,28 @@
return new Animation[]{startSet, endSet};
}
- Animation loadOpenAnimation(boolean isEnter) {
- // TODO(b/196173550) We need to customize the animation to handle two open window as one.
- return mTransitionAnimation.loadDefaultAnimationAttr(isEnter
+ Animation loadOpenAnimation(@NonNull RemoteAnimationTarget target,
+ @NonNull Rect wholeAnimationBounds) {
+ final boolean isEnter = target.mode != MODE_CLOSING;
+ final Animation animation = mTransitionAnimation.loadDefaultAnimationAttr(isEnter
? R.styleable.WindowAnimation_activityOpenEnterAnimation
: R.styleable.WindowAnimation_activityOpenExitAnimation);
+ animation.initialize(target.localBounds.width(), target.localBounds.height(),
+ wholeAnimationBounds.width(), wholeAnimationBounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
}
- Animation loadCloseAnimation(boolean isEnter) {
- // TODO(b/196173550) We need to customize the animation to handle two open window as one.
- return mTransitionAnimation.loadDefaultAnimationAttr(isEnter
+ Animation loadCloseAnimation(@NonNull RemoteAnimationTarget target,
+ @NonNull Rect wholeAnimationBounds) {
+ final boolean isEnter = target.mode != MODE_CLOSING;
+ final Animation animation = mTransitionAnimation.loadDefaultAnimationAttr(isEnter
? R.styleable.WindowAnimation_activityCloseEnterAnimation
: R.styleable.WindowAnimation_activityCloseExitAnimation);
+ animation.initialize(target.localBounds.width(), target.localBounds.height(),
+ wholeAnimationBounds.width(), wholeAnimationBounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
}
private class SettingsObserver extends ContentObserver {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 8df7cbb..b191cab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -110,9 +110,9 @@
@VisibleForTesting
final ColorCache mColorCache;
- SplashscreenContentDrawer(Context context, TransactionPool pool) {
+ SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool) {
mContext = context;
- mIconProvider = new IconProvider(context);
+ mIconProvider = iconProvider;
mTransactionPool = pool;
// Initialize Splashscreen worker thread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 979bf00..bd48696 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -61,6 +61,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
@@ -123,11 +124,11 @@
* @param splashScreenExecutor The thread used to control add and remove starting window.
*/
public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
- TransactionPool pool) {
+ IconProvider iconProvider, TransactionPool pool) {
mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mSplashScreenExecutor = splashScreenExecutor;
- mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, pool);
+ mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool);
mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
mWindowManagerGlobal = WindowManagerGlobal.getInstance();
mDisplayManager.getDisplay(DEFAULT_DISPLAY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 99644f9..a86e07a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -43,6 +43,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.TriConsumer;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -85,9 +86,11 @@
private final SparseIntArray mTaskBackgroundColors = new SparseIntArray();
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
- StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) {
+ StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, IconProvider iconProvider,
+ TransactionPool pool) {
mContext = context;
- mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
+ iconProvider, pool);
mStartingWindowTypeAlgorithm = startingWindowTypeAlgorithm;
mSplashScreenExecutor = splashScreenExecutor;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index e5a8aa0..b866bf9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -69,6 +69,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -93,6 +94,8 @@
@Mock
private WindowManager mMockWindowManager;
@Mock
+ private IconProvider mIconProvider;
+ @Mock
private TransactionPool mTransactionPool;
private final Handler mTestHandler = new Handler(Looper.getMainLooper());
@@ -105,8 +108,8 @@
int mAddWindowForTask = 0;
TestStartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
- TransactionPool pool) {
- super(context, splashScreenExecutor, pool);
+ IconProvider iconProvider, TransactionPool pool) {
+ super(context, splashScreenExecutor, iconProvider, pool);
}
@Override
@@ -156,7 +159,8 @@
doNothing().when(mMockWindowManager).addView(any(), any());
mTestExecutor = new HandlerExecutor(mTestHandler);
mStartingSurfaceDrawer = spy(
- new TestStartingSurfaceDrawer(mTestContext, mTestExecutor, mTransactionPool));
+ new TestStartingSurfaceDrawer(mTestContext, mTestExecutor, mIconProvider,
+ mTransactionPool));
}
@Test
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index fea1e15..491f5f5 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -569,6 +569,7 @@
"renderthread/DrawFrameTask.cpp",
"renderthread/EglManager.cpp",
"renderthread/ReliableSurface.cpp",
+ "renderthread/RenderEffectCapabilityQuery.cpp",
"renderthread/VulkanManager.cpp",
"renderthread/VulkanSurface.cpp",
"renderthread/RenderProxy.cpp",
@@ -697,6 +698,7 @@
"tests/unit/MatrixTests.cpp",
"tests/unit/OpBufferTests.cpp",
"tests/unit/PathInterpolatorTests.cpp",
+ "tests/unit/RenderEffectCapabilityQueryTests.cpp",
"tests/unit/RenderNodeDrawableTests.cpp",
"tests/unit/RenderNodeTests.cpp",
"tests/unit/RenderPropertiesTests.cpp",
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 513ad9a..bcfe9c3 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -50,7 +50,8 @@
bool Properties::skipEmptyFrames = true;
bool Properties::useBufferAge = true;
bool Properties::enablePartialUpdates = true;
-bool Properties::enableRenderEffectCache = false;
+// Default true unless otherwise specified in RenderThread Configuration
+bool Properties::enableRenderEffectCache = true;
DebugLevel Properties::debugLevel = kDebugDisabled;
OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 383c79b..c7d7a17 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -28,6 +28,7 @@
#include "Frame.h"
#include "Properties.h"
+#include "RenderEffectCapabilityQuery.h"
#include "utils/Color.h"
#include "utils/StringUtils.h"
@@ -148,7 +149,11 @@
mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
auto* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
- Properties::enableRenderEffectCache = (strcmp(vendor, "Qualcomm") != 0);
+ auto* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ Properties::enableRenderEffectCache = supportsRenderEffectCache(
+ vendor, version);
+ ALOGV("RenderEffectCache supported %d on driver version %s",
+ Properties::enableRenderEffectCache, version);
}
EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
diff --git a/libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp b/libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp
new file mode 100644
index 0000000..a003988
--- /dev/null
+++ b/libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <utils/Log.h>
+
+bool supportsRenderEffectCache(const char* vendor, const char* version) {
+ if (strcmp(vendor, "Qualcomm") != 0) {
+ return true;
+ }
+
+ int major;
+ int minor;
+ int driverMajor;
+ int driverMinor;
+ int n = sscanf(version,"OpenGL ES %d.%d V@%d.%d",
+ &major,
+ &minor,
+ &driverMajor,
+ &driverMinor);
+ // Ensure we have parsed the vendor string properly and we have either
+ // a newer major driver version, or the minor version is rev'ed
+ // Based on b/198227600#comment5 it appears that the corresponding fix
+ // is in driver version 571.0
+ return n == 4 && driverMajor >= 571;
+}
\ No newline at end of file
diff --git a/libs/hwui/renderthread/RenderEffectCapabilityQuery.h b/libs/hwui/renderthread/RenderEffectCapabilityQuery.h
new file mode 100644
index 0000000..ea673dd
--- /dev/null
+++ b/libs/hwui/renderthread/RenderEffectCapabilityQuery.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/**
+ * Verify if the provided vendor and version supports RenderEffect caching
+ * behavior.
+ *
+ * Certain Open GL Driver implementations run into blocking scenarios
+ * with Fence::waitForever without a corresponding signal to unblock
+ * This happens during attempts to cache SkImage instances across frames
+ * especially in circumstances using RenderEffect/SkImageFilter internally.
+ * So detect the corresponding GL Vendor and driver version to determine if
+ * caching SkImage instances across frames is supported.
+ * See b/197263715 & b/193145089
+ * @param vendor Vendor of the GL driver
+ * @param version Version of the GL driver from the given vendor
+ * @return True if a RenderEffect result can be cached across frames,
+ * false otherwise
+ */
+bool supportsRenderEffectCache(const char* vendor, const char* version);
diff --git a/libs/hwui/tests/unit/EglManagerTests.cpp b/libs/hwui/tests/unit/EglManagerTests.cpp
index f7f2406..7f2e158 100644
--- a/libs/hwui/tests/unit/EglManagerTests.cpp
+++ b/libs/hwui/tests/unit/EglManagerTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include "renderthread/EglManager.h"
+#include "renderthread/RenderEffectCapabilityQuery.h"
#include "tests/common/TestContext.h"
using namespace android;
@@ -41,4 +42,17 @@
}
eglManager.destroy();
+}
+
+TEST(EglManager, verifyRenderEffectCacheSupported) {
+ EglManager eglManager;
+ eglManager.initialize();
+ auto* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ auto* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ // Make sure that EglManager initializes Properties::enableRenderEffectCache
+ // based on the given gl vendor and version within EglManager->initialize()
+ bool renderEffectCacheSupported = supportsRenderEffectCache(vendor, version);
+ EXPECT_EQ(renderEffectCacheSupported,
+ Properties::enableRenderEffectCache);
+ eglManager.destroy();
}
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp b/libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp
new file mode 100644
index 0000000..0ee6549
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include "renderthread/RenderEffectCapabilityQuery.h"
+#include "tests/common/TestContext.h"
+
+TEST(RenderEffectCapabilityQuery, testSupportedVendor) {
+ ASSERT_TRUE(supportsRenderEffectCache("Google", "OpenGL ES 1.4 V@0.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testSupportedVendorWithDifferentVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Google", "OpenGL ES 1.3 V@571.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithSupportedVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@571.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithSupportedPatchVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@571.1"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithNewerThanSupportedMajorVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@572.0"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithNewerThanSupportedMinorVersion) {
+ ASSERT_TRUE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.5 V@571.2"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithUnsupportedMajorVersion) {
+ ASSERT_FALSE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.0 V@570.1"));
+}
+
+TEST(RenderEffectCapabilityQuery, testVendorWithUnsupportedVersion) {
+ ASSERT_FALSE(supportsRenderEffectCache("Qualcomm", "OpenGL ES 1.1 V@570.0"));
+}
+
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index c4cbc2b..5f2bef7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -16,10 +16,15 @@
package com.android.settingslib.applications;
+import android.annotation.SuppressLint;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+/**
+ * A class for applying config changes and determing if doing so resulting in any "interesting"
+ * changes.
+ */
public class InterestingConfigChanges {
private final Configuration mLastConfiguration = new Configuration();
private final int mFlags;
@@ -35,6 +40,14 @@
mFlags = flags;
}
+ /**
+ * Applies the given config change and returns whether an "interesting" change happened.
+ *
+ * @param res The source of the new config to apply
+ *
+ * @return Whether interesting changes occurred
+ */
+ @SuppressLint("NewApi")
public boolean applyNewConfig(Resources res) {
int configChanges = mLastConfiguration.updateFrom(
Configuration.generateDelta(mLastConfiguration, res.getConfiguration()));
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index db6b23b..7272a66 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -69,6 +69,7 @@
// Some Hearing Aids (especially the 2nd device) needs more time to do service discovery
private static final long MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT = 15000;
private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
+ private static final long MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT = 30000;
private static final long MAX_MEDIA_PROFILE_CONNECT_DELAY = 60000;
private final Context mContext;
@@ -760,6 +761,8 @@
timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
} else if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID)) {
timeout = MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT;
+ } else if (ArrayUtils.contains(uuids, BluetoothUuid.LE_AUDIO)) {
+ timeout = MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT;
}
if (BluetoothUtils.D) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 4ac1938..cbee982 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -805,12 +805,6 @@
Settings.Global.HDMI_CONTROL_ENABLED,
GlobalSettingsProto.Hdmi.CONTROL_ENABLED);
dumpSetting(s, p,
- Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
- GlobalSettingsProto.Hdmi.SYSTEM_AUDIO_CONTROL_ENABLED);
- dumpSetting(s, p,
- Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
- GlobalSettingsProto.Hdmi.CONTROL_AUTO_WAKEUP_ENABLED);
- dumpSetting(s, p,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
GlobalSettingsProto.Hdmi.CONTROL_AUTO_DEVICE_OFF_ENABLED);
p.end(hdmiToken);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index df7bf20..3c700dc 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -299,13 +299,8 @@
Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
Settings.Global.GNSS_SATELLITE_BLOCKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
- Settings.Global.HDMI_CEC_SWITCH_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
- Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
- Settings.Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
- Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
- Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HIDDEN_API_POLICY,
Settings.Global.FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7f0c5d4..7d06620 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -460,6 +460,9 @@
<!-- Permission needed for CTS test - MatchContentFrameRateTest -->
<uses-permission android:name="android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE" />
+ <!-- Permission needed for CTS test - DefaultDisplayModeTest -->
+ <uses-permission android:name="android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE" />
+
<!-- Permissions needed for CTS test - TimeManagerTest -->
<uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
<uses-permission android:name="android.permission.SUGGEST_EXTERNAL_TIME" />
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 2765882..a3d924f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -200,10 +200,10 @@
/**
* Interpolate alpha for notifications background scrim during shade expansion.
* @param fraction Shade expansion fraction
- * @param forNotification If we want the alpha of the notification shade or the scrim.
+ * @param forUiContent If we want the alpha of the scrims, or ui that's on top of them.
*/
- public static float getNotificationScrimAlpha(float fraction, boolean forNotification) {
- if (forNotification) {
+ public static float getNotificationScrimAlpha(float fraction, boolean forUiContent) {
+ if (forUiContent) {
fraction = MathUtils.constrainedMap(0f, 1f, 0.3f, 1f, fraction);
} else {
fraction = MathUtils.constrainedMap(0f, 1f, 0f, 0.5f, fraction);
diff --git a/packages/SystemUI/docs/keyguard.md b/packages/SystemUI/docs/keyguard.md
index e3d48ae..5e7bc1c 100644
--- a/packages/SystemUI/docs/keyguard.md
+++ b/packages/SystemUI/docs/keyguard.md
@@ -8,5 +8,39 @@
Keyguard is the first screen available when turning on the device, as long as the user has not specified a security method of NONE.
+## Critical User Journeys
+
+The journeys below generally refer to Keyguard's portion of the overall flow, especially regarding use of the power button. Power button key interpretation (short press, long press, very long press, multi press) is done in [PhoneWindowManager][4], with calls to [PowerManagerService][2] to sleep or wake up, if needed.
+
+### Power On - AOD enabled or disabled
+
+Begins with the device in low power mode, with the display active for [AOD][3] or inactive. [PowerManagerService][2] can be directed to wake up on various user-configurable signals, such as lift to wake, screen taps, among others. [AOD][2], whether visibly enabled or not, handles these signals to transition AOD to full Lockscreen content. See more in [AOD][3].
+
+### Power Off
+
+An indication to power off the device most likely comes from one of two signals: the user presses the power button or the screen timeout has passed. This may [lock the device](#How-the-device-locks)
+
+#### On Lockscreen
+
+#### On Lockscreen, occluded by an activity
+
+#### Device unlocked, Keyguard has gone away
+
+### Pulsing (Incoming notifications while dozing)
+
+### How the device locks
+
+More coming
+* Screen timeout
+* Smart lock
+* Device policy
+* Power button instantly locks setting
+* Lock timeout after screen timeout setting
+
+
[1]: /frameworks/base/packages/SystemUI/docs/keyguard/bouncer.md
+[2]: /frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
+[3]: /frameworks/base/packages/SystemUI/docs/keyguard/aod.md
+[4]: /frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
+
diff --git a/packages/SystemUI/docs/keyguard/aod.md b/packages/SystemUI/docs/keyguard/aod.md
new file mode 100644
index 0000000..6d76ed55
--- /dev/null
+++ b/packages/SystemUI/docs/keyguard/aod.md
@@ -0,0 +1 @@
+# Always-on Display (AOD)
diff --git a/packages/SystemUI/docs/keyguard/bouncer.md b/packages/SystemUI/docs/keyguard/bouncer.md
index a724966..51f8516 100644
--- a/packages/SystemUI/docs/keyguard/bouncer.md
+++ b/packages/SystemUI/docs/keyguard/bouncer.md
@@ -7,9 +7,9 @@
The bouncer contains a hierarchy of controllers/views to render the user's security method and to manage the authentication attempts.
1. [KeyguardBouncer][1] - Entrypoint for managing the bouncer visibility.
- 1. [KeyguardHostViewController][2] - Intercepts media keys. Can most likely be merged with the next item.
- 1. [KeyguardSecurityContainerController][3] - Manages unlock attempt responses, one-handed use
- 1. [KeyguardSecurityViewFlipperController][4] - Based upon the [KeyguardSecurityModel#SecurityMode][5], will instantiate the required view and controller. PIN, Pattern, etc.
+ 1. [KeyguardHostViewController][2] - Intercepts media keys. Can most likely be merged with the next item.
+ 1. [KeyguardSecurityContainerController][3] - Manages unlock attempt responses, one-handed use
+ 1. [KeyguardSecurityViewFlipperController][4] - Based upon the [KeyguardSecurityModel#SecurityMode][5], will instantiate the required view and controller. PIN, Pattern, etc.
[1]: /frameworks/base/packages/SystemUI/com/android/systemui/statusbar/phone/KeyguardBouncer
[2]: /frameworks/base/packages/SystemUI/com/android/keyguard/KeyguardHostViewController
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index a03d849..757dc2e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -52,7 +52,16 @@
boolean isShowingDetail();
void closeDetail();
void animateHeaderSlidingOut();
- void setQsExpansion(float qsExpansionFraction, float headerTranslation);
+
+ /**
+ * Asks QS to update its presentation, according to {@code NotificationPanelViewController}.
+ *
+ * @param qsExpansionFraction How much each UI element in QS should be expanded (QQS to QS.)
+ * @param panelExpansionFraction Whats the expansion of the whole shade.
+ * @param headerTranslation How much we should vertically translate QS.
+ */
+ void setQsExpansion(float qsExpansionFraction, float panelExpansionFraction,
+ float headerTranslation);
void setHeaderListening(boolean listening);
void notifyCustomizeChanged();
void setContainerController(QSContainerController controller);
@@ -75,13 +84,13 @@
/**
* If QS should translate as we pull it down, or if it should be static.
*/
- void setTranslateWhileExpanding(boolean shouldTranslate);
+ void setInSplitShade(boolean shouldTranslate);
/**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full
* shade. 0.0f means we're not transitioning yet.
*/
- default void setTransitionToFullShadeAmount(float pxAmount, boolean animated) {}
+ default void setTransitionToFullShadeAmount(float pxAmount, float progress) {}
/**
* A rounded corner clipping that makes QS feel as if it were behind everything.
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
new file mode 100644
index 0000000..363a022
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ 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.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="?androidprv:attr/colorAccentPrimaryVariant"
+ android:width="1dp"/>
+ <corners android:radius="20dp"/>
+ <padding
+ android:left="16dp"
+ android:right="16dp"
+ android:top="8dp"
+ android:bottom="8dp" />
+ <solid android:color="@android:color/transparent" />
+</shape>
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index b338894..cd6bc11 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,41 +24,44 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="94dp"
+ android:layout_height="96dp"
android:gravity="start|center_vertical"
android:paddingStart="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/header_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:importantForAccessibility="no"/>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="16dp"
+ android:layout_height="match_parent"
+ android:paddingStart="16dp"
+ android:paddingTop="20dp"
+ android:paddingBottom="24dp"
+ android:paddingEnd="24dp"
android:orientation="vertical">
<TextView
android:id="@+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
+ android:gravity="center_vertical"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="20sp"/>
-
<TextView
android:id="@+id/header_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
+ android:textColor="?android:attr/textColorTertiary"
android:fontFamily="roboto-regular"
- android:textSize="14sp"/>
-
+ android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>
@@ -81,21 +84,21 @@
android:overScrollMode="never"/>
</LinearLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider"/>
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="18dp"
+ android:layout_marginEnd="24dp"
android:orientation="horizontal">
<Button
android:id="@+id/stop"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="64dp"
+ android:layout_height="36dp"
+ android:minWidth="0dp"
android:text="@string/keyboard_key_media_stop"
android:visibility="gone"/>
@@ -106,10 +109,10 @@
<Button
android:id="@+id/done"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="64dp"
- android:layout_marginEnd="0dp"
+ android:layout_height="36dp"
+ android:minWidth="0dp"
android:text="@string/inline_done_button"/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 16c03e1..a5a7efa 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -23,17 +23,20 @@
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="64dp">
+ android:layout_height="88dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="16dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="8dp">
<FrameLayout
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_gravity="center_vertical|start"
- android:layout_marginStart="16dp">
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical|start">
<ImageView
android:id="@+id/title_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_gravity="center"/>
</FrameLayout>
@@ -42,49 +45,69 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="68dp"
+ android:layout_marginStart="64dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"/>
+ android:textSize="16sp"/>
<RelativeLayout
android:id="@+id/two_line_layout"
android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_marginStart="52dp"
- android:layout_marginEnd="69dp"
- android:layout_marginTop="10dp">
+ android:layout_marginStart="48dp">
<TextView
android:id="@+id/two_line_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
- android:layout_marginEnd="15dp"
+ android:layout_marginEnd="48dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"/>
+ android:textSize="16sp"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="15dp"
- android:layout_marginBottom="7dp"
+ android:layout_marginTop="4dp"
android:layout_alignParentBottom="true"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorSecondary"
- android:textSize="12sp"
+ android:textSize="14sp"
android:fontFamily="roboto-regular"
android:visibility="gone"/>
<SeekBar
android:id="@+id/volume_seekbar"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="8dp"
style="@*android:style/Widget.DeviceDefault.SeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
+ <ImageView
+ android:id="@+id/add_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="right"
+ android:layout_marginEnd="24dp"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/ic_add"
+ android:tint="?android:attr/colorAccent"
+ />
+ <CheckBox
+ android:id="@+id/check_box"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="right"
+ android:layout_marginEnd="24dp"
+ android:layout_alignParentRight="true"
+ android:button="@drawable/ic_check_box"
+ android:visibility="gone"
+ />
</RelativeLayout>
<ProgressBar
@@ -92,47 +115,17 @@
style="@*android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="258dp"
android:layout_height="18dp"
- android:layout_marginStart="68dp"
- android:layout_marginTop="40dp"
+ android:layout_marginStart="64dp"
+ android:layout_marginTop="28dp"
android:indeterminate="true"
android:indeterminateOnly="true"
android:visibility="gone"/>
-
- <View
- android:id="@+id/end_divider"
- android:layout_width="1dp"
- android:layout_height="36dp"
- android:layout_marginEnd="68dp"
- android:layout_gravity="right|center_vertical"
- android:background="?android:attr/listDivider"
- android:visibility="gone"/>
-
- <ImageView
- android:id="@+id/add_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="right|center_vertical"
- android:layout_marginEnd="24dp"
- android:src="@drawable/ic_add"
- android:tint="?android:attr/colorAccent"
- android:visibility="gone"/>
-
- <CheckBox
- android:id="@+id/check_box"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="right|center_vertical"
- android:layout_marginEnd="24dp"
- android:button="@drawable/ic_check_box"
- android:visibility="gone"/>
</FrameLayout>
<View
android:id="@+id/bottom_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
android:layout_gravity="bottom"
android:background="?android:attr/listDivider"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index eb2d4c2..485ed67 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -848,7 +848,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"संगीत"</string>
<string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string>
- <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"कॅलेंडर"</string>
<string name="tuner_full_zen_title" msgid="5120366354224404511">"आवाज नियंत्रणांसह दर्शवा"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"व्यत्यय आणू नका"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"आवाजाच्या बटणांचा शार्टकट"</string>
diff --git a/packages/SystemUI/res/values-sw720dp-land/config.xml b/packages/SystemUI/res/values-sw720dp-land/config.xml
new file mode 100644
index 0000000..e4573c6
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp-land/config.xml
@@ -0,0 +1,35 @@
+<?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>
+ <!-- Max number of columns for quick controls area -->
+ <integer name="controls_max_columns">2</integer>
+
+ <!-- The maximum number of rows in the QuickQSPanel -->
+ <integer name="quick_qs_panel_max_rows">4</integer>
+
+ <!-- The maximum number of tiles in the QuickQSPanel -->
+ <integer name="quick_qs_panel_max_tiles">8</integer>
+
+ <!-- Whether to use the split 2-column notification shade -->
+ <bool name="config_use_split_notification_shade">true</bool>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">2</integer>
+
+ <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
+ <bool name="config_skinnyNotifsInLandscape">false</bool>
+</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/config.xml b/packages/SystemUI/res/values-sw720dp-port/config.xml
new file mode 100644
index 0000000..1225086
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp-port/config.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- The maximum number of tiles in the QuickQSPanel -->
+ <integer name="quick_qs_panel_max_tiles">6</integer>
+
+ <!-- The number of columns in the QuickSettings -->
+ <integer name="quick_settings_num_columns">3</integer>
+
+ <!-- The maximum number of rows in the QuickSettings -->
+ <integer name="quick_settings_max_rows">3</integer>
+
+</resources>
+
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index ac44251..436f8d0 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -22,14 +22,5 @@
<resources>
<integer name="status_bar_config_maxNotificationIcons">5</integer>
- <!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_tiles">6</integer>
-
- <!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">3</integer>
-
- <!-- The maximum number of rows in the QuickSettings -->
- <integer name="quick_settings_max_rows">3</integer>
-
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6f8e2f1..a108b42 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1436,10 +1436,10 @@
<!-- Output switcher panel related dimensions -->
<dimen name="media_output_dialog_list_margin">12dp</dimen>
<dimen name="media_output_dialog_list_max_height">364dp</dimen>
- <dimen name="media_output_dialog_header_album_icon_size">52dp</dimen>
- <dimen name="media_output_dialog_header_back_icon_size">36dp</dimen>
+ <dimen name="media_output_dialog_header_album_icon_size">48dp</dimen>
+ <dimen name="media_output_dialog_header_back_icon_size">32dp</dimen>
<dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
- <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
+ <dimen name="media_output_dialog_icon_corner_radius">8dp</dimen>
<dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
<!-- Distance that the full shade transition takes in order for qs to fully transition to the
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b3bdffd..1d0660e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2830,6 +2830,8 @@
<string name="controls_media_settings_button">Settings</string>
<!-- Description for media control's playing media item, including information for the media's title, the artist, and source app [CHAR LIMIT=NONE]-->
<string name="controls_media_playing_item_description"><xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> by <xliff:g id="artist_name" example="Various artists">%2$s</xliff:g> is playing from <xliff:g id="app_label" example="Spotify">%3$s</xliff:g></string>
+ <!-- Content description for media cotnrols progress bar [CHAR_LIMIT=NONE] -->
+ <string name="controls_media_seekbar_description"><xliff:g id="elapsed_time" example="1:30">%1$s</xliff:g> of <xliff:g id="total_time" example="3:00">%2$s</xliff:g></string>
<!-- Title for Smartspace recommendation card within media controls. The "Play" means the action to play a media [CHAR_LIMIT=10] -->
<string name="controls_media_smartspace_rec_title">Play</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 6ca368c..761e3db 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -513,6 +513,10 @@
<item name="android:background">@drawable/btn_borderless_rect</item>
</style>
+ <style name="MediaOutputRoundedOutlinedButton" parent="@android:style/Widget.Material.Button">
+ <item name="android:background">@drawable/media_output_dialog_button_background</item>
+ </style>
+
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="android:windowActionBar">false</item>
<item name="preferenceTheme">@style/TunerPreferenceTheme</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5969e92..24f3673 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -277,7 +277,6 @@
private boolean mBouncer; // true if bouncerIsOrWillBeShowing
private boolean mAuthInterruptActive;
private boolean mNeedsSlowUnlockTransition;
- private boolean mHasLockscreenWallpaper;
private boolean mAssistantVisible;
private boolean mKeyguardOccluded;
private boolean mOccludingAppRequestingFp;
@@ -2579,31 +2578,6 @@
}
/**
- * Update the state whether Keyguard currently has a lockscreen wallpaper.
- *
- * @param hasLockscreenWallpaper Whether Keyguard has a lockscreen wallpaper.
- */
- public void setHasLockscreenWallpaper(boolean hasLockscreenWallpaper) {
- Assert.isMainThread();
- if (hasLockscreenWallpaper != mHasLockscreenWallpaper) {
- mHasLockscreenWallpaper = hasLockscreenWallpaper;
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onHasLockscreenWallpaperChanged(hasLockscreenWallpaper);
- }
- }
- }
- }
-
- /**
- * @return Whether Keyguard has a lockscreen wallpaper.
- */
- public boolean hasLockscreenWallpaper() {
- return mHasLockscreenWallpaper;
- }
-
- /**
* Handle {@link #MSG_DPM_STATE_CHANGED}
*/
private void handleDevicePolicyManagerStateChanged(int userId) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 6aa7aaa..e970a86 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -292,11 +292,6 @@
public void onStrongAuthStateChanged(int userId) { }
/**
- * Called when the state whether we have a lockscreen wallpaper has changed.
- */
- public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { }
-
- /**
* Called when the dream's window state is changed.
* @param dreaming true if the dream's window has been created and is visible
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8cfd225..9aa03a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -265,7 +265,7 @@
boolean wasShowingUnlockIcon = mShowUnlockIcon;
mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen()
&& (!mUdfpsEnrolled || !mRunningFPS);
- mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
+ mShowUnlockIcon = (mCanDismissLockScreen || mUserUnlockedWithBiometric) && isLockScreen();
mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS;
final CharSequence prevContentDescription = mView.getContentDescription();
@@ -477,13 +477,15 @@
@Override
public void onBiometricRunningStateChanged(boolean running,
BiometricSourceType biometricSourceType) {
+ final boolean wasRunningFps = mRunningFPS;
+ final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
mUserUnlockedWithBiometric =
mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
KeyguardUpdateMonitor.getCurrentUser());
if (biometricSourceType == FINGERPRINT) {
mRunningFPS = running;
- if (!mRunningFPS) {
+ if (wasRunningFps && !mRunningFPS) {
if (mCancelDelayedUpdateVisibilityRunnable != null) {
mCancelDelayedUpdateVisibilityRunnable.run();
}
@@ -493,10 +495,14 @@
// button in this case, so we delay updating the visibility by 50ms.
mCancelDelayedUpdateVisibilityRunnable =
mExecutor.executeDelayed(() -> updateVisibility(), 50);
- } else {
- updateVisibility();
+ return;
}
}
+
+ if (wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric
+ || wasRunningFps != mRunningFPS) {
+ updateVisibility();
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 5265718..7813840 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -670,13 +670,6 @@
}
}
}
-
- @Override
- public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) {
- synchronized (KeyguardViewMediator.this) {
- notifyHasLockscreenWallpaperChanged(hasLockscreenWallpaper);
- }
- }
};
ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
@@ -2873,21 +2866,6 @@
}
}
- private void notifyHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) {
- int size = mKeyguardStateCallbacks.size();
- for (int i = size - 1; i >= 0; i--) {
- try {
- mKeyguardStateCallbacks.get(i).onHasLockscreenWallpaperChanged(
- hasLockscreenWallpaper);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to call onHasLockscreenWallpaperChanged", e);
- if (e instanceof DeadObjectException) {
- mKeyguardStateCallbacks.remove(i);
- }
- }
- }
- }
-
public void addStateMonitorCallback(IKeyguardStateCallback callback) {
synchronized (this) {
mKeyguardStateCallbacks.add(callback);
@@ -2897,7 +2875,6 @@
callback.onInputRestrictedStateChanged(mInputRestricted);
callback.onTrustedChanged(mUpdateMonitor.getUserHasTrust(
KeyguardUpdateMonitor.getCurrentUser()));
- callback.onHasLockscreenWallpaperChanged(mUpdateMonitor.hasLockscreenWallpaper());
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call to IKeyguardStateCallback", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 424f801..e73eb66 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -55,6 +55,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
@@ -119,6 +120,7 @@
private int mSmartspaceMediaItemsCount;
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
+ private final FalsingManager mFalsingManager;
/**
* Initialize a new control panel
@@ -131,7 +133,8 @@
ActivityStarter activityStarter, MediaViewController mediaViewController,
SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
KeyguardDismissUtil keyguardDismissUtil, MediaOutputDialogFactory
- mediaOutputDialogFactory, MediaCarouselController mediaCarouselController) {
+ mediaOutputDialogFactory, MediaCarouselController mediaCarouselController,
+ FalsingManager falsingManager) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
@@ -141,6 +144,7 @@
mKeyguardDismissUtil = keyguardDismissUtil;
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
+ mFalsingManager = falsingManager;
loadDimens();
mSeekBarViewModel.setLogSmartspaceClick(() -> {
@@ -235,10 +239,14 @@
}
});
mPlayerViewHolder.getCancel().setOnClickListener(v -> {
- closeGuts();
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ closeGuts();
+ }
});
mPlayerViewHolder.getSettings().setOnClickListener(v -> {
- mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ }
});
}
@@ -259,10 +267,14 @@
}
});
mRecommendationViewHolder.getCancel().setOnClickListener(v -> {
- closeGuts();
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ closeGuts();
+ }
});
mRecommendationViewHolder.getSettings().setOnClickListener(v -> {
- mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ }
});
}
@@ -299,6 +311,7 @@
PendingIntent clickIntent = data.getClickIntent();
if (clickIntent != null) {
mPlayerViewHolder.getPlayer().setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
if (mMediaViewController.isGutsVisible()) return;
logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
@@ -365,8 +378,12 @@
setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
seamlessView.setOnClickListener(
- v -> mMediaOutputDialogFactory.create(data.getPackageName(), true,
- mPlayerViewHolder.getSeamlessButton()));
+ v -> {
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ mMediaOutputDialogFactory.create(data.getPackageName(), true,
+ mPlayerViewHolder.getSeamlessButton());
+ }
+ });
ImageView iconView = mPlayerViewHolder.getSeamlessIcon();
TextView deviceName = mPlayerViewHolder.getSeamlessText();
@@ -417,9 +434,11 @@
} else {
button.setEnabled(true);
button.setOnClickListener(v -> {
- logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
- /* isRecommendationCard */ false);
- action.run();
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+ /* isRecommendationCard */ false);
+ action.run();
+ }
});
}
boolean visibleInCompat = actionsWhenCollapsed.contains(i);
@@ -451,6 +470,8 @@
mPlayerViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
mPlayerViewHolder.getDismiss().setEnabled(isDismissible);
mPlayerViewHolder.getDismiss().setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
/* isRecommendationCard */ false);
@@ -633,6 +654,8 @@
mSmartspaceMediaItemsCount = uiComponentIndex;
// Set up long press to show guts setting panel.
mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
/* isRecommendationCard */ true);
closeGuts();
@@ -788,6 +811,8 @@
}
view.setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
/* isRecommendationCard */ true,
interactedSubcardRank,
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index f17ad6f..33ef19a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -50,6 +50,7 @@
holder.seekBar.setProgress(0)
holder.elapsedTimeView.setText("")
holder.totalTimeView.setText("")
+ holder.seekBar.contentDescription = ""
return
}
@@ -61,16 +62,22 @@
setVerticalPadding(seekBarEnabledVerticalPadding)
}
- data.duration?.let {
- holder.seekBar.setMax(it)
- holder.totalTimeView.setText(DateUtils.formatElapsedTime(
- it / DateUtils.SECOND_IN_MILLIS))
- }
+ holder.seekBar.setMax(data.duration)
+ val totalTimeString = DateUtils.formatElapsedTime(
+ data.duration / DateUtils.SECOND_IN_MILLIS)
+ holder.totalTimeView.setText(totalTimeString)
data.elapsedTime?.let {
holder.seekBar.setProgress(it)
- holder.elapsedTimeView.setText(DateUtils.formatElapsedTime(
- it / DateUtils.SECOND_IN_MILLIS))
+ val elapsedTimeString = DateUtils.formatElapsedTime(
+ it / DateUtils.SECOND_IN_MILLIS)
+ holder.elapsedTimeView.setText(elapsedTimeString)
+
+ holder.seekBar.contentDescription = holder.seekBar.context.getString(
+ R.string.controls_media_seekbar_description,
+ elapsedTimeString,
+ totalTimeString
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index d1b6548..125b87b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -135,14 +135,11 @@
if (currentlyConnected && mController.isActiveRemoteDevice(device)
&& mController.getSelectableMediaDevice().size() > 0) {
// Init active device layout
- mDivider.setVisibility(View.VISIBLE);
- mDivider.setTransitionAlpha(1);
mAddIcon.setVisibility(View.VISIBLE);
mAddIcon.setTransitionAlpha(1);
mAddIcon.setOnClickListener(this::onEndItemClick);
} else {
// Init non-active device layout
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
}
if (mCurrentActivePosition == position) {
@@ -181,7 +178,6 @@
super.onBind(customizedItem, topMargin, bottomMargin);
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
mCheckBox.setVisibility(View.GONE);
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
mBottomDivider.setVisibility(View.GONE);
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
@@ -196,13 +192,10 @@
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.GONE);
if (mController.getSelectableMediaDevice().size() > 0) {
- mDivider.setVisibility(View.VISIBLE);
- mDivider.setTransitionAlpha(1);
mAddIcon.setVisibility(View.VISIBLE);
mAddIcon.setTransitionAlpha(1);
mAddIcon.setOnClickListener(this::onEndItemClick);
} else {
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
}
mTitleIcon.setImageDrawable(getSpeakerDrawable());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 0890841..1ffc2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -121,7 +121,6 @@
final ProgressBar mProgressBar;
final SeekBar mSeekBar;
final RelativeLayout mTwoLineLayout;
- final View mDivider;
final View mBottomDivider;
final CheckBox mCheckBox;
private String mDeviceId;
@@ -136,7 +135,6 @@
mTitleIcon = view.requireViewById(R.id.title_icon);
mProgressBar = view.requireViewById(R.id.volume_indeterminate_progress);
mSeekBar = view.requireViewById(R.id.volume_seekbar);
- mDivider = view.requireViewById(R.id.end_divider);
mBottomDivider = view.requireViewById(R.id.bottom_divider);
mAddIcon = view.requireViewById(R.id.add_icon);
mCheckBox = view.requireViewById(R.id.check_box);
@@ -151,21 +149,12 @@
return;
}
mTitleIcon.setImageIcon(icon);
- setMargin(topMargin, bottomMargin);
});
});
}
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
- setMargin(topMargin, bottomMargin);
- }
-
- private void setMargin(boolean topMargin, boolean bottomMargin) {
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mContainerLayout
- .getLayoutParams();
- params.topMargin = topMargin ? mMargin : 0;
- params.bottomMargin = bottomMargin ? mMargin : 0;
- mContainerLayout.setLayoutParams(params);
+ // TODO (b/201718621): clean up method after adjustment
}
void setSingleLineLayout(CharSequence title, boolean bFocused) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 85d0802..6895ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -175,7 +175,7 @@
}
if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {
int currentActivePosition = mAdapter.getCurrentActivePosition();
- if (currentActivePosition >= 0) {
+ if (currentActivePosition >= 0 && currentActivePosition < mAdapter.getItemCount()) {
mAdapter.notifyItemChanged(currentActivePosition);
} else {
mAdapter.notifyDataSetChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 437a0c8..42dd886 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -73,6 +73,7 @@
private final String mPackageName;
private final Context mContext;
private final MediaSessionManager mMediaSessionManager;
+ private final LocalBluetoothManager mLocalBluetoothManager;
private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -85,7 +86,6 @@
private MediaController mMediaController;
@VisibleForTesting
Callback mCallback;
- Callback mPreviousCallback;
@VisibleForTesting
LocalMediaManager mLocalMediaManager;
@@ -101,6 +101,7 @@
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
+ mLocalBluetoothManager = lbm;
mShadeController = shadeController;
mActivityStarter = starter;
mAboveStatusbar = aboveStatusbar;
@@ -135,19 +136,7 @@
}
return;
}
-
- if (mPreviousCallback != null) {
- Log.w(TAG,
- "Callback started when mPreviousCallback is not null, which is unexpected");
- mPreviousCallback.dismissDialog();
- }
-
- // If we start the output group dialog when the output dialog is shown, we need to keep a
- // reference to the output dialog to set it back as the callback once we dismiss the output
- // group dialog.
- mPreviousCallback = mCallback;
mCallback = cb;
-
mLocalMediaManager.unregisterCallback(this);
mLocalMediaManager.stopScan();
mLocalMediaManager.registerCallback(this);
@@ -163,15 +152,6 @@
mLocalMediaManager.stopScan();
}
mMediaDevices.clear();
-
- // If there was a previous callback, i.e. we just dismissed the output group dialog and are
- // now back on the output dialog, then we reset the callback to its previous value.
- mCallback = null;
- Callback previous = mPreviousCallback;
- mPreviousCallback = null;
- if (previous != null) {
- start(previous);
- }
}
@Override
@@ -480,7 +460,11 @@
void launchMediaOutputGroupDialog(View mediaOutputDialog) {
// We show the output group dialog from the output dialog.
- MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar, this);
+ MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
+ mAboveStatusbar, mMediaSessionManager, mLocalBluetoothManager, mShadeController,
+ mActivityStarter, mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar,
+ controller);
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index 968c350..11d76db 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -96,7 +96,6 @@
@Override
void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
super.onBind(device, topMargin, bottomMargin, position);
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.VISIBLE);
@@ -135,7 +134,6 @@
mTitleIcon.setImageDrawable(getSpeakerDrawable());
mBottomDivider.setVisibility(View.VISIBLE);
mCheckBox.setVisibility(View.GONE);
- mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
initSessionSeekbar();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index bfb63ea..90d3448 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -35,7 +35,6 @@
import com.android.systemui.qs.TouchAnimator.Listener;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.tileimpl.HeightOverrideable;
-import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.wm.shell.animation.Interpolators;
@@ -170,19 +169,6 @@
}
}
- void startAlphaAnimation(boolean show) {
- if (show == mToShowing) {
- return;
- }
- mToShowing = show;
- if (show) {
- CrossFadeHelper.fadeIn(mQs.getView(), QQS_FADE_IN_DURATION, 0 /* delay */);
- } else {
- CrossFadeHelper.fadeOut(mQs.getView(), QQS_FADE_OUT_DURATION, 0 /* delay */,
- null /* endRunnable */);
- }
- }
-
/**
* Sets whether or not the keyguard is currently being shown with a collapsed header.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index ad3135e..17c2fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -90,6 +90,7 @@
private int mLayoutDirection;
private QSFooter mFooter;
private float mLastQSExpansion = -1;
+ private float mLastPanelFraction;
private boolean mQsDisabled;
private ImageView mQsDragHandler;
@@ -121,7 +122,7 @@
* When true, QS will translate from outside the screen. It will be clipped with parallax
* otherwise.
*/
- private boolean mTranslateWhileExpanding;
+ private boolean mInSplitShade;
private boolean mPulseExpanding;
/**
@@ -136,6 +137,12 @@
private DumpManager mDumpManager;
+ /**
+ * Progress of pull down from the center of the lock screen.
+ * @see com.android.systemui.statusbar.LockscreenShadeTransitionController
+ */
+ private float mFullShadeProgress;
+
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
InjectionInflationController injectionInflater, QSTileHost qsTileHost,
@@ -227,7 +234,8 @@
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
boolean sizeChanged = (oldTop - oldBottom) != (top - bottom);
if (sizeChanged) {
- setQsExpansion(mLastQSExpansion, mLastHeaderTranslation);
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction,
+ mLastHeaderTranslation);
}
});
mQSPanelController.setUsingHorizontalLayoutChangeListener(
@@ -409,7 +417,7 @@
mQSAnimator.setShowCollapsedOnKeyguard(showCollapsed);
}
if (!showCollapsed && isKeyguardState()) {
- setQsExpansion(mLastQSExpansion, 0);
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction, 0);
}
}
}
@@ -477,33 +485,30 @@
}
@Override
- public void setTranslateWhileExpanding(boolean shouldTranslate) {
- mTranslateWhileExpanding = shouldTranslate;
- mQSAnimator.setTranslateWhileExpanding(shouldTranslate);
+ public void setInSplitShade(boolean inSplitShade) {
+ mInSplitShade = inSplitShade;
+ mQSAnimator.setTranslateWhileExpanding(inSplitShade);
}
@Override
- public void setTransitionToFullShadeAmount(float pxAmount, boolean animated) {
+ public void setTransitionToFullShadeAmount(float pxAmount, float progress) {
boolean isTransitioningToFullShade = pxAmount > 0;
if (isTransitioningToFullShade != mTransitioningToFullShade) {
mTransitioningToFullShade = isTransitioningToFullShade;
updateShowCollapsedOnKeyguard();
- setQsExpansion(mLastQSExpansion, mLastHeaderTranslation);
}
+ mFullShadeProgress = progress;
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation);
}
@Override
- public void setQsExpansion(float expansion, float proposedTranslation) {
- if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + proposedTranslation);
+ public void setQsExpansion(float expansion, float panelExpansionFraction,
+ float proposedTranslation) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
- if (mQSAnimator != null) {
- final boolean showQSOnLockscreen = expansion > 0;
- final boolean showQSUnlocked = headerTranslation == 0 || !mTranslateWhileExpanding;
- mQSAnimator.startAlphaAnimation(showQSOnLockscreen || showQSUnlocked
- || mTransitioningToFullShade);
- }
+ float progress = mTransitioningToFullShade ? mFullShadeProgress : panelExpansionFraction;
+ setAlphaAnimationProgress(mInSplitShade ? progress : 1);
mContainer.setExpansion(expansion);
- final float translationScaleY = (mTranslateWhileExpanding
+ final float translationScaleY = (mInSplitShade
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
boolean onKeyguardAndExpanded = isKeyguardState() && !mShowCollapsedOnKeyguard;
if (!mHeaderAnimating && !headerWillBeAnimating()) {
@@ -520,6 +525,7 @@
return;
}
mLastHeaderTranslation = headerTranslation;
+ mLastPanelFraction = panelExpansionFraction;
mLastQSExpansion = expansion;
mLastKeyguardAndExpanded = onKeyguardAndExpanded;
mLastViewHeight = currentHeight;
@@ -561,6 +567,17 @@
updateMediaPositions();
}
+ private void setAlphaAnimationProgress(float progress) {
+ final View view = getView();
+ if (progress == 0 && view.getVisibility() != View.INVISIBLE) {
+ view.setVisibility(View.INVISIBLE);
+ } else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
+ view.setVisibility((View.VISIBLE));
+ }
+ float alpha = Interpolators.getNotificationScrimAlpha(progress, true /* uiContent */);
+ view.setAlpha(alpha);
+ }
+
private void updateQsBounds() {
if (mLastQSExpansion == 1.0f) {
// Fully expanded, let's set the layout bounds as clip bounds. This is necessary because
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
index fe1a619..3b85e5d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
@@ -52,7 +52,7 @@
internal const val DONT_ADD_TILE = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED
internal const val TILE_ALREADY_ADDED =
StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED
- internal const val DISMISSED = 3
+ internal const val DISMISSED = StatusBarManager.TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED
}
private val commandQueueCallback = object : CommandQueue.Callbacks {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 8a39719..4f932a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -819,12 +819,15 @@
}
}
- private void showTryFingerprintMsg(String a11yString) {
+ private void showTryFingerprintMsg(int msgId, String a11yString) {
if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
// if udfps available, there will always be a tappable affordance to unlock
// For example, the lock icon
if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) {
showTransientIndication(R.string.keyguard_unlock_press);
+ } else if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
+ // since face is locked out, simply show "try fingerprint"
+ showTransientIndication(R.string.keyguard_try_fingerprint);
} else {
showTransientIndication(R.string.keyguard_face_failed_use_fp);
}
@@ -916,7 +919,7 @@
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
if (biometricSourceType == BiometricSourceType.FACE
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
- showTryFingerprintMsg(helpString);
+ showTryFingerprintMsg(msgId, helpString);
return;
}
showTransientIndication(helpString, false /* isError */, showActionToUnlock);
@@ -936,7 +939,7 @@
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()
&& !mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isScreenOn()) {
- showTryFingerprintMsg(errString);
+ showTryFingerprintMsg(msgId, errString);
return;
}
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -945,7 +948,7 @@
if (!mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isUdfpsEnrolled()
&& mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
- showTryFingerprintMsg(errString);
+ showTryFingerprintMsg(msgId, errString);
} else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
mStatusBarKeyguardViewManager.showBouncerMessage(
mContext.getResources().getString(R.string.keyguard_unlock_press),
@@ -989,8 +992,8 @@
private boolean shouldSuppressFaceMsgAndShowTryFingerprintMsg() {
// For dual biometric, don't show face auth messages
return mKeyguardUpdateMonitor.isFingerprintDetectionRunning()
- && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- true /* isStrongBiometric */);
+ && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ true /* isStrongBiometric */);
}
private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 03d8e7e..77e329f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -208,6 +208,11 @@
lateinit var isScrimOpaqueChangedListener: Consumer<Boolean>
/**
+ * A runnable to call when the scrim has been fully revealed. This is only invoked once
+ */
+ var fullyRevealedRunnable: Runnable? = null
+
+ /**
* How much of the underlying views are revealed, in percent. 0 means they will be completely
* obscured and 1 means they'll be fully visible.
*/
@@ -218,10 +223,20 @@
revealEffect.setRevealAmountOnScrim(value, this)
updateScrimOpaque()
+ maybeTriggerFullyRevealedRunnable()
invalidate()
}
}
+ private fun maybeTriggerFullyRevealedRunnable() {
+ if (revealAmount == 1.0f) {
+ fullyRevealedRunnable?.let {
+ it.run()
+ fullyRevealedRunnable = null
+ }
+ }
+ }
+
/**
* The [LightRevealEffect] used to manipulate the radial gradient whenever [revealAmount]
* changes.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index ca18b07..dca7f70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -298,9 +298,8 @@
nsslController.setTransitionToFullShadeAmount(field)
notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */)
- // TODO: appear qs also in split shade
- val qsAmount = if (useSplitShade) 0f else field
- qS.setTransitionToFullShadeAmount(qsAmount, false /* animate */)
+ val progress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
+ qS.setTransitionToFullShadeAmount(field, progress)
// TODO: appear media also in split shade
val mediaAmount = if (useSplitShade) 0f else field
mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 7aa2dc7..d4f54e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -36,7 +36,6 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
-import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.phone.ScrimController
@@ -73,6 +72,10 @@
private const val TAG = "DepthController"
}
+ /**
+ * Did we already unblur while dozing?
+ */
+ private var alreadyUnblurredWhileDozing = false
lateinit var root: View
private var blurRoot: View? = null
private var keyguardAnimator: Animator? = null
@@ -229,9 +232,11 @@
private val keyguardStateCallback = object : KeyguardStateController.Callback {
override fun onKeyguardFadingAwayChanged() {
if (!keyguardStateController.isKeyguardFadingAway ||
- biometricUnlockController.mode != MODE_WAKE_AND_UNLOCK) {
+ !biometricUnlockController.isWakeAndUnlock) {
return
}
+ // When wakeAndUnlocking the screen remains dozing, so we have to manually trigger
+ // the unblur earlier
keyguardAnimator?.cancel()
keyguardAnimator = ValueAnimator.ofFloat(1f, 0f).apply {
@@ -253,6 +258,7 @@
})
start()
}
+ alreadyUnblurredWhileDozing = statusBarStateController.dozeAmount != 0.0f
}
override fun onKeyguardShowingChanged() {
@@ -274,10 +280,24 @@
if (isDozing) {
shadeAnimation.finishIfRunning()
brightnessMirrorSpring.finishIfRunning()
+
+ // unset this for safety, to be ready for the next wakeup
+ alreadyUnblurredWhileDozing = false
}
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
+ if (alreadyUnblurredWhileDozing) {
+ if (linear == 0.0f) {
+ // We finished waking up, let's reset
+ alreadyUnblurredWhileDozing = false
+ } else {
+ // We've already handled the unbluring from the keyguardAnimator above.
+ // if we would continue, we'd play another unzoom / blur animation from the
+ // dozing changing.
+ return
+ }
+ }
wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased)
scheduleUpdate()
}
@@ -435,6 +455,7 @@
it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch")
it.println("qsPanelExpansion: $qsPanelExpansion")
it.println("transitionToFullShadeProgress: $transitionToFullShadeProgress")
+ it.println("alreadyUnblurredWhileDozing: $alreadyUnblurredWhileDozing")
it.println("lastAppliedBlur: $lastAppliedBlur")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 0352212..452e737 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -69,6 +69,7 @@
import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
+import com.android.systemui.statusbar.phone.ongoingcall.SwipeStatusBarAwayGestureHandler;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -255,15 +256,29 @@
IActivityManager iActivityManager,
OngoingCallLogger logger,
DumpManager dumpManager,
- StatusBarWindowController statusBarWindowController) {
+ StatusBarWindowController statusBarWindowController,
+ SwipeStatusBarAwayGestureHandler swipeStatusBarAwayGestureHandler) {
Optional<StatusBarWindowController> windowController =
featureFlags.isOngoingCallInImmersiveEnabled()
? Optional.of(statusBarWindowController)
: Optional.empty();
+ Optional<SwipeStatusBarAwayGestureHandler> gestureHandler =
+ featureFlags.isOngoingCallInImmersiveEnabled()
+ ? Optional.of(swipeStatusBarAwayGestureHandler)
+ : Optional.empty();
OngoingCallController ongoingCallController =
new OngoingCallController(
- notifCollection, featureFlags, systemClock, activityStarter, mainExecutor,
- iActivityManager, logger, dumpManager, windowController);
+ notifCollection,
+ featureFlags,
+ systemClock,
+ activityStarter,
+ mainExecutor,
+ iActivityManager,
+ logger,
+ dumpManager,
+ windowController,
+ gestureHandler
+ );
ongoingCallController.init();
return ongoingCallController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 78fcd82..2a13e6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -119,7 +119,6 @@
LoaderResult result = loadBitmap(mCurrentUserId, mSelectedUser);
if (result.success) {
mCached = true;
- mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
mCache = result.bitmap;
}
return mCache;
@@ -235,7 +234,6 @@
if (result.success) {
mCached = true;
mCache = result.bitmap;
- mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
mMediaManager.updateMediaMetaData(
true /* metaDataChanged */, true /* allowEnterAnimation */);
}
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 c34e7ff..d09a89e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -1091,7 +1091,7 @@
Utils.shouldUseSplitNotificationShade(mResources);
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
if (mQs != null) {
- mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
+ mQs.setInSplitShade(mShouldUseSplitNotificationShade);
}
int topMargin = mShouldUseSplitNotificationShade ? mSplitShadeStatusBarHeight :
@@ -2344,7 +2344,7 @@
private void updateQsExpansion() {
if (mQs == null) return;
float qsExpansionFraction = computeQsExpansionFraction();
- mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
+ mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation());
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
@@ -3489,9 +3489,9 @@
* cases, such as if there's a heads-up notification.
*/
public void setPanelScrimMinFraction(float minFraction) {
- mBar.onPanelMinFractionChanged(minFraction);
mMinFraction = minFraction;
mDepthController.setPanelPullDownMinFraction(mMinFraction);
+ mScrimController.setPanelScrimMinFraction(mMinFraction);
}
public void clearNotificationEffects() {
@@ -3607,7 +3607,7 @@
mQs.setExpandClickListener(mOnClickListener);
mQs.setHeaderClickable(isQsExpansionEnabled());
mQs.setOverscrolling(mStackScrollerOverscrolling);
- mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
+ mQs.setInSplitShade(mShouldUseSplitNotificationShade);
// recompute internal state when qspanel height changes
mQs.getView().addOnLayoutChangeListener(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 1f1090d..310fe73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -146,11 +146,6 @@
}
/**
- * Percentage of panel expansion offset, caused by pulling down on a heads-up.
- */
- abstract void onPanelMinFractionChanged(float minFraction);
-
- /**
* @param frac the fraction from the expansion in [0, 1]
* @param expanded whether the panel is currently expanded; this is independent from the
* fraction as the panel also might be expanded if the fraction is 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 768567b..c23577c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -385,11 +385,16 @@
final boolean expand;
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
- // If we get a cancel, put the shade back to the state it was in when the gesture
- // started
- if (onKeyguard) {
+ // If the keyguard is fading away, don't expand it again. This can happen if you're
+ // swiping to unlock, the app below the keyguard is in landscape, and the screen
+ // rotates while your finger is still down after the swipe to unlock.
+ if (mKeyguardStateController.isKeyguardFadingAway()) {
+ expand = false;
+ } else if (onKeyguard) {
expand = true;
} else {
+ // If we get a cancel, put the shade back to the state it was in when the
+ // gesture started
expand = !mPanelClosedOnDown;
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 1cca477..150d9c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -18,8 +18,6 @@
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
-import static java.lang.Float.isNaN;
-
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
@@ -57,7 +55,6 @@
StatusBar mBar;
private ScrimController mScrimController;
- private float mMinFraction;
private Runnable mHideExpandedRunnable = new Runnable() {
@Override
public void run() {
@@ -268,20 +265,8 @@
}
@Override
- public void onPanelMinFractionChanged(float minFraction) {
- if (isNaN(minFraction)) {
- throw new IllegalArgumentException("minFraction cannot be NaN");
- }
- if (mMinFraction != minFraction) {
- mMinFraction = minFraction;
- updateScrimFraction();
- }
- }
-
- @Override
public void panelExpansionChanged(float frac, boolean expanded) {
super.panelExpansionChanged(frac, expanded);
- updateScrimFraction();
if ((frac == 0 || frac == 1)) {
if (mPanelExpansionStateChangedListener != null) {
mPanelExpansionStateChangedListener.onPanelExpansionStateChanged();
@@ -302,15 +287,6 @@
mPanelEnabledProvider = panelEnabledProvider;
}
- private void updateScrimFraction() {
- float scrimFraction = mPanelFraction;
- if (mMinFraction < 1.0f) {
- scrimFraction = Math.max((mPanelFraction - mMinFraction) / (1.0f - mMinFraction),
- 0);
- }
- mScrimController.setPanelExpansion(scrimFraction);
- }
-
public void updateResources() {
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index a564637..371ec7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -34,6 +34,7 @@
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
@@ -183,8 +184,10 @@
private float mScrimBehindAlphaKeyguard = KEYGUARD_SCRIM_ALPHA;
private final float mDefaultScrimAlpha;
- // Assuming the shade is expanded during initialization
- private float mPanelExpansion = 1f;
+ private float mRawPanelExpansionFraction;
+ private float mPanelScrimMinFraction;
+ // Calculated based on mRawPanelExpansionFraction and mPanelScrimMinFraction
+ private float mPanelExpansionFraction = 1f; // Assume shade is expanded during initialization
private float mQsExpansion;
private boolean mQsBottomVisible;
@@ -483,14 +486,39 @@
*
* The expansion fraction is tied to the scrim opacity.
*
- * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
+ * See {@link PanelBar#panelExpansionChanged}.
+ *
+ * @param rawPanelExpansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
*/
- public void setPanelExpansion(float fraction) {
- if (isNaN(fraction)) {
- throw new IllegalArgumentException("Fraction should not be NaN");
+ public void setRawPanelExpansionFraction(
+ @FloatRange(from = 0.0, to = 1.0) float rawPanelExpansionFraction) {
+ if (isNaN(rawPanelExpansionFraction)) {
+ throw new IllegalArgumentException("rawPanelExpansionFraction should not be NaN");
}
- if (mPanelExpansion != fraction) {
- mPanelExpansion = fraction;
+ mRawPanelExpansionFraction = rawPanelExpansionFraction;
+ calculateAndUpdatePanelExpansion();
+ }
+
+ /** See {@link NotificationPanelViewController#setPanelScrimMinFraction(float)}. */
+ public void setPanelScrimMinFraction(float minFraction) {
+ if (isNaN(minFraction)) {
+ throw new IllegalArgumentException("minFraction should not be NaN");
+ }
+ mPanelScrimMinFraction = minFraction;
+ calculateAndUpdatePanelExpansion();
+ }
+
+ private void calculateAndUpdatePanelExpansion() {
+ float panelExpansionFraction = mRawPanelExpansionFraction;
+ if (mPanelScrimMinFraction < 1.0f) {
+ panelExpansionFraction = Math.max(
+ (mRawPanelExpansionFraction - mPanelScrimMinFraction)
+ / (1.0f - mPanelScrimMinFraction),
+ 0);
+ }
+
+ if (mPanelExpansionFraction != panelExpansionFraction) {
+ mPanelExpansionFraction = panelExpansionFraction;
boolean relevantState = (mState == ScrimState.UNLOCKED
|| mState == ScrimState.KEYGUARD
@@ -892,7 +920,8 @@
}
private float getInterpolatedFraction() {
- return Interpolators.getNotificationScrimAlpha(mPanelExpansion, false /* notification */);
+ return Interpolators.getNotificationScrimAlpha(
+ mPanelExpansionFraction, false /* notification */);
}
private void setScrimAlpha(ScrimView scrim, float alpha) {
@@ -1228,8 +1257,8 @@
pw.println(mTracking);
pw.print(" mDefaultScrimAlpha=");
pw.println(mDefaultScrimAlpha);
- pw.print(" mExpansionFraction=");
- pw.println(mPanelExpansion);
+ pw.print(" mPanelExpansionFraction=");
+ pw.println(mPanelExpansionFraction);
pw.print(" mExpansionAffectsAlpha=");
pw.println(mExpansionAffectsAlpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index bfb4b7a..1f0785e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -336,6 +336,7 @@
}
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private boolean mCallingFadingAwayAfterReveal;
private StatusBarCommandQueueCallbacks mCommandQueueCallbacks;
void setWindowState(int state) {
@@ -899,6 +900,8 @@
lockscreenShadeTransitionController.setStatusbar(this);
mExpansionChangedListeners = new ArrayList<>();
+ addExpansionChangedListener(
+ (expansion, expanded) -> mScrimController.setRawPanelExpansionFraction(expansion));
mBubbleExpandListener =
(isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
@@ -1404,6 +1407,12 @@
mDeviceProvisionedController.addCallback(mUserSetupObserver);
mUserSetupObserver.onUserSetupChanged();
+ for (ExpansionChangedListener listener : mExpansionChangedListeners) {
+ // The initial expansion amount comes from mNotificationPanelViewController, so we
+ // should send the amount once we've fully set up that controller.
+ sendInitialExpansionAmount(listener);
+ }
+
// disable profiling bars, since they overlap and clutter the output on app windows
ThreadedRenderer.overrideProperty("disableProfileBars", "true");
@@ -3131,8 +3140,20 @@
public void fadeKeyguardWhilePulsing() {
mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,
()-> {
- hideKeyguard();
- mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ Runnable finishFading = () -> {
+ mCallingFadingAwayAfterReveal = false;
+ hideKeyguard();
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ };
+ if (mLightRevealScrim.getRevealAmount() != 1.0f) {
+ mCallingFadingAwayAfterReveal = true;
+ // We're still revealing the Light reveal, let's only go to keyguard once
+ // that has finished and nothing moves anymore.
+ // Going there introduces lots of jank
+ mLightRevealScrim.setFullyRevealedRunnable(finishFading);
+ } else {
+ finishFading.run();
+ }
}).start();
}
@@ -4233,9 +4254,11 @@
}
private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) {
- expansionChangedListener.onExpansionChanged(
- mNotificationPanelViewController.getExpandedFraction(),
- mNotificationPanelViewController.isExpanded());
+ if (mNotificationPanelViewController != null) {
+ expansionChangedListener.onExpansionChanged(
+ mNotificationPanelViewController.getExpandedFraction(),
+ mNotificationPanelViewController.isExpanded());
+ }
}
public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
@@ -4291,7 +4314,7 @@
+ "mStatusBarKeyguardViewManager was null");
return;
}
- if (mKeyguardStateController.isKeyguardFadingAway()) {
+ if (mKeyguardStateController.isKeyguardFadingAway() && !mCallingFadingAwayAfterReveal) {
mStatusBarKeyguardViewManager.onKeyguardFadedAway();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index b708861..235a8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -208,9 +208,18 @@
apply(mCurrentState);
}
- /** Sets whether there is currently an ongoing call. */
- public void setIsCallOngoing(boolean isCallOngoing) {
- mCurrentState.mIsCallOngoing = isCallOngoing;
+ /**
+ * Sets whether an ongoing process requires the status bar to be forced visible.
+ *
+ * This method is separate from {@link this#setForceStatusBarVisible} because the ongoing
+ * process **takes priority**. For example, if {@link this#setForceStatusBarVisible} is set to
+ * false but this method is set to true, then the status bar **will** be visible.
+ *
+ * TODO(b/195839150): We should likely merge this method and
+ * {@link this#setForceStatusBarVisible} together and use some sort of ranking system instead.
+ */
+ public void setOngoingProcessRequiresStatusBarVisible(boolean visible) {
+ mCurrentState.mOngoingProcessRequiresStatusBarVisible = visible;
apply(mCurrentState);
}
@@ -254,13 +263,14 @@
private static class State {
boolean mForceStatusBarVisible;
boolean mIsLaunchAnimationRunning;
- boolean mIsCallOngoing;
+ boolean mOngoingProcessRequiresStatusBarVisible;
}
private void applyForceStatusBarVisibleFlag(State state) {
if (state.mForceStatusBarVisible
|| state.mIsLaunchAnimationRunning
- || state.mIsCallOngoing) {
+ // Don't force-show the status bar if the user has already dismissed it.
+ || state.mOngoingProcessRequiresStatusBarVisible) {
mLpChanged.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
} else {
mLpChanged.privateFlags &= ~PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 143aaba..f3f3325 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -4,10 +4,10 @@
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
-import android.content.res.Configuration
import android.database.ContentObserver
import android.os.Handler
import android.provider.Settings
+import android.view.Surface
import android.view.View
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
@@ -239,10 +239,11 @@
return false
}
- // If we're not allowed to rotate the keyguard, then only do the screen off animation if
- // we're in portrait. Otherwise, AOD will animate in sideways, which looks weird.
+ // If we're not allowed to rotate the keyguard, it can only be displayed in zero-degree
+ // portrait. If we're in another orientation, disable the screen off animation so we don't
+ // animate in the keyguard AOD UI sideways or upside down.
if (!keyguardStateController.isKeyguardScreenRotationAllowed &&
- context.resources.configuration.orientation != Configuration.ORIENTATION_PORTRAIT) {
+ context.display.rotation != Surface.ROTATION_0) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index b7c80de..c3c935e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -60,6 +60,7 @@
private val logger: OngoingCallLogger,
private val dumpManager: DumpManager,
private val statusBarWindowController: Optional<StatusBarWindowController>,
+ private val swipeStatusBarAwayGestureHandler: Optional<SwipeStatusBarAwayGestureHandler>,
) : CallbackController<OngoingCallListener>, Dumpable {
/** Non-null if there's an active call notification. */
@@ -96,7 +97,8 @@
entry.sbn.notification.contentIntent?.intent,
entry.sbn.uid,
entry.sbn.notification.extras.getInt(
- Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING
+ Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING,
+ statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false
)
if (newOngoingCallInfo == callNotificationInfo) {
return
@@ -202,9 +204,16 @@
)
}
}
-
setUpUidObserver(currentCallNotificationInfo)
- statusBarWindowController.ifPresent { it.setIsCallOngoing(true) }
+ if (!currentCallNotificationInfo.statusBarSwipedAway) {
+ statusBarWindowController.ifPresent {
+ it.setOngoingProcessRequiresStatusBarVisible(true)
+ }
+ // TODO(b/195839150): Only listen for the gesture when in immersive mode.
+ swipeStatusBarAwayGestureHandler.ifPresent {
+ it.addOnGestureDetectedCallback(TAG, this::onSwipeAwayGestureDetected)
+ }
+ }
mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
} else {
// If we failed to update the chip, don't store the call info. Then [hasOngoingCall]
@@ -271,7 +280,8 @@
private fun removeChip() {
callNotificationInfo = null
tearDownChipView()
- statusBarWindowController.ifPresent { it.setIsCallOngoing(false) }
+ statusBarWindowController.ifPresent { it.setOngoingProcessRequiresStatusBarVisible(false) }
+ swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) }
mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
if (uidObserver != null) {
iActivityManager.unregisterUidObserver(uidObserver)
@@ -286,13 +296,34 @@
return this.findViewById(R.id.ongoing_call_chip_time)
}
+ /**
+ * If there's an active ongoing call, then we will force the status bar to always show, even if
+ * the user is in immersive mode. However, we also want to give users the ability to swipe away
+ * the status bar if they need to access the area under the status bar.
+ *
+ * This method updates the status bar window appropriately when the swipe away gesture is
+ * detected.
+ */
+ private fun onSwipeAwayGestureDetected() {
+ if (DEBUG) { Log.d(TAG, "Swipe away gesture detected") }
+ callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true)
+ statusBarWindowController.ifPresent {
+ it.setOngoingProcessRequiresStatusBarVisible(false)
+ }
+ swipeStatusBarAwayGestureHandler.ifPresent {
+ it.removeOnGestureDetectedCallback(TAG)
+ }
+ }
+
private data class CallNotificationInfo(
val key: String,
val callStartTime: Long,
val intent: Intent?,
val uid: Int,
/** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */
- val isOngoing: Boolean
+ val isOngoing: Boolean,
+ /** True if the user has swiped away the status bar while in this phone call. */
+ val statusBarSwipedAway: Boolean
) {
/**
* Returns true if the notification information has a valid call start time.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt
new file mode 100644
index 0000000..c97cf14
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/SwipeStatusBarAwayGestureHandler.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ongoingcall
+
+import android.content.Context
+import android.os.Looper
+import android.util.Log
+import android.view.Choreographer
+import android.view.Display
+import android.view.InputEvent
+import android.view.MotionEvent
+import android.view.MotionEvent.*
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.system.InputChannelCompat
+import com.android.systemui.shared.system.InputMonitorCompat
+import com.android.systemui.statusbar.phone.StatusBarWindowController
+import javax.inject.Inject
+
+/**
+ * A class to detect when a user swipes away the status bar. To be notified when the swipe away
+ * gesture is detected, add a callback via [addOnGestureDetectedCallback].
+ */
+@SysUISingleton
+open class SwipeStatusBarAwayGestureHandler @Inject constructor(
+ context: Context,
+ private val statusBarWindowController: StatusBarWindowController,
+) {
+
+ /**
+ * Active callbacks, each associated with a tag. Gestures will only be monitored if
+ * [callbacks.size] > 0.
+ */
+ private val callbacks: MutableMap<String, () -> Unit> = mutableMapOf()
+
+ private var startY: Float = 0f
+ private var startTime: Long = 0L
+ private var monitoringCurrentTouch: Boolean = false
+
+ private var inputMonitor: InputMonitorCompat? = null
+ private var inputReceiver: InputChannelCompat.InputEventReceiver? = null
+
+ // TODO(b/195839150): Update this threshold when the config changes?
+ private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.system_gestures_start_threshold
+ )
+
+ /** Adds a callback that will be triggered when the swipe away gesture is detected. */
+ fun addOnGestureDetectedCallback(tag: String, callback: () -> Unit) {
+ val callbacksWasEmpty = callbacks.isEmpty()
+ callbacks[tag] = callback
+ if (callbacksWasEmpty) {
+ startGestureListening()
+ }
+ }
+
+ /** Removes the callback. */
+ fun removeOnGestureDetectedCallback(tag: String) {
+ callbacks.remove(tag)
+ if (callbacks.isEmpty()) {
+ stopGestureListening()
+ }
+ }
+
+ private fun onInputEvent(ev: InputEvent) {
+ if (ev !is MotionEvent) {
+ return
+ }
+
+ when (ev.actionMasked) {
+ ACTION_DOWN -> {
+ if (
+ // Gesture starts just below the status bar
+ // TODO(b/195839150): Is [statusBarHeight] the correct dimension to use for
+ // determining which down touches are valid?
+ ev.y >= statusBarWindowController.statusBarHeight
+ && ev.y <= 3 * statusBarWindowController.statusBarHeight
+ ) {
+ Log.d(TAG, "Beginning gesture detection, y=${ev.y}")
+ startY = ev.y
+ startTime = ev.eventTime
+ monitoringCurrentTouch = true
+ } else {
+ monitoringCurrentTouch = false
+ }
+ }
+ ACTION_MOVE -> {
+ if (!monitoringCurrentTouch) {
+ return
+ }
+ if (
+ // Gesture is up
+ ev.y < startY
+ // Gesture went far enough
+ && (startY - ev.y) >= swipeDistanceThreshold
+ // Gesture completed quickly enough
+ && (ev.eventTime - startTime) < SWIPE_TIMEOUT_MS
+ ) {
+ Log.i(TAG, "Gesture detected; notifying callbacks")
+ callbacks.values.forEach { it.invoke() }
+ monitoringCurrentTouch = false
+ }
+ }
+ ACTION_CANCEL, ACTION_UP -> {
+ monitoringCurrentTouch = false
+ }
+ }
+ }
+
+ /** Start listening for the swipe gesture. */
+ private fun startGestureListening() {
+ stopGestureListening()
+
+ if (DEBUG) { Log.d(TAG, "Input listening started") }
+ inputMonitor = InputMonitorCompat(TAG, Display.DEFAULT_DISPLAY).also {
+ inputReceiver = it.getInputReceiver(
+ Looper.getMainLooper(),
+ Choreographer.getInstance(),
+ this::onInputEvent
+ )
+ }
+ }
+
+ /** Stop listening for the swipe gesture. */
+ private fun stopGestureListening() {
+ inputMonitor?.let {
+ if (DEBUG) { Log.d(TAG, "Input listening stopped") }
+ inputMonitor = null
+ it.dispose()
+ }
+ inputReceiver?.let {
+ inputReceiver = null
+ it.dispose()
+ }
+ }
+}
+
+private const val SWIPE_TIMEOUT_MS: Long = 500
+private val TAG = SwipeStatusBarAwayGestureHandler::class.simpleName
+private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 514a903..ff1929c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -26,6 +26,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.launcher3.icons.IconProvider;
import com.android.systemui.dagger.WMComponent;
import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
@@ -166,6 +167,12 @@
return new SystemWindows(displayController, wmService);
}
+ @WMSingleton
+ @Provides
+ static IconProvider provideIconProvider(Context context) {
+ return new IconProvider(context);
+ }
+
// We currently dedupe multiple messages, so we use the shell main handler directly
@WMSingleton
@Provides
@@ -486,9 +493,10 @@
@Provides
static StartingWindowController provideStartingWindowController(Context context,
@ShellSplashscreenThread ShellExecutor splashScreenExecutor,
- StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) {
+ StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, IconProvider iconProvider,
+ TransactionPool pool) {
return new StartingWindowController(context, splashScreenExecutor,
- startingWindowTypeAlgorithm, pool);
+ startingWindowTypeAlgorithm, iconProvider, pool);
}
//
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 6237031..cdf40a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -41,6 +41,7 @@
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -80,6 +81,14 @@
};
}
+ @After
+ public void tearDown() {
+ if (mController != null) {
+ mController.onAccessibilityButtonTargetsChanged("");
+ mController = null;
+ }
+ }
+
@Test
public void initController_registerListeners() {
mController = setUpController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index c464cad..ddf1d70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -18,14 +18,18 @@
import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Vibrator;
@@ -39,15 +43,18 @@
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.LockIconView;
import com.android.keyguard.LockIconViewController;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -69,7 +76,10 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class LockIconViewControllerTest extends SysuiTestCase {
+ private static final String UNLOCKED_LABEL = "unlocked";
+
private @Mock LockIconView mLockIconView;
+ private @Mock AnimatedVectorDrawable mIconDrawable;
private @Mock Context mContext;
private @Mock Resources mResources;
private @Mock DisplayMetrics mDisplayMetrics;
@@ -97,6 +107,11 @@
@Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor;
private AuthController.Callback mAuthControllerCallback;
+ @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback>
+ mKeyguardUpdateMonitorCallbackCaptor =
+ ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+ private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+
@Captor private ArgumentCaptor<PointF> mPointCaptor;
@Before
@@ -108,6 +123,13 @@
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
when(mLockIconView.findViewById(anyInt())).thenReturn(mAodFp);
+ when(mResources.getString(R.string.accessibility_unlock_button)).thenReturn(UNLOCKED_LABEL);
+ when(mResources.getDrawable(anyInt(), anyObject())).thenReturn(mIconDrawable);
+
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
mLockIconViewController = new LockIconViewController(
mLockIconView,
@@ -192,6 +214,29 @@
verify(mLockIconView).setUseBackground(false);
}
+ @Test
+ public void testUnlockIconShows_biometricUnlockedTrue() {
+ // GIVEN UDFPS sensor location is available
+ setupUdfps();
+
+ // GIVEN lock icon controller is initialized and view is attached
+ mLockIconViewController.init();
+ captureAttachListener();
+ mAttachListener.onViewAttachedToWindow(mLockIconView);
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ reset(mLockIconView);
+
+ // WHEN face auth's biometric running state changes
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+
+ // THEN the unlock icon is shown
+ verify(mLockIconView).setContentDescription(UNLOCKED_LABEL);
+ }
+
private Pair<Integer, PointF> setupUdfps() {
final PointF udfpsLocation = new PointF(50, 75);
final int radius = 33;
@@ -220,4 +265,10 @@
verify(mLockIconView).addOnAttachStateChangeListener(mAttachCaptor.capture());
mAttachListener = mAttachCaptor.getValue();
}
+
+ private void captureKeyguardUpdateMonitorCallback() {
+ verify(mKeyguardUpdateMonitor).registerCallback(
+ mKeyguardUpdateMonitorCallbackCaptor.capture());
+ mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 42629f5..bf5a6e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -41,6 +41,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
@@ -95,6 +96,7 @@
@Mock private lateinit var collapsedSet: ConstraintSet
@Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
@Mock private lateinit var mediaCarouselController: MediaCarouselController
+ @Mock private lateinit var falsingManager: FalsingManager
private lateinit var appIcon: ImageView
private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -131,8 +133,8 @@
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
- seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil,
- mediaOutputDialogFactory, mediaCarouselController)
+ seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil,
+ mediaOutputDialogFactory, mediaCarouselController, falsingManager)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Mock out a view holder for the player to attach to.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 7d8728e..e77802f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -76,6 +76,7 @@
assertThat(seekBarView.getThumb().getAlpha()).isEqualTo(0)
assertThat(elapsedTimeView.getText()).isEqualTo("")
assertThat(totalTimeView.getText()).isEqualTo("")
+ assertThat(seekBarView.contentDescription).isEqualTo("")
assertThat(seekBarView.maxHeight).isEqualTo(disabledHeight)
}
@@ -102,6 +103,9 @@
assertThat(seekBarView.max).isEqualTo(120000)
assertThat(elapsedTimeView.getText()).isEqualTo("00:03")
assertThat(totalTimeView.getText()).isEqualTo("02:00")
+
+ val desc = context.getString(R.string.controls_media_seekbar_description, "00:03", "02:00")
+ assertThat(seekBarView.contentDescription).isEqualTo(desc)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 25ca8c9..750600ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -119,7 +119,6 @@
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
@@ -181,7 +180,6 @@
when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(mMediaDevices);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -190,7 +188,6 @@
when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(new ArrayList<>());
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
}
@@ -198,7 +195,6 @@
public void onBindViewHolder_bindNonActiveConnectedDevice_verifyView() {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -215,7 +211,6 @@
when(mMediaDevice2.isConnected()).thenReturn(false);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -231,7 +226,6 @@
LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
index 1f85112..ca5d570 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupAdapterTest.java
@@ -99,7 +99,6 @@
assertThat(mGroupViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mGroupViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
@@ -114,7 +113,6 @@
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
@@ -141,7 +139,6 @@
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
@@ -167,7 +164,6 @@
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
@@ -186,7 +182,6 @@
assertThat(mGroupViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mGroupViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mGroupViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index c50296b..7938511 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -209,7 +209,7 @@
verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
- verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyBoolean())
+ verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
}
@Test
@@ -220,7 +220,7 @@
verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
- verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyBoolean())
+ verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(depthController).transitionToFullShadeProgress = anyFloat()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 5ebe900..705112a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -623,7 +623,7 @@
@Test
public void transitionToUnlocked() {
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
@@ -638,7 +638,7 @@
));
// Back scrim should be visible after start dragging
- mScrimController.setPanelExpansion(0.3f);
+ mScrimController.setRawPanelExpansionFraction(0.3f);
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, SEMI_TRANSPARENT,
@@ -663,20 +663,20 @@
@Test
public void panelExpansion() {
- mScrimController.setPanelExpansion(0f);
- mScrimController.setPanelExpansion(0.5f);
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setRawPanelExpansionFraction(0.5f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
finishAnimationsImmediately();
reset(mScrimBehind);
- mScrimController.setPanelExpansion(0f);
- mScrimController.setPanelExpansion(1.0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
finishAnimationsImmediately();
assertEquals("Scrim alpha should change after setPanelExpansion",
mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
finishAnimationsImmediately();
assertEquals("Scrim alpha should change after setPanelExpansion",
@@ -723,21 +723,21 @@
@Test
public void panelExpansionAffectsAlpha() {
- mScrimController.setPanelExpansion(0f);
- mScrimController.setPanelExpansion(0.5f);
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setRawPanelExpansionFraction(0.5f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
finishAnimationsImmediately();
final float scrimAlpha = mScrimBehind.getViewAlpha();
reset(mScrimBehind);
mScrimController.setExpansionAffectsAlpha(false);
- mScrimController.setPanelExpansion(0.8f);
+ mScrimController.setRawPanelExpansionFraction(0.8f);
verifyZeroInteractions(mScrimBehind);
assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha "
+ "is false", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
mScrimController.setExpansionAffectsAlpha(true);
- mScrimController.setPanelExpansion(0.1f);
+ mScrimController.setRawPanelExpansionFraction(0.1f);
finishAnimationsImmediately();
Assert.assertNotEquals("Scrim opacity should change when setExpansionAffectsAlpha "
+ "is true", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
@@ -747,7 +747,7 @@
public void transitionToUnlockedFromOff() {
// Simulate unlock with fingerprint without AOD
mScrimController.transitionTo(ScrimState.OFF);
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
finishAnimationsImmediately();
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -769,7 +769,7 @@
public void transitionToUnlockedFromAod() {
// Simulate unlock with fingerprint
mScrimController.transitionTo(ScrimState.AOD);
- mScrimController.setPanelExpansion(0f);
+ mScrimController.setRawPanelExpansionFraction(0f);
finishAnimationsImmediately();
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -948,7 +948,7 @@
@Test
public void testConservesExpansionOpacityAfterTransition() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(0.5f);
+ mScrimController.setRawPanelExpansionFraction(0.5f);
finishAnimationsImmediately();
final float expandedAlpha = mScrimBehind.getViewAlpha();
@@ -1075,7 +1075,7 @@
@Test
public void testScrimsOpaque_whenShadeFullyExpanded() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(1);
+ mScrimController.setRawPanelExpansionFraction(1);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0, 300);
finishAnimationsImmediately();
@@ -1089,7 +1089,7 @@
@Test
public void testScrimsVisible_whenShadeVisible() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(0.3f);
+ mScrimController.setRawPanelExpansionFraction(0.3f);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0, 300);
finishAnimationsImmediately();
@@ -1124,7 +1124,7 @@
public void testScrimsVisible_whenShadeVisible_clippingQs() {
mScrimController.setClipsQsScrim(true);
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.setPanelExpansion(0.3f);
+ mScrimController.setRawPanelExpansionFraction(0.3f);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0.5f, 300);
finishAnimationsImmediately();
@@ -1150,7 +1150,7 @@
public void testNotificationScrimTransparent_whenOnLockscreen() {
mScrimController.transitionTo(ScrimState.KEYGUARD);
// even if shade is not pulled down, panel has expansion of 1 on the lockscreen
- mScrimController.setPanelExpansion(1);
+ mScrimController.setRawPanelExpansionFraction(1);
mScrimController.setQsPosition(0f, /*qs panel bottom*/ 0);
assertScrimAlpha(Map.of(
@@ -1160,7 +1160,7 @@
@Test
public void testNotificationScrimVisible_afterOpeningShadeFromLockscreen() {
- mScrimController.setPanelExpansion(1);
+ mScrimController.setRawPanelExpansionFraction(1);
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
finishAnimationsImmediately();
@@ -1203,11 +1203,11 @@
@Test
public void testNotificationTransparency_followsTransitionToFullShade() {
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
- mScrimController.setPanelExpansion(1.0f);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
finishAnimationsImmediately();
float shadeLockedAlpha = mNotificationsScrim.getViewAlpha();
mScrimController.transitionTo(ScrimState.KEYGUARD);
- mScrimController.setPanelExpansion(1.0f);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
finishAnimationsImmediately();
float keyguardAlpha = mNotificationsScrim.getViewAlpha();
@@ -1227,7 +1227,7 @@
}
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
- mScrimController.setPanelExpansion(expansion);
+ mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
// alpha is not changing linearly thus 0.2 of leeway when asserting
assertEquals(expectedAlpha, mNotificationsScrim.getViewAlpha(), 0.2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index e97aba2..be27876 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -50,8 +50,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.nullable
+import org.mockito.ArgumentMatchers.*
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.eq
@@ -83,6 +82,7 @@
private lateinit var controller: OngoingCallController
private lateinit var notifCollectionListener: NotifCollectionListener
+ @Mock private lateinit var mockSwipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler
@Mock private lateinit var mockOngoingCallListener: OngoingCallListener
@Mock private lateinit var mockActivityStarter: ActivityStarter
@Mock private lateinit var mockIActivityManager: IActivityManager
@@ -112,6 +112,7 @@
OngoingCallLogger(uiEventLoggerFake),
DumpManager(),
Optional.of(mockStatusBarWindowController),
+ Optional.of(mockSwipeStatusBarAwayGestureHandler),
)
controller.init()
controller.addCallback(mockOngoingCallListener)
@@ -141,7 +142,15 @@
fun onEntryUpdated_isOngoingCallNotif_windowControllerUpdated() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- verify(mockStatusBarWindowController).setIsCallOngoing(true)
+ verify(mockStatusBarWindowController).setOngoingProcessRequiresStatusBarVisible(true)
+ }
+
+ @Test
+ fun onEntryUpdated_isOngoingCallNotif_swipeGestureCallbackAdded() {
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .addOnGestureDetectedCallback(anyString(), any())
}
@Test
@@ -242,7 +251,18 @@
notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
- verify(mockStatusBarWindowController).setIsCallOngoing(false)
+ verify(mockStatusBarWindowController).setOngoingProcessRequiresStatusBarVisible(false)
+ }
+
+ @Test
+ fun onEntryUpdated_callNotifAddedThenRemoved_swipeGestureCallbackRemoved() {
+ val ongoingCallNotifEntry = createOngoingCallNotifEntry()
+ notifCollectionListener.onEntryAdded(ongoingCallNotifEntry)
+
+ notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED)
+
+ verify(mockSwipeStatusBarAwayGestureHandler)
+ .removeOnGestureDetectedCallback(anyString())
}
/** Regression test for b/188491504. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
index eebcbe6..3d55488 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
@@ -31,7 +31,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import java.lang.Exception
/**
* UsbPermissionActivityTest
@@ -54,7 +53,9 @@
putExtra(Intent.EXTRA_INTENT, PendingIntent.getBroadcast(
mContext,
334,
- Intent("NO_ACTION"),
+ Intent("NO_ACTION").apply {
+ setPackage("com.android.systemui.tests")
+ },
PendingIntent.FLAG_MUTABLE))
putExtra(UsbManager.EXTRA_ACCESSORY, UsbAccessory(
"manufacturer",
diff --git a/proto/src/criticalevents/OWNERS b/proto/src/criticalevents/OWNERS
new file mode 100644
index 0000000..07c0e70
--- /dev/null
+++ b/proto/src/criticalevents/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/criticalevents/OWNERS
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 850c3ff..9e4e1a1 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1251,4 +1251,9 @@
* @return the number of freed bytes or -1 if there was an error in the process.
*/
public abstract long deleteOatArtifactsOfPackage(String packageName);
+
+ /**
+ * Reconcile all app data for the given user.
+ */
+ public abstract void reconcileAppsData(int userId, int flags, boolean migrateAppsData);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 63301ac..fab58e8 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -385,6 +385,10 @@
private int[] mAllowedNetworkTypeReason;
private long[] mAllowedNetworkTypeValue;
+ private static final List<LinkCapacityEstimate> INVALID_LCE_LIST =
+ new ArrayList<LinkCapacityEstimate>(Arrays.asList(new LinkCapacityEstimate(
+ LinkCapacityEstimate.LCE_TYPE_COMBINED,
+ LinkCapacityEstimate.INVALID, LinkCapacityEstimate.INVALID)));
private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists;
/**
@@ -719,7 +723,7 @@
mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
- mLinkCapacityEstimateLists.add(i, new ArrayList<>());
+ mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
}
}
@@ -819,7 +823,7 @@
mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
- mLinkCapacityEstimateLists.add(i, new ArrayList<>());
+ mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index b2fa86b..98452e5 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -825,9 +825,18 @@
}
synchronized void onInitSensors(boolean init) {
- final int[] modes = getSupportedHeadTrackingModes();
- if (modes.length == 0) {
- Log.i(TAG, "not initializing sensors, no headtracking supported");
+ final String action = init ? "initializing" : "releasing";
+ if (mSpat == null) {
+ Log.e(TAG, "not " + action + " sensors, null spatializer");
+ return;
+ }
+ try {
+ if (!mSpat.isHeadTrackingSupported()) {
+ Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
return;
}
initSensors(init);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 045ee8a..5178f35 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1632,13 +1632,13 @@
mDisplayModeDirector.getAppRequestObserver().setAppRequest(
displayId, requestedModeId, requestedMinRefreshRate, requestedMaxRefreshRate);
- if (display.getDisplayInfoLocked().minimalPostProcessingSupported) {
- boolean mppRequest = mMinimalPostProcessingAllowed && preferMinimalPostProcessing;
+ // TODO(b/202378408) set minimal post-processing only if it's supported once we have a
+ // separate API for disabling on-device processing.
+ boolean mppRequest = mMinimalPostProcessingAllowed && preferMinimalPostProcessing;
- if (display.getRequestedMinimalPostProcessingLocked() != mppRequest) {
- display.setRequestedMinimalPostProcessingLocked(mppRequest);
- shouldScheduleTraversal = true;
- }
+ if (display.getRequestedMinimalPostProcessingLocked() != mppRequest) {
+ display.setRequestedMinimalPostProcessingLocked(mppRequest);
+ shouldScheduleTraversal = true;
}
if (shouldScheduleTraversal) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index dbe17b7..b6d13e0 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -993,12 +993,12 @@
mGameContentTypeRequested = on;
- if (!mGameContentTypeSupported) {
- Slog.d(TAG, "Unable to set game content type because the connected "
- + "display does not support game content type.");
- return;
- }
-
+ // Even if game content type is not supported on the connected display we
+ // propagate the requested state down to the HAL. This is because some devices
+ // with external displays, such as Android TV set-top boxes, use this signal
+ // to disable/enable on-device processing.
+ // TODO(b/202378408) set game content type only if it's supported once we have a
+ // separate API for disabling on-device processing.
mSurfaceControlProxy.setGameContentType(getDisplayTokenLocked(), on);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 5de89c9..cf8cc38 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -522,19 +522,19 @@
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL:
- return STORAGE_GLOBAL_SETTINGS;
+ return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
- return STORAGE_GLOBAL_SETTINGS;
+ return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
- return STORAGE_GLOBAL_SETTINGS;
+ return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL:
- return STORAGE_GLOBAL_SETTINGS;
+ return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING:
return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY:
- return STORAGE_GLOBAL_SETTINGS;
+ return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP:
return STORAGE_GLOBAL_SETTINGS;
case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV:
@@ -563,19 +563,19 @@
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL:
- return Global.HDMI_CEC_SWITCH_ENABLED;
+ return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
- return Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP;
+ return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
- return Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED;
+ return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL:
- return Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED;
+ return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING:
return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY:
- return Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED;
+ return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP:
return Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED;
case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV:
@@ -634,15 +634,6 @@
case Global.HDMI_CONTROL_ENABLED:
notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
break;
- case Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
- break;
- case Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE);
- break;
- case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY);
- break;
case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP);
break;
@@ -687,9 +678,6 @@
ContentResolver resolver = mContext.getContentResolver();
String[] settings = new String[] {
Global.HDMI_CONTROL_ENABLED,
- Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
- Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
- Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
};
for (String setting: settings) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ec8e5e4..d14ef16 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -270,6 +270,24 @@
| Context.BIND_IMPORTANT_BACKGROUND;
/**
+ * Binding flags for establishing connection to the {@link InputMethodService} when
+ * config_killableInputMethods is enabled.
+ */
+ private static final int IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS =
+ Context.BIND_AUTO_CREATE
+ | Context.BIND_REDUCTION_FLAGS;
+
+ /**
+ * Binding flags for establishing connection to the {@link InputMethodService}.
+ *
+ * <p>
+ * This defaults to {@link #IME_CONNECTION_BIND_FLAGS} unless config_killableInputMethods is
+ * enabled, in which case this takes the value of
+ * {@link #IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS}.
+ */
+ private final int mImeConnectionBindFlags;
+
+ /**
* Binding flags used only while the {@link InputMethodService} is showing window.
*/
private static final int IME_VISIBLE_BIND_FLAGS =
@@ -1651,6 +1669,16 @@
mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
mSettings, context);
mMenuController = new InputMethodMenuController(this);
+
+ // If configured, use low priority flags to make the IME killable by the lowmemorykiller
+ final boolean lowerIMEPriority = mRes.getBoolean(
+ com.android.internal.R.bool.config_killableInputMethods);
+
+ if (lowerIMEPriority) {
+ mImeConnectionBindFlags = IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS;
+ } else {
+ mImeConnectionBindFlags = IME_CONNECTION_BIND_FLAGS;
+ }
}
@GuardedBy("mMethodMap")
@@ -2437,7 +2465,7 @@
mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
PendingIntent.FLAG_IMMUTABLE));
- if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
+ if (bindCurrentInputMethodServiceLocked(mCurIntent, this, mImeConnectionBindFlags)) {
mLastBindTime = SystemClock.uptimeMillis();
mHaveConnection = true;
mCurId = info.getId();
@@ -3158,7 +3186,7 @@
SystemClock.uptimeMillis()-mLastBindTime,1);
Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
mContext.unbindService(this);
- bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
+ bindCurrentInputMethodServiceLocked(mCurIntent, this, mImeConnectionBindFlags);
} else {
if (DEBUG) {
Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index d37c1c8..8f81c0a5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -408,8 +408,6 @@
private static final String ATTR_NETWORK_TYPES = "networkTypes";
private static final String ATTR_XML_UTILS_NAME = "name";
- private static final String ACTION_ALLOW_BACKGROUND =
- "com.android.server.net.action.ALLOW_BACKGROUND";
private static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
private static final String ACTION_SNOOZE_RAPID =
@@ -974,11 +972,6 @@
mContext.registerReceiver(
mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
- // listen for restrict background changes from notifications
- final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
- mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler,
- Context.RECEIVER_EXPORTED);
-
// Listen for snooze from notifications
mContext.registerReceiver(mSnoozeReceiver,
new IntentFilter(ACTION_SNOOZE_WARNING), MANAGE_NETWORK_POLICY, mHandler);
@@ -1197,20 +1190,6 @@
/**
* Receiver that watches for {@link Notification} control of
- * {@link #mRestrictBackground}.
- */
- final private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // on background handler thread, and verified MANAGE_NETWORK_POLICY
- // permission above.
-
- setRestrictBackground(false);
- }
- };
-
- /**
- * Receiver that watches for {@link Notification} control of
* {@link NetworkPolicy#lastWarningSnooze}.
*/
final private BroadcastReceiver mSnoozeReceiver = new BroadcastReceiver() {
@@ -5522,10 +5501,6 @@
}
}
- private static Intent buildAllowBackgroundDataIntent() {
- return new Intent(ACTION_ALLOW_BACKGROUND);
- }
-
private static Intent buildSnoozeWarningIntent(NetworkTemplate template, String targetPackage) {
final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b7744c7e..75d7893 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5022,7 +5022,6 @@
@Override
public boolean matchesCallFilter(Bundle extras) {
- enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
return mZenModeHelper.matchesCallFilter(
Binder.getCallingUserHandle(),
extras,
@@ -5032,6 +5031,12 @@
}
@Override
+ public void cleanUpCallersAfter(long timeThreshold) {
+ enforceSystemOrSystemUI("INotificationManager.cleanUpCallersAfter");
+ mZenModeHelper.cleanUpCallersAfter(timeThreshold);
+ }
+
+ @Override
public boolean isSystemConditionProviderEnabled(String path) {
enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
return mConditionProviders.isSystemProviderEnabled(path);
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index 4d19855..0f526d4 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -311,6 +311,10 @@
}
}
+ protected void cleanUpCallersAfter(long timeThreshold) {
+ REPEAT_CALLERS.cleanUpCallsAfter(timeThreshold);
+ }
+
private static class RepeatCallers {
// Person : time
private final ArrayMap<String, Long> mCalls = new ArrayMap<>();
@@ -346,6 +350,17 @@
}
}
+ // Clean up all calls that occurred after the given time.
+ // Used only for tests, to clean up after testing.
+ private synchronized void cleanUpCallsAfter(long timeThreshold) {
+ for (int i = mCalls.size() - 1; i >= 0; i--) {
+ final long time = mCalls.valueAt(i);
+ if (time > timeThreshold) {
+ mCalls.removeAt(i);
+ }
+ }
+ }
+
private void setThresholdMinutes(Context context) {
if (mThresholdMinutes <= 0) {
mThresholdMinutes = context.getResources().getInteger(com.android.internal.R.integer
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 16a0b7e..93f1b47 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -188,6 +188,10 @@
mFiltering.recordCall(record);
}
+ protected void cleanUpCallersAfter(long timeThreshold) {
+ mFiltering.cleanUpCallersAfter(timeThreshold);
+ }
+
public boolean shouldIntercept(NotificationRecord record) {
synchronized (mConfig) {
return mFiltering.shouldIntercept(mZenMode, mConsolidatedPolicy, record);
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
new file mode 100644
index 0000000..8387482
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -0,0 +1,588 @@
+/*
+ * 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.pm;
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.SELinuxUtil;
+import android.content.pm.UserInfo;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
+import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.TimingsTraceLog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.server.SystemServerInitThreadPool;
+import com.android.server.pm.dex.ArtManagerService;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+
+import dalvik.system.VMRuntime;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+
+/**
+ * Prepares app data for users
+ */
+final class AppDataHelper {
+ private static final boolean DEBUG_APP_DATA = false;
+
+ private final PackageManagerService mPm;
+ private final Installer mInstaller;
+ private final ArtManagerService mArtManagerService;
+
+ // TODO(b/198166813): remove PMS dependency
+ AppDataHelper(PackageManagerService pm) {
+ mPm = pm;
+ mInstaller = mPm.mInjector.getInstaller();
+ mArtManagerService = mPm.mInjector.getArtManagerService();
+ }
+
+ /**
+ * Prepare app data for the given app just after it was installed or
+ * upgraded. This method carefully only touches users that it's installed
+ * for, and it forces a restorecon to handle any seinfo changes.
+ * <p>
+ * Verifies that directories exist and that ownership and labeling is
+ * correct for all installed apps. If there is an ownership mismatch, it
+ * will try recovering system apps by wiping data; third-party app data is
+ * left intact.
+ * <p>
+ * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
+ */
+ public void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
+ final PackageSetting ps;
+ synchronized (mPm.mLock) {
+ ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+ mPm.mSettings.writeKernelMappingLPr(ps);
+ }
+
+ Installer.Batch batch = new Installer.Batch();
+ UserManagerInternal umInternal = mPm.mInjector.getUserManagerInternal();
+ StorageManagerInternal smInternal = mPm.mInjector.getLocalService(
+ StorageManagerInternal.class);
+ for (UserInfo user : umInternal.getUsers(false /*excludeDying*/)) {
+ final int flags;
+ if (StorageManager.isUserKeyUnlocked(user.id)
+ && smInternal.isCeStoragePrepared(user.id)) {
+ flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
+ } else if (umInternal.isUserRunning(user.id)) {
+ flags = StorageManager.FLAG_STORAGE_DE;
+ } else {
+ continue;
+ }
+
+ // TODO@ashfall check ScanResult.mNeedsNewAppId, and if true instead
+ // of creating app data, migrate / change ownership of existing
+ // data.
+
+ if (ps.getInstalled(user.id)) {
+ // TODO: when user data is locked, mark that we're still dirty
+ prepareAppData(batch, pkg, user.id, flags).thenRun(() -> {
+ // Note: this code block is executed with the Installer lock
+ // already held, since it's invoked as a side-effect of
+ // executeBatchLI()
+ if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
+ // Prepare app data on external storage; currently this is used to
+ // setup any OBB dirs that were created by the installer correctly.
+ int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid()));
+ smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid);
+ }
+ });
+ }
+ }
+ executeBatchLI(batch);
+ }
+
+ private void executeBatchLI(@NonNull Installer.Batch batch) {
+ try {
+ batch.execute(mInstaller);
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, "Failed to execute pending operations", e);
+ }
+ }
+
+ /**
+ * Prepare app data for the given app.
+ * <p>
+ * Verifies that directories exist and that ownership and labeling is
+ * correct for all installed apps. If there is an ownership mismatch, this
+ * will try recovering system apps by wiping data; third-party app data is
+ * left intact.
+ */
+ private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
+ @Nullable AndroidPackage pkg, int userId, int flags) {
+ if (pkg == null) {
+ Slog.wtf(TAG, "Package was null!", new Throwable());
+ return CompletableFuture.completedFuture(null);
+ }
+ return prepareAppDataLeaf(batch, pkg, userId, flags);
+ }
+
+ private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
+ @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) {
+ prepareAppData(batch, pkg, userId, flags).thenRun(() -> {
+ // Note: this code block is executed with the Installer lock
+ // already held, since it's invoked as a side-effect of
+ // executeBatchLI()
+ if (maybeMigrateAppData && maybeMigrateAppDataLIF(pkg, userId)) {
+ // We may have just shuffled around app data directories, so
+ // prepare them one more time
+ final Installer.Batch batchInner = new Installer.Batch();
+ prepareAppData(batchInner, pkg, userId, flags);
+ executeBatchLI(batchInner);
+ }
+ });
+ }
+
+ private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch,
+ @NonNull AndroidPackage pkg, int userId, int flags) {
+ if (DEBUG_APP_DATA) {
+ Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
+ + Integer.toHexString(flags));
+ }
+
+ final PackageSetting ps;
+ final String seInfoUser;
+ synchronized (mPm.mLock) {
+ ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+ seInfoUser = SELinuxUtil.getSeinfoUser(ps.readUserState(userId));
+ }
+ final String volumeUuid = pkg.getVolumeUuid();
+ final String packageName = pkg.getPackageName();
+
+ final int appId = UserHandle.getAppId(pkg.getUid());
+
+ String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
+
+ Preconditions.checkNotNull(pkgSeInfo);
+
+ final String seInfo = pkgSeInfo + seInfoUser;
+ final int targetSdkVersion = pkg.getTargetSdkVersion();
+
+ return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo,
+ targetSdkVersion).whenComplete((ceDataInode, e) -> {
+ // Note: this code block is executed with the Installer lock
+ // already held, since it's invoked as a side-effect of
+ // executeBatchLI()
+ if (e != null) {
+ logCriticalInfo(Log.WARN, "Failed to create app data for " + packageName
+ + ", but trying to recover: " + e);
+ destroyAppDataLeafLIF(pkg, userId, flags);
+ try {
+ ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId,
+ flags, appId, seInfo, pkg.getTargetSdkVersion());
+ logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
+ } catch (Installer.InstallerException e2) {
+ logCriticalInfo(Log.DEBUG, "Recovery failed!");
+ }
+ }
+
+ // Prepare the application profiles only for upgrades and
+ // first boot (so that we don't repeat the same operation at
+ // each boot).
+ //
+ // We only have to cover the upgrade and first boot here
+ // because for app installs we prepare the profiles before
+ // invoking dexopt (in installPackageLI).
+ //
+ // We also have to cover non system users because we do not
+ // call the usual install package methods for them.
+ //
+ // NOTE: in order to speed up first boot time we only create
+ // the current profile and do not update the content of the
+ // reference profile. A system image should already be
+ // configured with the right profile keys and the profiles
+ // for the speed-profile prebuilds should already be copied.
+ // That's done in #performDexOptUpgrade.
+ //
+ // TODO(calin, mathieuc): We should use .dm files for
+ // prebuilds profiles instead of manually copying them in
+ // #performDexOptUpgrade. When we do that we should have a
+ // more granular check here and only update the existing
+ // profiles.
+ if (mPm.mIsUpgrade || mPm.mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
+ mArtManagerService.prepareAppProfiles(pkg, userId,
+ /* updateReferenceProfileContent= */ false);
+ }
+
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
+ // TODO: mark this structure as dirty so we persist it!
+ synchronized (mPm.mLock) {
+ if (ps != null) {
+ ps.setCeDataInode(ceDataInode, userId);
+ }
+ }
+ }
+
+ prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
+ });
+ }
+
+ public void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting,
+ int userId, int flags) {
+ if (pkg == null) {
+ Slog.wtf(TAG, "Package was null!", new Throwable());
+ return;
+ }
+ prepareAppDataContentsLeafLIF(pkg, pkgSetting, userId, flags);
+ }
+
+ private void prepareAppDataContentsLeafLIF(AndroidPackage pkg,
+ @Nullable PackageSetting pkgSetting, int userId, int flags) {
+ final String volumeUuid = pkg.getVolumeUuid();
+ final String packageName = pkg.getPackageName();
+
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
+ // Create a native library symlink only if we have native libraries
+ // and if the native libraries are 32 bit libraries. We do not provide
+ // this symlink for 64 bit libraries.
+ String primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
+ if (primaryCpuAbi != null && !VMRuntime.is64BitAbi(primaryCpuAbi)) {
+ final String nativeLibPath = pkg.getNativeLibraryDir();
+ try {
+ mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
+ nativeLibPath, userId);
+ } catch (Installer.InstallerException e) {
+ Slog.e(TAG, "Failed to link native for " + packageName + ": " + e);
+ }
+ }
+ }
+ }
+
+ /**
+ * For system apps on non-FBE devices, this method migrates any existing
+ * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
+ * requested by the app.
+ */
+ private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) {
+ if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated()
+ && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+ final int storageTarget = pkg.isDefaultToDeviceProtectedStorage()
+ ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
+ try {
+ mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId,
+ storageTarget);
+ } catch (Installer.InstallerException e) {
+ logCriticalInfo(Log.WARN,
+ "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Reconcile all app data for the given user.
+ * <p>
+ * Verifies that directories exist and that ownership and labeling is
+ * correct for all installed apps on all mounted volumes.
+ */
+ @NonNull
+ public void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
+ final StorageManager storage = mPm.mInjector.getSystemService(StorageManager.class);
+ for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+ final String volumeUuid = vol.getFsUuid();
+ synchronized (mPm.mInstallLock) {
+ reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData);
+ }
+ }
+ }
+
+ @GuardedBy("mPm.mInstallLock")
+ void reconcileAppsDataLI(String volumeUuid, int userId, int flags,
+ boolean migrateAppData) {
+ reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */);
+ }
+
+ /**
+ * Reconcile all app data on given mounted volume.
+ * <p>
+ * Destroys app data that isn't expected, either due to uninstallation or
+ * reinstallation on another volume.
+ * <p>
+ * Verifies that directories exist and that ownership and labeling is
+ * correct for all installed apps.
+ *
+ * @return list of skipped non-core packages (if {@code onlyCoreApps} is true)
+ */
+ @GuardedBy("mPm.mInstallLock")
+ private List<String> reconcileAppsDataLI(String volumeUuid, int userId, int flags,
+ boolean migrateAppData, boolean onlyCoreApps) {
+ Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ + Integer.toHexString(flags) + " migrateAppData=" + migrateAppData);
+ List<String> result = onlyCoreApps ? new ArrayList<>() : null;
+
+ final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
+ final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
+
+ // First look for stale data that doesn't belong, and check if things
+ // have changed since we did our last restorecon
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
+ if (StorageManager.isFileEncryptedNativeOrEmulated()
+ && !StorageManager.isUserKeyUnlocked(userId)) {
+ throw new RuntimeException(
+ "Yikes, someone asked us to reconcile CE storage while " + userId
+ + " was still locked; this would have caused massive data loss!");
+ }
+
+ final File[] files = FileUtils.listFilesOrEmpty(ceDir);
+ for (File file : files) {
+ final String packageName = file.getName();
+ try {
+ assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+ } catch (PackageManagerException e) {
+ logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
+ try {
+ mInstaller.destroyAppData(volumeUuid, packageName, userId,
+ StorageManager.FLAG_STORAGE_CE, 0);
+ } catch (Installer.InstallerException e2) {
+ logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
+ }
+ }
+ }
+ }
+ if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
+ final File[] files = FileUtils.listFilesOrEmpty(deDir);
+ for (File file : files) {
+ final String packageName = file.getName();
+ try {
+ assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+ } catch (PackageManagerException e) {
+ logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
+ try {
+ mInstaller.destroyAppData(volumeUuid, packageName, userId,
+ StorageManager.FLAG_STORAGE_DE, 0);
+ } catch (Installer.InstallerException e2) {
+ logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
+ }
+ }
+ }
+ }
+
+ // Ensure that data directories are ready to roll for all packages
+ // installed for this volume and user
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "prepareAppDataAndMigrate");
+ Installer.Batch batch = new Installer.Batch();
+ final List<PackageSetting> packages;
+ synchronized (mPm.mLock) {
+ packages = mPm.mSettings.getVolumePackagesLPr(volumeUuid);
+ }
+ int preparedCount = 0;
+ for (PackageSetting ps : packages) {
+ final String packageName = ps.getPackageName();
+ if (ps.getPkg() == null) {
+ Slog.w(TAG, "Odd, missing scanned package " + packageName);
+ // TODO: might be due to legacy ASEC apps; we should circle back
+ // and reconcile again once they're scanned
+ continue;
+ }
+ // Skip non-core apps if requested
+ if (onlyCoreApps && !ps.getPkg().isCoreApp()) {
+ result.add(packageName);
+ continue;
+ }
+
+ if (ps.getInstalled(userId)) {
+ prepareAppDataAndMigrate(batch, ps.getPkg(), userId, flags, migrateAppData);
+ preparedCount++;
+ }
+ }
+ executeBatchLI(batch);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+ Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
+ return result;
+ }
+
+ private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
+ throws PackageManagerException {
+ synchronized (mPm.mLock) {
+ // Normalize package name to handle renamed packages
+ packageName = normalizePackageNameLPr(packageName);
+
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+ if (ps == null) {
+ throw new PackageManagerException("Package " + packageName + " is unknown");
+ } else if (!TextUtils.equals(volumeUuid, ps.getVolumeUuid())) {
+ throw new PackageManagerException(
+ "Package " + packageName + " found on unknown volume " + volumeUuid
+ + "; expected volume " + ps.getVolumeUuid());
+ } else if (!ps.getInstalled(userId)) {
+ throw new PackageManagerException(
+ "Package " + packageName + " not installed for user " + userId);
+ }
+ }
+ }
+
+ @GuardedBy("mPm.mLock")
+ private String normalizePackageNameLPr(String packageName) {
+ String normalizedPackageName = mPm.mSettings.getRenamedPackageLPr(packageName);
+ return normalizedPackageName != null ? normalizedPackageName : packageName;
+ }
+
+ /**
+ * Prepare storage for system user really early during boot,
+ * since core system apps like SettingsProvider and SystemUI
+ * can't wait for user to start
+ */
+ public Future<?> fixAppsDataOnBoot() {
+ final int storageFlags;
+ if (StorageManager.isFileEncryptedNativeOrEmulated()) {
+ storageFlags = StorageManager.FLAG_STORAGE_DE;
+ } else {
+ storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
+ }
+ List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
+ UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
+ true /* onlyCoreApps */);
+ Future<?> prepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
+ TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
+ Trace.TRACE_TAG_PACKAGE_MANAGER);
+ traceLog.traceBegin("AppDataFixup");
+ try {
+ mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
+ StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, "Trouble fixing GIDs", e);
+ }
+ traceLog.traceEnd();
+
+ traceLog.traceBegin("AppDataPrepare");
+ if (deferPackages == null || deferPackages.isEmpty()) {
+ return;
+ }
+ int count = 0;
+ final Installer.Batch batch = new Installer.Batch();
+ for (String pkgName : deferPackages) {
+ AndroidPackage pkg = null;
+ synchronized (mPm.mLock) {
+ PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+ if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
+ pkg = ps.getPkg();
+ }
+ }
+ if (pkg != null) {
+ prepareAppDataAndMigrate(batch, pkg, UserHandle.USER_SYSTEM, storageFlags,
+ true /* maybeMigrateAppData */);
+ count++;
+ }
+ }
+ synchronized (mPm.mInstallLock) {
+ executeBatchLI(batch);
+ }
+ traceLog.traceEnd();
+ Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
+ }, "prepareAppData");
+ return prepareAppDataFuture;
+ }
+
+ void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
+ if (pkg == null) {
+ return;
+ }
+ clearAppDataLeafLIF(pkg, userId, flags);
+
+ if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
+ clearAppProfilesLIF(pkg);
+ }
+ }
+
+ private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
+ final PackageSetting ps;
+ synchronized (mPm.mLock) {
+ ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+ }
+ for (int realUserId : mPm.resolveUserIds(userId)) {
+ final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
+ try {
+ mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+ flags, ceDataInode);
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, String.valueOf(e));
+ }
+ }
+ }
+
+ void clearAppProfilesLIF(AndroidPackage pkg) {
+ if (pkg == null) {
+ Slog.wtf(TAG, "Package was null!", new Throwable());
+ return;
+ }
+ mArtManagerService.clearAppProfiles(pkg);
+ }
+
+ public void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) {
+ if (pkg == null) {
+ Slog.wtf(TAG, "Package was null!", new Throwable());
+ return;
+ }
+ destroyAppDataLeafLIF(pkg, userId, flags);
+ }
+
+ public void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
+ final PackageSetting ps;
+ synchronized (mPm.mLock) {
+ ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+ }
+ for (int realUserId : mPm.resolveUserIds(userId)) {
+ final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
+ try {
+ mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+ flags, ceDataInode);
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, String.valueOf(e));
+ }
+ mPm.getDexManager().notifyPackageDataDestroyed(pkg.getPackageName(), userId);
+ }
+ }
+
+ public void destroyAppProfilesLIF(AndroidPackage pkg) {
+ if (pkg == null) {
+ Slog.wtf(TAG, "Package was null!", new Throwable());
+ return;
+ }
+ destroyAppProfilesLeafLIF(pkg);
+ }
+
+ private void destroyAppProfilesLeafLIF(AndroidPackage pkg) {
+ try {
+ mInstaller.destroyAppProfiles(pkg.getPackageName());
+ } catch (Installer.InstallerException e) {
+ Slog.w(TAG, String.valueOf(e));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 5b692b0..37879d7 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -50,7 +50,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.incremental.IncrementalManager;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -78,33 +77,32 @@
private static final boolean DEBUG_SD_INSTALL = false;
private final PackageManagerService mPm;
- private final IncrementalManager mIncrementalManager;
- private final Installer mInstaller;
private final UserManagerInternal mUserManagerInternal;
private final PermissionManagerServiceInternal mPermissionManager;
private final RemovePackageHelper mRemovePackageHelper;
private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+ private final AppDataHelper mAppDataHelper;
// TODO(b/198166813): remove PMS dependency
DeletePackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper,
- InitAndSystemPackageHelper initAndSystemPackageHelper) {
+ InitAndSystemPackageHelper initAndSystemPackageHelper,
+ AppDataHelper appDataHelper) {
mPm = pm;
- mIncrementalManager = mPm.mInjector.getIncrementalManager();
- mInstaller = mPm.mInjector.getInstaller();
mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
mRemovePackageHelper = removePackageHelper;
mInitAndSystemPackageHelper = initAndSystemPackageHelper;
+ mAppDataHelper = appDataHelper;
}
DeletePackageHelper(PackageManagerService pm) {
mPm = pm;
- mIncrementalManager = mPm.mInjector.getIncrementalManager();
- mInstaller = mPm.mInjector.getInstaller();
+ mAppDataHelper = new AppDataHelper(mPm);
mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
- mRemovePackageHelper = new RemovePackageHelper(mPm);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(mPm, mRemovePackageHelper);
+ mRemovePackageHelper = new RemovePackageHelper(mPm, mAppDataHelper);
+ mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(mPm, mRemovePackageHelper,
+ mAppDataHelper);
}
/**
@@ -457,7 +455,7 @@
pkg = mPm.mPackages.get(ps.getPackageName());
}
- mRemovePackageHelper.destroyAppProfilesLIF(pkg);
+ mAppDataHelper.destroyAppProfilesLIF(pkg);
final SharedUserSetting sus = ps.getSharedUser();
List<AndroidPackage> sharedUserPkgs = sus != null ? sus.getPackages() : null;
@@ -472,7 +470,7 @@
+ nextUserId);
}
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- mRemovePackageHelper.destroyAppDataLIF(pkg, nextUserId,
+ mAppDataHelper.destroyAppDataLIF(pkg, nextUserId,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
}
PackageManagerService.removeKeystoreDataIfNeeded(mUserManagerInternal, nextUserId,
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index 8c52630..9ba69f8 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -88,11 +88,14 @@
final class InitAndSystemPackageHelper {
private final PackageManagerService mPm;
private final RemovePackageHelper mRemovePackageHelper;
+ private final AppDataHelper mAppDataHelper;
// TODO(b/198166813): remove PMS dependency
- InitAndSystemPackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper) {
+ InitAndSystemPackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper,
+ AppDataHelper appDataHelper) {
mPm = pm;
mRemovePackageHelper = removePackageHelper;
+ mAppDataHelper = appDataHelper;
}
/**
@@ -571,7 +574,7 @@
mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
synchronized (mPm.mLock) {
- mPm.prepareAppDataAfterInstallLIF(pkg);
+ mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
try {
mPm.updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
Collections.unmodifiableMap(mPm.mPackages));
@@ -615,8 +618,9 @@
}
return false;
}
- mPm.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ mAppDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
+ | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(),
pkg.getBaseApkPath(), pkg.getSplitCodePaths());
}
@@ -839,7 +843,7 @@
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
- mPm.prepareAppDataAfterInstallLIF(pkg);
+ mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
// writer
synchronized (mPm.mLock) {
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
index 2187416..5a18d40 100644
--- a/services/core/java/com/android/server/pm/InstallParams.java
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -1840,6 +1840,7 @@
*/
private void executePostCommitSteps(CommitRequest commitRequest) {
final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
+ final AppDataHelper appDataHelper = new AppDataHelper(mPm);
for (ReconciledPackage reconciledPkg : commitRequest.mReconciledPackages.values()) {
final boolean instantApp = ((reconciledPkg.mScanResult.mRequest.mScanFlags
& SCAN_AS_INSTANT_APP) != 0);
@@ -1856,10 +1857,11 @@
}
incrementalStorages.add(storage);
}
- mPm.prepareAppDataAfterInstallLIF(pkg);
+ appDataHelper.prepareAppDataAfterInstallLIF(pkg);
if (reconciledPkg.mPrepareResult.mClearCodeCache) {
- mPm.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ appDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
+ | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
if (reconciledPkg.mPrepareResult.mReplace) {
mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index df54030..2bec8be 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -143,7 +143,6 @@
import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
@@ -199,7 +198,6 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
-import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.permission.PermissionManager;
import android.provider.ContactsContract;
@@ -224,7 +222,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TimingsTraceLog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -256,7 +253,6 @@
import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
-import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.apphibernation.AppHibernationService;
@@ -339,7 +335,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
@@ -417,7 +412,6 @@
static final boolean DEBUG_ABI_SELECTION = false;
public static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
- private static final boolean DEBUG_APP_DATA = false;
/** REMOVE. According to Svet, this was only used to reset permissions during development. */
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
@@ -1059,6 +1053,7 @@
private final RemovePackageHelper mRemovePackageHelper;
private final DeletePackageHelper mDeletePackageHelper;
private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+ private final AppDataHelper mAppDataHelper;
/**
* Invalidate the package info cache, which includes updating the cached computer.
@@ -1575,7 +1570,7 @@
Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
+ oldSeInfo + " to: " + newSeInfo);
ps.getPkgState().setOverrideSeInfo(newSeInfo);
- m.prepareAppDataAfterInstallLIF(pkg);
+ m.mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
}
}
};
@@ -1747,10 +1742,12 @@
mDomainVerificationConnection = new DomainVerificationConnection(this);
mBroadcastHelper = new BroadcastHelper(mInjector);
- mRemovePackageHelper = new RemovePackageHelper(this);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper);
+ mAppDataHelper = new AppDataHelper(this);
+ mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
+ mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper,
+ mAppDataHelper);
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
- mInitAndSystemPackageHelper);
+ mInitAndSystemPackageHelper, mAppDataHelper);
invalidatePackageInfoCache();
}
@@ -1896,10 +1893,12 @@
mDomainVerificationManager.setConnection(mDomainVerificationConnection);
mBroadcastHelper = new BroadcastHelper(mInjector);
- mRemovePackageHelper = new RemovePackageHelper(this);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper);
+ mAppDataHelper = new AppDataHelper(this);
+ mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
+ mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper,
+ mAppDataHelper);
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
- mInitAndSystemPackageHelper);
+ mInitAndSystemPackageHelper, mAppDataHelper);
synchronized (mLock) {
// Create the computer as soon as the state objects have been installed. The
@@ -2136,56 +2135,7 @@
}
}
- // Prepare storage for system user really early during boot,
- // since core system apps like SettingsProvider and SystemUI
- // can't wait for user to start
- final int storageFlags;
- if (StorageManager.isFileEncryptedNativeOrEmulated()) {
- storageFlags = StorageManager.FLAG_STORAGE_DE;
- } else {
- storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
- }
- List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
- UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
- true /* onlyCoreApps */);
- mPrepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
- TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
- Trace.TRACE_TAG_PACKAGE_MANAGER);
- traceLog.traceBegin("AppDataFixup");
- try {
- mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
- } catch (InstallerException e) {
- Slog.w(TAG, "Trouble fixing GIDs", e);
- }
- traceLog.traceEnd();
-
- traceLog.traceBegin("AppDataPrepare");
- if (deferPackages == null || deferPackages.isEmpty()) {
- return;
- }
- int count = 0;
- final Installer.Batch batch = new Installer.Batch();
- for (String pkgName : deferPackages) {
- AndroidPackage pkg = null;
- synchronized (mLock) {
- PackageSetting ps = mSettings.getPackageLPr(pkgName);
- if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
- pkg = ps.getPkg();
- }
- }
- if (pkg != null) {
- prepareAppDataAndMigrate(batch, pkg, UserHandle.USER_SYSTEM, storageFlags,
- true /* maybeMigrateAppData */);
- count++;
- }
- }
- synchronized (mInstallLock) {
- executeBatchLI(batch);
- }
- traceLog.traceEnd();
- Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
- }, "prepareAppData");
+ mPrepareAppDataFuture = mAppDataHelper.fixAppsDataOnBoot();
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
@@ -2198,7 +2148,7 @@
final PackageSetting ps = packageSettings.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.getVolumeUuid())) {
// No apps are running this early, so no need to freeze
- clearAppDataLIF(ps.getPkg(), UserHandle.USER_ALL,
+ mAppDataHelper.clearAppDataLIF(ps.getPkg(), UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY
| Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
@@ -3051,11 +3001,6 @@
filterCallingUid, userId);
}
- @GuardedBy("mLock")
- private String normalizePackageNameLPr(String packageName) {
- String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
- return normalizedPackageName != null ? normalizedPackageName : packageName;
- }
@Override
public void deletePreloadsFileCache() {
@@ -6534,41 +6479,6 @@
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
- void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
- if (pkg == null) {
- return;
- }
- clearAppDataLeafLIF(pkg, userId, flags);
-
- if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
- clearAppProfilesLIF(pkg);
- }
- }
-
- private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
- final PackageSetting ps;
- synchronized (mLock) {
- ps = mSettings.getPackageLPr(pkg.getPackageName());
- }
- for (int realUserId : resolveUserIds(userId)) {
- final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
- try {
- mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
- flags, ceDataInode);
- } catch (InstallerException e) {
- Slog.w(TAG, String.valueOf(e));
- }
- }
- }
-
- void clearAppProfilesLIF(AndroidPackage pkg) {
- if (pkg == null) {
- Slog.wtf(TAG, "Package was null!", new Throwable());
- return;
- }
- mArtManagerService.clearAppProfiles(pkg);
- }
-
@GuardedBy("mLock")
private void applyDefiningSharedLibraryUpdateLocked(
AndroidPackage pkg, SharedLibraryInfo libInfo,
@@ -7834,7 +7744,7 @@
if (pkgSetting.getPkg() != null) {
synchronized (mInstallLock) {
// We don't need to freeze for a brand new install
- prepareAppDataAfterInstallLIF(pkgSetting.getPkg());
+ mAppDataHelper.prepareAppDataAfterInstallLIF(pkgSetting.getPkg());
}
}
sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE);
@@ -9435,7 +9345,7 @@
try (PackageFreezer freezer = freezePackage(packageName, "clearApplicationProfileData")) {
synchronized (mInstallLock) {
- clearAppProfilesLIF(pkg);
+ mAppDataHelper.clearAppProfilesLIF(pkg);
}
}
}
@@ -9527,7 +9437,7 @@
}
mPermissionManager.resetRuntimePermissions(pkg, userId);
- clearAppDataLIF(pkg, userId,
+ mAppDataHelper.clearAppDataLIF(pkg, userId,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
final int appId = UserHandle.getAppId(pkg.getUid());
@@ -9543,7 +9453,7 @@
} else {
flags = 0;
}
- prepareAppDataContentsLIF(pkg, ps, userId, flags);
+ mAppDataHelper.prepareAppDataContentsLIF(pkg, ps, userId, flags);
return true;
}
@@ -9627,8 +9537,10 @@
final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
// We're only clearing cache files, so we don't care if the
// app is unfrozen and still able to run
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ mAppDataHelper.clearAppDataLIF(pkg, userId,
+ flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+ mAppDataHelper.clearAppDataLIF(pkg, userId,
+ flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
if (observer != null) {
@@ -12325,382 +12237,6 @@
}
}
- private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
- throws PackageManagerException {
- synchronized (mLock) {
- // Normalize package name to handle renamed packages
- packageName = normalizePackageNameLPr(packageName);
-
- final PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps == null) {
- throw new PackageManagerException("Package " + packageName + " is unknown");
- } else if (!TextUtils.equals(volumeUuid, ps.getVolumeUuid())) {
- throw new PackageManagerException(
- "Package " + packageName + " found on unknown volume " + volumeUuid
- + "; expected volume " + ps.getVolumeUuid());
- } else if (!ps.getInstalled(userId)) {
- throw new PackageManagerException(
- "Package " + packageName + " not installed for user " + userId);
- }
- }
- }
-
- private void executeBatchLI(@NonNull Installer.Batch batch) {
- try {
- batch.execute(mInstaller);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to execute pending operations", e);
- }
- }
-
- /**
- * Reconcile all app data for the given user.
- * <p>
- * Verifies that directories exist and that ownership and labeling is
- * correct for all installed apps on all mounted volumes.
- */
- @NonNull
- void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
- final StorageManager storage = mInjector.getSystemService(StorageManager.class);
- for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
- final String volumeUuid = vol.getFsUuid();
- synchronized (mInstallLock) {
- reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData);
- }
- }
- }
-
- @GuardedBy("mInstallLock")
- void reconcileAppsDataLI(String volumeUuid, int userId, int flags,
- boolean migrateAppData) {
- reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */);
- }
-
- /**
- * Reconcile all app data on given mounted volume.
- * <p>
- * Destroys app data that isn't expected, either due to uninstallation or
- * reinstallation on another volume.
- * <p>
- * Verifies that directories exist and that ownership and labeling is
- * correct for all installed apps.
- * @return list of skipped non-core packages (if {@code onlyCoreApps} is true)
- */
- @GuardedBy("mInstallLock")
- private List<String> reconcileAppsDataLI(String volumeUuid, int userId, int flags,
- boolean migrateAppData, boolean onlyCoreApps) {
- Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
- + Integer.toHexString(flags) + " migrateAppData=" + migrateAppData);
- List<String> result = onlyCoreApps ? new ArrayList<>() : null;
-
- final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
- final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
-
- // First look for stale data that doesn't belong, and check if things
- // have changed since we did our last restorecon
- if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
- if (StorageManager.isFileEncryptedNativeOrEmulated()
- && !StorageManager.isUserKeyUnlocked(userId)) {
- throw new RuntimeException(
- "Yikes, someone asked us to reconcile CE storage while " + userId
- + " was still locked; this would have caused massive data loss!");
- }
-
- final File[] files = FileUtils.listFilesOrEmpty(ceDir);
- for (File file : files) {
- final String packageName = file.getName();
- try {
- assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
- } catch (PackageManagerException e) {
- logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
- try {
- mInstaller.destroyAppData(volumeUuid, packageName, userId,
- StorageManager.FLAG_STORAGE_CE, 0);
- } catch (InstallerException e2) {
- logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
- }
- }
- }
- }
- if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
- final File[] files = FileUtils.listFilesOrEmpty(deDir);
- for (File file : files) {
- final String packageName = file.getName();
- try {
- assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
- } catch (PackageManagerException e) {
- logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
- try {
- mInstaller.destroyAppData(volumeUuid, packageName, userId,
- StorageManager.FLAG_STORAGE_DE, 0);
- } catch (InstallerException e2) {
- logCriticalInfo(Log.WARN, "Failed to destroy: " + e2);
- }
- }
- }
- }
-
- // Ensure that data directories are ready to roll for all packages
- // installed for this volume and user
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "prepareAppDataAndMigrate");
- Installer.Batch batch = new Installer.Batch();
- final List<PackageSetting> packages;
- synchronized (mLock) {
- packages = mSettings.getVolumePackagesLPr(volumeUuid);
- }
- int preparedCount = 0;
- for (PackageSetting ps : packages) {
- final String packageName = ps.getPackageName();
- if (ps.getPkg() == null) {
- Slog.w(TAG, "Odd, missing scanned package " + packageName);
- // TODO: might be due to legacy ASEC apps; we should circle back
- // and reconcile again once they're scanned
- continue;
- }
- // Skip non-core apps if requested
- if (onlyCoreApps && !ps.getPkg().isCoreApp()) {
- result.add(packageName);
- continue;
- }
-
- if (ps.getInstalled(userId)) {
- prepareAppDataAndMigrate(batch, ps.getPkg(), userId, flags, migrateAppData);
- preparedCount++;
- }
- }
- executeBatchLI(batch);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
- Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
- return result;
- }
-
- /**
- * Prepare app data for the given app just after it was installed or
- * upgraded. This method carefully only touches users that it's installed
- * for, and it forces a restorecon to handle any seinfo changes.
- * <p>
- * Verifies that directories exist and that ownership and labeling is
- * correct for all installed apps. If there is an ownership mismatch, it
- * will try recovering system apps by wiping data; third-party app data is
- * left intact.
- * <p>
- * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
- */
- void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
- final PackageSetting ps;
- synchronized (mLock) {
- ps = mSettings.getPackageLPr(pkg.getPackageName());
- mSettings.writeKernelMappingLPr(ps);
- }
-
- Installer.Batch batch = new Installer.Batch();
- UserManagerInternal umInternal = mInjector.getUserManagerInternal();
- StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class);
- for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
- final int flags;
- if (StorageManager.isUserKeyUnlocked(user.id)
- && smInternal.isCeStoragePrepared(user.id)) {
- flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
- } else if (umInternal.isUserRunning(user.id)) {
- flags = StorageManager.FLAG_STORAGE_DE;
- } else {
- continue;
- }
-
- // TODO@ashfall check ScanResult.mNeedsNewAppId, and if true instead
- // of creating app data, migrate / change ownership of existing
- // data.
-
- if (ps.getInstalled(user.id)) {
- // TODO: when user data is locked, mark that we're still dirty
- prepareAppData(batch, pkg, user.id, flags).thenRun(() -> {
- // Note: this code block is executed with the Installer lock
- // already held, since it's invoked as a side-effect of
- // executeBatchLI()
- if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
- // Prepare app data on external storage; currently this is used to
- // setup any OBB dirs that were created by the installer correctly.
- int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid()));
- smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid);
- }
- });
- }
- }
- executeBatchLI(batch);
- }
-
- /**
- * Prepare app data for the given app.
- * <p>
- * Verifies that directories exist and that ownership and labeling is
- * correct for all installed apps. If there is an ownership mismatch, this
- * will try recovering system apps by wiping data; third-party app data is
- * left intact.
- */
- private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
- @Nullable AndroidPackage pkg, int userId, int flags) {
- if (pkg == null) {
- Slog.wtf(TAG, "Package was null!", new Throwable());
- return CompletableFuture.completedFuture(null);
- }
- return prepareAppDataLeaf(batch, pkg, userId, flags);
- }
-
- private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
- @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) {
- prepareAppData(batch, pkg, userId, flags).thenRun(() -> {
- // Note: this code block is executed with the Installer lock
- // already held, since it's invoked as a side-effect of
- // executeBatchLI()
- if (maybeMigrateAppData && maybeMigrateAppDataLIF(pkg, userId)) {
- // We may have just shuffled around app data directories, so
- // prepare them one more time
- final Installer.Batch batchInner = new Installer.Batch();
- prepareAppData(batchInner, pkg, userId, flags);
- executeBatchLI(batchInner);
- }
- });
- }
-
- private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch,
- @NonNull AndroidPackage pkg, int userId, int flags) {
- if (DEBUG_APP_DATA) {
- Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
- + Integer.toHexString(flags));
- }
-
- final PackageSetting ps;
- final String seInfoUser;
- synchronized (mLock) {
- ps = mSettings.getPackageLPr(pkg.getPackageName());
- seInfoUser = SELinuxUtil.getSeinfoUser(ps.readUserState(userId));
- }
- final String volumeUuid = pkg.getVolumeUuid();
- final String packageName = pkg.getPackageName();
-
- final int appId = UserHandle.getAppId(pkg.getUid());
-
- String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
-
- Preconditions.checkNotNull(pkgSeInfo);
-
- final String seInfo = pkgSeInfo + seInfoUser;
- final int targetSdkVersion = pkg.getTargetSdkVersion();
-
- return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo,
- targetSdkVersion).whenComplete((ceDataInode, e) -> {
- // Note: this code block is executed with the Installer lock
- // already held, since it's invoked as a side-effect of
- // executeBatchLI()
- if (e != null) {
- logCriticalInfo(Log.WARN, "Failed to create app data for " + packageName
- + ", but trying to recover: " + e);
- mRemovePackageHelper.destroyAppDataLeafLIF(pkg, userId, flags);
- try {
- ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId,
- flags, appId, seInfo, pkg.getTargetSdkVersion());
- logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
- } catch (InstallerException e2) {
- logCriticalInfo(Log.DEBUG, "Recovery failed!");
- }
- }
-
- // Prepare the application profiles only for upgrades and
- // first boot (so that we don't repeat the same operation at
- // each boot).
- //
- // We only have to cover the upgrade and first boot here
- // because for app installs we prepare the profiles before
- // invoking dexopt (in installPackageLI).
- //
- // We also have to cover non system users because we do not
- // call the usual install package methods for them.
- //
- // NOTE: in order to speed up first boot time we only create
- // the current profile and do not update the content of the
- // reference profile. A system image should already be
- // configured with the right profile keys and the profiles
- // for the speed-profile prebuilds should already be copied.
- // That's done in #performDexOptUpgrade.
- //
- // TODO(calin, mathieuc): We should use .dm files for
- // prebuilds profiles instead of manually copying them in
- // #performDexOptUpgrade. When we do that we should have a
- // more granular check here and only update the existing
- // profiles.
- if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
- mArtManagerService.prepareAppProfiles(pkg, userId,
- /* updateReferenceProfileContent= */ false);
- }
-
- if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
- // TODO: mark this structure as dirty so we persist it!
- synchronized (mLock) {
- if (ps != null) {
- ps.setCeDataInode(ceDataInode, userId);
- }
- }
- }
-
- prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
- });
- }
-
- private void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting,
- int userId, int flags) {
- if (pkg == null) {
- Slog.wtf(TAG, "Package was null!", new Throwable());
- return;
- }
- prepareAppDataContentsLeafLIF(pkg, pkgSetting, userId, flags);
- }
-
- private void prepareAppDataContentsLeafLIF(AndroidPackage pkg,
- @Nullable PackageSetting pkgSetting, int userId, int flags) {
- final String volumeUuid = pkg.getVolumeUuid();
- final String packageName = pkg.getPackageName();
-
- if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
- // Create a native library symlink only if we have native libraries
- // and if the native libraries are 32 bit libraries. We do not provide
- // this symlink for 64 bit libraries.
- String primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
- if (primaryCpuAbi != null && !VMRuntime.is64BitAbi(primaryCpuAbi)) {
- final String nativeLibPath = pkg.getNativeLibraryDir();
- try {
- mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
- nativeLibPath, userId);
- } catch (InstallerException e) {
- Slog.e(TAG, "Failed to link native for " + packageName + ": " + e);
- }
- }
- }
- }
-
- /**
- * For system apps on non-FBE devices, this method migrates any existing
- * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
- * requested by the app.
- */
- private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) {
- if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated()
- && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
- final int storageTarget = pkg.isDefaultToDeviceProtectedStorage()
- ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
- try {
- mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId,
- storageTarget);
- } catch (InstallerException e) {
- logCriticalInfo(Log.WARN,
- "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage());
- }
- return true;
- } else {
- return false;
- }
- }
-
public PackageFreezer freezePackage(String packageName, String killReason) {
return freezePackage(packageName, UserHandle.USER_ALL, killReason);
}
@@ -14635,6 +14171,12 @@
return block.apply(snapshot::getPackageSetting);
}
}
+
+ @Override
+ public void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
+ PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
+ migrateAppsData);
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 0b5c5c8..7596cdf 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -57,14 +57,20 @@
private final Installer mInstaller;
private final UserManagerInternal mUserManagerInternal;
private final PermissionManagerServiceInternal mPermissionManager;
+ private final AppDataHelper mAppDataHelper;
// TODO(b/198166813): remove PMS dependency
- RemovePackageHelper(PackageManagerService pm) {
+ RemovePackageHelper(PackageManagerService pm, AppDataHelper appDataHelper) {
mPm = pm;
mIncrementalManager = mPm.mInjector.getIncrementalManager();
mInstaller = mPm.mInjector.getInstaller();
mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
+ mAppDataHelper = appDataHelper;
+ }
+
+ RemovePackageHelper(PackageManagerService pm) {
+ this(pm, new AppDataHelper(pm));
}
@GuardedBy("mPm.mInstallLock")
@@ -231,9 +237,9 @@
resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.getPackageName(),
deletedPs.getVolumeUuid());
}
- destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
+ mAppDataHelper.destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
- destroyAppProfilesLIF(resolvedPkg);
+ mAppDataHelper.destroyAppProfilesLIF(resolvedPkg);
if (outInfo != null) {
outInfo.mDataRemoved = true;
}
@@ -315,45 +321,4 @@
mUserManagerInternal, UserHandle.USER_ALL, removedAppId);
}
}
-
- public void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) {
- if (pkg == null) {
- Slog.wtf(TAG, "Package was null!", new Throwable());
- return;
- }
- destroyAppDataLeafLIF(pkg, userId, flags);
- }
-
- public void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
- final PackageSetting ps;
- synchronized (mPm.mLock) {
- ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
- }
- for (int realUserId : mPm.resolveUserIds(userId)) {
- final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
- try {
- mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
- flags, ceDataInode);
- } catch (Installer.InstallerException e) {
- Slog.w(TAG, String.valueOf(e));
- }
- mPm.getDexManager().notifyPackageDataDestroyed(pkg.getPackageName(), userId);
- }
- }
-
- public void destroyAppProfilesLIF(AndroidPackage pkg) {
- if (pkg == null) {
- Slog.wtf(TAG, "Package was null!", new Throwable());
- return;
- }
- destroyAppProfilesLeafLIF(pkg);
- }
-
- private void destroyAppProfilesLeafLIF(AndroidPackage pkg) {
- try {
- mInstaller.destroyAppProfiles(pkg.getPackageName());
- } catch (Installer.InstallerException e) {
- Slog.w(TAG, String.valueOf(e));
- }
- }
}
diff --git a/services/core/java/com/android/server/pm/ScanPackageHelper.java b/services/core/java/com/android/server/pm/ScanPackageHelper.java
index 3bf0af7..ef06c58 100644
--- a/services/core/java/com/android/server/pm/ScanPackageHelper.java
+++ b/services/core/java/com/android/server/pm/ScanPackageHelper.java
@@ -1125,7 +1125,8 @@
return;
}
- mPm.clearAppProfilesLIF(pkg);
+ final AppDataHelper appDataHelper = new AppDataHelper(mPm);
+ appDataHelper.clearAppProfilesLIF(pkg);
if (DEBUG_INSTALL) {
Slog.d(TAG, originalPkgSetting.getPackageName()
+ " clear profile due to version change "
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 4b530b5..a82cb9e 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -129,6 +129,7 @@
return;
}
+ final AppDataHelper appDataHelper = new AppDataHelper(mPm);
final ArrayList<PackageFreezer> freezers = new ArrayList<>();
final ArrayList<AndroidPackage> loaded = new ArrayList<>();
final int parseFlags = mPm.mDefParseFlags | ParsingPackageUtils.PARSE_EXTERNAL_STORAGE;
@@ -155,7 +156,7 @@
}
if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
- mPm.clearAppDataLIF(
+ appDataHelper.clearAppDataLIF(
ps.getPkg(), UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY
| Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
@@ -182,7 +183,8 @@
try {
sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags);
synchronized (mPm.mInstallLock) {
- mPm.reconcileAppsDataLI(volumeUuid, user.id, flags, true /* migrateAppData */);
+ appDataHelper.reconcileAppsDataLI(volumeUuid, user.id, flags,
+ true /* migrateAppData */);
}
} catch (IllegalStateException e) {
// Device was probably ejected, and we'll process that event momentarily
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 30c77f9..302826f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4816,7 +4816,8 @@
mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
t.traceEnd();
t.traceBegin("reconcileAppsData");
- mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData);
+ getPackageManagerInternal().reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE,
+ migrateAppsData);
t.traceEnd();
if (userId != UserHandle.USER_SYSTEM) {
@@ -4851,7 +4852,8 @@
smInternal.markCeStoragePrepared(userId);
t.traceBegin("reconcileAppsData-" + userId);
- mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData);
+ getPackageManagerInternal().reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE,
+ migrateAppsData);
t.traceEnd();
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 3a1ffe1..626146c2 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -140,7 +140,8 @@
UserManager.DISALLOW_PRINTING,
UserManager.DISALLOW_CONFIG_PRIVATE_DNS,
UserManager.DISALLOW_MICROPHONE_TOGGLE,
- UserManager.DISALLOW_CAMERA_TOGGLE
+ UserManager.DISALLOW_CAMERA_TOGGLE,
+ UserManager.DISALLOW_CHANGE_WIFI_STATE
});
public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet(
@@ -184,7 +185,8 @@
UserManager.DISALLOW_USER_SWITCH,
UserManager.DISALLOW_CONFIG_PRIVATE_DNS,
UserManager.DISALLOW_MICROPHONE_TOGGLE,
- UserManager.DISALLOW_CAMERA_TOGGLE
+ UserManager.DISALLOW_CAMERA_TOGGLE,
+ UserManager.DISALLOW_CHANGE_WIFI_STATE
);
/**
@@ -219,7 +221,8 @@
Sets.newArraySet(
UserManager.DISALLOW_AIRPLANE_MODE,
UserManager.DISALLOW_CONFIG_DATE_TIME,
- UserManager.DISALLOW_CONFIG_PRIVATE_DNS
+ UserManager.DISALLOW_CONFIG_PRIVATE_DNS,
+ UserManager.DISALLOW_CHANGE_WIFI_STATE
);
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 12e6086d..5d34939 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -47,7 +47,6 @@
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -3291,18 +3290,7 @@
final boolean showing = mKeyguardDelegate.isShowing();
final boolean animate = showing && !isOccluded;
mKeyguardDelegate.setOccluded(isOccluded, animate);
-
- if (!showing) {
- return false;
- }
- if (mKeyguardCandidate != null) {
- if (isOccluded) {
- mKeyguardCandidate.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
- } else if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
- mKeyguardCandidate.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
- }
- }
- return true;
+ return showing;
}
/** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 86ff33e..cdd36f7 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -235,13 +235,6 @@
return false;
}
- public boolean hasLockscreenWallpaper() {
- if (mKeyguardService != null) {
- return mKeyguardService.hasLockscreenWallpaper();
- }
- return false;
- }
-
public boolean hasKeyguard() {
return mKeyguardState.deviceHasKeyguard;
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index c356fec..2029f86 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -267,10 +267,6 @@
return mKeyguardStateMonitor.isTrusted();
}
- public boolean hasLockscreenWallpaper() {
- return mKeyguardStateMonitor.hasLockscreenWallpaper();
- }
-
public boolean isSecure(int userId) {
return mKeyguardStateMonitor.isSecure(userId);
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f0f62ed..c0aa8ae 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -44,7 +44,6 @@
private volatile boolean mSimSecure = true;
private volatile boolean mInputRestricted = true;
private volatile boolean mTrusted = false;
- private volatile boolean mHasLockscreenWallpaper = false;
private int mCurrentUserId;
@@ -79,10 +78,6 @@
return mTrusted;
}
- public boolean hasLockscreenWallpaper() {
- return mHasLockscreenWallpaper;
- }
-
public int getCurrentUser() {
return mCurrentUserId;
}
@@ -116,11 +111,6 @@
mCallback.onTrustedChanged();
}
- @Override // Binder interface
- public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) {
- mHasLockscreenWallpaper = hasLockscreenWallpaper;
- }
-
public interface StateCallback {
void onTrustedChanged();
void onShowingChanged();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 7ac9110..00d01e1 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -23,6 +23,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.ITransientNotificationCallback;
@@ -1689,7 +1690,7 @@
}
@Override
- public int requestAddTile(
+ public void requestAddTile(
@NonNull ComponentName componentName,
@NonNull CharSequence label,
@NonNull Icon icon,
@@ -1710,13 +1711,35 @@
// Check current user
if (userId != currentUser) {
- return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER;
+ try {
+ callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "requestAddTile", e);
+ }
+ return;
}
// We've checked that the package, component name and uid all match.
ResolveInfo r = isComponentValidTileService(componentName, userId);
- if (r == null) {
- return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT;
+ if (r == null || !r.serviceInfo.exported) {
+ try {
+ callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "requestAddTile", e);
+ }
+ return;
+ }
+
+ final int procState = mActivityManagerInternal.getUidProcessState(callingUid);
+ if (ActivityManager.RunningAppProcessInfo.procStateToImportance(procState)
+ != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ try {
+ callback.onTileRequest(
+ StatusBarManager.TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "requestAddTile", e);
+ }
+ return;
}
IAddTileResultCallback proxyCallback = new IAddTileResultCallback.Stub() {
@@ -1734,12 +1757,16 @@
if (mBar != null) {
try {
mBar.requestAddTile(componentName, appName, label, icon, proxyCallback);
- return StatusBarManager.TILE_ADD_REQUEST_ANSWER_SUCCESS;
} catch (RemoteException e) {
Slog.e(TAG, "requestAddTile", e);
}
+ return;
}
- return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON;
+ try {
+ callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "requestAddTile", e);
+ }
}
public String[] getStatusBarIcons() {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index b71ad2e..6ad2f7c 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -501,6 +501,8 @@
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions,
@Nullable IBinder resultTo) {
+ final ActivityRecord caller =
+ resultTo != null ? ActivityRecord.forTokenLocked(resultTo) : null;
return obtainStarter(activityIntent, "startActivityInTaskFragment")
.setActivityOptions(activityOptions)
.setInTaskFragment(taskFragment)
@@ -508,6 +510,7 @@
.setRequestCode(-1)
.setCallingUid(Binder.getCallingUid())
.setCallingPid(Binder.getCallingPid())
+ .setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
.execute();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 93910f3..d944c58 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2013,7 +2013,7 @@
// Allowing the embedding if the task is owned by system.
final int hostUid = hostTask.effectiveUid;
- if (hostUid == Process.SYSTEM_UID) {
+ if (UserHandle.getAppId(hostUid) == Process.SYSTEM_UID) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index ffaf710..535a061 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -124,6 +124,7 @@
@interface TransitContainerType {}
private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>();
+ private final ArrayList<WindowContainer> mTempTransitionWindows = new ArrayList<>();
AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
@@ -523,26 +524,44 @@
}
}
+ private boolean transitionMayContainNonAppWindows(@TransitionOldType int transit) {
+ // We don't want to have the client to animate any non-app windows.
+ // Having {@code transit} of those types doesn't mean it will contain non-app windows, but
+ // non-app windows will only be included with those transition types. And we don't currently
+ // have any use case of those for TaskFragment transition.
+ // @see NonAppWindowAnimationAdapter#startNonAppWindowAnimations
+ if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+ || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+ || transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
+ || transit == TRANSIT_OLD_WALLPAPER_CLOSE) {
+ return true;
+ }
+
+ // Check if the wallpaper is going to participate in the transition. We don't want to have
+ // the client to animate the wallpaper windows.
+ // @see WallpaperAnimationAdapter#startWallpaperAnimations
+ return mDisplayContent.mWallpaperController.isWallpaperVisible();
+ }
+
/**
- * Overrides the pending transition with the remote animation defined by the
- * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
- * {@link TaskFragment} that are organized by the same organizer.
- *
- * @return {@code true} if the transition is overridden.
+ * Finds the common {@link android.window.TaskFragmentOrganizer} that organizes all app windows
+ * in the current transition.
+ * @return {@code null} if there is no such organizer, or if there are more than one.
*/
- private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
- ArraySet<Integer> activityTypes) {
- final ArrayList<WindowContainer> allWindows = new ArrayList<>();
- allWindows.addAll(mDisplayContent.mClosingApps);
- allWindows.addAll(mDisplayContent.mOpeningApps);
- allWindows.addAll(mDisplayContent.mChangingContainers);
+ @Nullable
+ private ITaskFragmentOrganizer findTaskFragmentOrganizerForAllWindows() {
+ mTempTransitionWindows.clear();
+ mTempTransitionWindows.addAll(mDisplayContent.mClosingApps);
+ mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps);
+ mTempTransitionWindows.addAll(mDisplayContent.mChangingContainers);
// It should only animated by the organizer if all windows are below the same leaf Task.
Task leafTask = null;
- for (int i = allWindows.size() - 1; i >= 0; i--) {
- final ActivityRecord r = getAppFromContainer(allWindows.get(i));
+ for (int i = mTempTransitionWindows.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = getAppFromContainer(mTempTransitionWindows.get(i));
if (r == null) {
- return false;
+ leafTask = null;
+ break;
}
// The activity may be a child of embedded Task, but we want to find the owner Task.
// As a result, find the organized TaskFragment first.
@@ -561,26 +580,31 @@
? organizedTaskFragment.getTask()
: r.getTask();
if (task == null) {
- return false;
+ leafTask = null;
+ break;
}
// We don't want the organizer to handle transition of other non-embedded Task.
if (leafTask != null && leafTask != task) {
- return false;
+ leafTask = null;
+ break;
}
final ActivityRecord rootActivity = task.getRootActivity();
// We don't want the organizer to handle transition when the whole app is closing.
if (rootActivity == null) {
- return false;
+ leafTask = null;
+ break;
}
// We don't want the organizer to handle transition of non-embedded activity of other
// app.
if (r.getUid() != rootActivity.getUid() && !r.isEmbedded()) {
- return false;
+ leafTask = null;
+ break;
}
leafTask = task;
}
+ mTempTransitionWindows.clear();
if (leafTask == null) {
- return false;
+ return null;
}
// We don't support remote animation for Task with multiple TaskFragmentOrganizers.
@@ -599,12 +623,28 @@
if (hasMultipleOrganizers) {
ProtoLog.e(WM_DEBUG_APP_TRANSITIONS, "We don't support remote animation for"
+ " Task with multiple TaskFragmentOrganizers.");
+ return null;
+ }
+ return organizer[0];
+ }
+
+ /**
+ * Overrides the pending transition with the remote animation defined by the
+ * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
+ * {@link TaskFragment} that are organized by the same organizer.
+ *
+ * @return {@code true} if the transition is overridden.
+ */
+ private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
+ ArraySet<Integer> activityTypes) {
+ if (transitionMayContainNonAppWindows(transit)) {
return false;
}
- final RemoteAnimationDefinition definition = organizer[0] != null
+ final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizerForAllWindows();
+ final RemoteAnimationDefinition definition = organizer != null
? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
- .getRemoteAnimationDefinition(organizer[0])
+ .getRemoteAnimationDefinition(organizer)
: null;
final RemoteAnimationAdapter adapter = definition != null
? definition.getAdapter(transit, activityTypes)
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 881bd35..c9a8d94 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -913,15 +913,6 @@
// letterboxed. Hence always let them extend under the cutout.
attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
break;
- case TYPE_NOTIFICATION_SHADE:
- // If the Keyguard is in a hidden state (occluded by another window), we force to
- // remove the wallpaper and keyguard flag so that any change in-flight after setting
- // the keyguard as occluded wouldn't set these flags again.
- // See {@link #processKeyguardSetHiddenResultLw}.
- if (mService.mPolicy.isKeyguardOccluded()) {
- attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
- }
- break;
case TYPE_TOAST:
// While apps should use the dedicated toast APIs to add such windows
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c630e91..bd41de3 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -194,8 +194,7 @@
if (keyguardChanged) {
// Irrelevant to AOD.
- dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */,
- false /* turningScreenOn */);
+ dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */);
mKeyguardGoingAway = false;
if (keyguardShowing) {
mDismissalRequested = false;
@@ -396,6 +395,8 @@
mService.continueWindowLayout();
}
}
+ dismissMultiWindowModeForTaskIfNeeded(topActivity != null
+ ? topActivity.getRootTask() : null);
}
/**
@@ -421,21 +422,6 @@
}
}
- /**
- * Called when somebody wants to turn screen on.
- */
- private void handleTurnScreenOn(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
-
- mTaskSupervisor.wakeUp("handleTurnScreenOn");
- if (mKeyguardShowing && canDismissKeyguard()) {
- mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
- mDismissalRequested = true;
- }
- }
-
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
@@ -449,11 +435,9 @@
}
private void dismissMultiWindowModeForTaskIfNeeded(
- @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) {
- // If turningScreenOn is true, it means that the visibility state has changed from
- // currentTaskControllingOcclusion and we should update windowing mode.
+ @Nullable Task currentTaskControllingOcclusion) {
// TODO(b/113840485): Handle docked stack for individual display.
- if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) {
+ if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
return;
}
@@ -592,26 +576,17 @@
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
- boolean occludingChange = false;
- boolean turningScreenOn = false;
if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
&& mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity
- || controller.canDismissKeyguard())) {
- turningScreenOn = true;
- controller.handleTurnScreenOn(mDisplayId);
+ && (mRequestDismissKeyguard || occludedByActivity)) {
+ controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
- occludingChange = true;
controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
}
-
- if (occludingChange || turningScreenOn) {
- controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn);
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index a663c62..22c8459 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -793,7 +793,7 @@
private RemoteAnimationTarget[] createWallpaperAnimations() {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "createWallpaperAnimations()");
- return WallpaperAnimationAdapter.startWallpaperAnimations(mService, 0L, 0L,
+ return WallpaperAnimationAdapter.startWallpaperAnimations(mDisplayContent, 0L, 0L,
adapter -> {
synchronized (mService.mGlobalLock) {
// If the wallpaper animation is canceled, continue with the recents
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 16a45fe..ca1aed5 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -207,7 +207,7 @@
if (wrappers.mThumbnailAdapter != null
&& wrappers.mThumbnailAdapter.mCapturedFinishCallback != null) {
wrappers.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(wrappers.mAdapter.mAnimationType,
+ .onAnimationFinished(wrappers.mThumbnailAdapter.mAnimationType,
wrappers.mThumbnailAdapter);
}
mPendingAnimations.remove(i);
@@ -218,7 +218,7 @@
private RemoteAnimationTarget[] createWallpaperAnimations() {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createWallpaperAnimations()");
- return WallpaperAnimationAdapter.startWallpaperAnimations(mService,
+ return WallpaperAnimationAdapter.startWallpaperAnimations(mDisplayContent,
mRemoteAnimationAdapter.getDuration(),
mRemoteAnimationAdapter.getStatusBarTransitionDelay(),
adapter -> {
@@ -260,7 +260,7 @@
}
if (adapters.mThumbnailAdapter != null) {
adapters.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(adapters.mAdapter.mAnimationType,
+ .onAnimationFinished(adapters.mThumbnailAdapter.mAnimationType,
adapters.mThumbnailAdapter);
}
mPendingAnimations.remove(i);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 1a881f7..d9f0091 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2151,6 +2151,9 @@
final Task rootTask;
if (singleActivity) {
rootTask = task;
+
+ // Apply the last recents animation leash transform to the task entering PIP
+ rootTask.maybeApplyLastRecentsAnimationTransaction();
} else {
// In the case of multiple activities, we will create a new task for it and then
// move the PIP activity into the task. Note that we explicitly defer the task
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c7bf8ec..d712bbf 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -57,8 +57,11 @@
@VisibleForTesting
SurfaceControl mLeash;
@VisibleForTesting
+ SurfaceFreezer.Snapshot mSnapshot;
+ @VisibleForTesting
final Animatable mAnimatable;
- private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
+ @VisibleForTesting
+ final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
/**
* Static callback to run on all animations started through this SurfaceAnimator
@@ -151,12 +154,14 @@
* @param animationFinishedCallback The callback being triggered when the animation finishes.
* @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
* cancel call to the underlying AnimationAdapter.
+ * @param snapshotAnim The animation to run for the snapshot. {@code null} if there is no
+ * snapshot.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
@Nullable Runnable animationCancelledCallback,
- @Nullable SurfaceFreezer freezer) {
+ @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mAnimation = anim;
mAnimationType = type;
@@ -181,12 +186,16 @@
return;
}
mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
+ if (snapshotAnim != null) {
+ mSnapshot = freezer.takeSnapshotForAnimation();
+ mSnapshot.startAnimation(t, snapshotAnim, type);
+ }
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type) {
startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */,
- null /* animationCancelledCallback */, null /* freezer */);
+ null /* animationCancelledCallback */, null /* snapshotAnim */, null /* freezer */);
}
/**
@@ -328,6 +337,7 @@
final OnAnimationFinishedCallback animationFinishedCallback =
mSurfaceAnimationFinishedCallback;
final Runnable animationCancelledCallback = mAnimationCancelledCallback;
+ final SurfaceFreezer.Snapshot snapshot = mSnapshot;
reset(t, false);
if (animation != null) {
if (!mAnimationStartDelayed && forwardCancel) {
@@ -346,9 +356,14 @@
}
}
- if (forwardCancel && leash != null) {
- t.remove(leash);
- mService.scheduleAnimationLocked();
+ if (forwardCancel) {
+ if (snapshot != null) {
+ snapshot.cancelAnimation(t, false /* restarting */);
+ }
+ if (leash != null) {
+ t.remove(leash);
+ mService.scheduleAnimationLocked();
+ }
}
if (!restarting) {
@@ -361,6 +376,12 @@
mAnimation = null;
mSurfaceAnimationFinishedCallback = null;
mAnimationType = ANIMATION_TYPE_NONE;
+ final SurfaceFreezer.Snapshot snapshot = mSnapshot;
+ mSnapshot = null;
+ if (snapshot != null) {
+ // Reset the mSnapshot reference before calling the callback to prevent circular reset.
+ snapshot.cancelAnimation(t, !destroyLeash);
+ }
if (mLeash == null) {
return;
}
@@ -377,11 +398,15 @@
boolean scheduleAnim = false;
final SurfaceControl surface = animatable.getSurfaceControl();
final SurfaceControl parent = animatable.getParentSurfaceControl();
+ final SurfaceControl curAnimationLeash = animatable.getAnimationLeash();
// If the surface was destroyed or the leash is invalid, we don't care to reparent it back.
// Note that we also set this variable to true even if the parent isn't valid anymore, in
// order to ensure onAnimationLeashLost still gets called in this case.
- final boolean reparent = surface != null;
+ // If the animation leash is set, and it is different from the removing leash, it means the
+ // surface now has a new animation surface. We don't want to reparent for that.
+ final boolean reparent = surface != null && (curAnimationLeash == null
+ || curAnimationLeash.equals(leash));
if (reparent) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent: " + parent);
// We shouldn't really need these isValid checks but we do
@@ -608,6 +633,14 @@
void onAnimationLeashLost(Transaction t);
/**
+ * Gets the last created animation leash that has not lost yet.
+ */
+ @Nullable
+ default SurfaceControl getAnimationLeash() {
+ return null;
+ }
+
+ /**
* @return A new surface to be used for the animation leash, inserted at the correct
* position in the hierarchy.
*/
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index 89986ce..9a0cabe 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION;
import android.annotation.NonNull;
@@ -27,13 +26,11 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
-import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
-import java.util.function.Supplier;
-
/**
* This class handles "freezing" of an Animatable. The Animatable in question should implement
* Freezable.
@@ -54,7 +51,8 @@
private final Freezable mAnimatable;
private final WindowManagerService mWmService;
- private SurfaceControl mLeash;
+ @VisibleForTesting
+ SurfaceControl mLeash;
Snapshot mSnapshot = null;
final Rect mFreezeBounds = new Rect();
@@ -94,7 +92,7 @@
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
return;
}
- mSnapshot = new Snapshot(mWmService.mSurfaceFactory, t, screenshotBuffer, mLeash);
+ mSnapshot = new Snapshot(t, screenshotBuffer, mLeash);
}
}
@@ -109,12 +107,25 @@
}
/**
+ * Used by {@link SurfaceAnimator}. This "transfers" the snapshot leash to be used for
+ * animation. By transferring the leash, this will no longer try to clean-up the leash when
+ * finished.
+ */
+ @Nullable
+ Snapshot takeSnapshotForAnimation() {
+ final Snapshot out = mSnapshot;
+ mSnapshot = null;
+ return out;
+ }
+
+ /**
* Clean-up the snapshot and remove leash. If the leash was taken, this just cleans-up the
* snapshot.
*/
void unfreeze(SurfaceControl.Transaction t) {
if (mSnapshot != null) {
mSnapshot.cancelAnimation(t, false /* restarting */);
+ mSnapshot = null;
}
if (mLeash == null) {
return;
@@ -163,13 +174,12 @@
class Snapshot {
private SurfaceControl mSurfaceControl;
private AnimationAdapter mAnimation;
- private SurfaceAnimator.OnAnimationFinishedCallback mFinishedCallback;
/**
* @param t Transaction to create the thumbnail in.
* @param screenshotBuffer A thumbnail or placeholder for thumbnail to initialize with.
*/
- Snapshot(Supplier<Surface> surfaceFactory, SurfaceControl.Transaction t,
+ Snapshot(SurfaceControl.Transaction t,
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
// We can't use a delegating constructor since we need to
// reference this::onAnimationFinished
@@ -211,19 +221,15 @@
* component responsible for running the animation. It runs the animation with
* {@link AnimationAdapter#startAnimation} once the hierarchy with
* the Leash has been set up.
- * @param animationFinishedCallback The callback being triggered when the animation
- * finishes.
*/
- void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type,
- @Nullable SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback) {
+ void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type) {
cancelAnimation(t, true /* restarting */);
mAnimation = anim;
- mFinishedCallback = animationFinishedCallback;
if (mSurfaceControl == null) {
cancelAnimation(t, false /* restarting */);
return;
}
- mAnimation.startAnimation(mSurfaceControl, t, type, animationFinishedCallback);
+ mAnimation.startAnimation(mSurfaceControl, t, type, null /* finishCallback */);
}
/**
@@ -235,18 +241,9 @@
void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) {
final SurfaceControl leash = mSurfaceControl;
final AnimationAdapter animation = mAnimation;
- final SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback =
- mFinishedCallback;
mAnimation = null;
- mFinishedCallback = null;
if (animation != null) {
animation.onAnimationCancelled(leash);
- if (!restarting) {
- if (animationFinishedCallback != null) {
- animationFinishedCallback.onAnimationFinished(
- ANIMATION_TYPE_APP_TRANSITION, animation);
- }
- }
}
if (!restarting) {
destroy(t);
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 25f7269..0b20f37 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -64,18 +64,17 @@
*
* @return RemoteAnimationTarget[] targets for all the visible wallpaper windows
*/
- public static RemoteAnimationTarget[] startWallpaperAnimations(WindowManagerService service,
+ public static RemoteAnimationTarget[] startWallpaperAnimations(DisplayContent displayContent,
long durationHint, long statusBarTransitionDelay,
Consumer<WallpaperAnimationAdapter> animationCanceledRunnable,
ArrayList<WallpaperAnimationAdapter> adaptersOut) {
+ if (!displayContent.mWallpaperController.isWallpaperVisible()) {
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
+ "\tWallpaper of display=%s is not visible", displayContent);
+ return new RemoteAnimationTarget[0];
+ }
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
- service.mRoot.forAllWallpaperWindows(wallpaperWindow -> {
- if (!wallpaperWindow.getDisplayContent().mWallpaperController.isWallpaperVisible()) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tNot visible=%s", wallpaperWindow);
- return;
- }
-
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tvisible=%s", wallpaperWindow);
+ displayContent.forAllWallpaperWindows(wallpaperWindow -> {
final WallpaperAnimationAdapter wallpaperAdapter = new WallpaperAnimationAdapter(
wallpaperWindow, durationHint, statusBarTransitionDelay,
animationCanceledRunnable);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 9a4bf63..51ecce0 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -111,6 +111,7 @@
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -178,6 +179,10 @@
*/
protected final SurfaceAnimator mSurfaceAnimator;
+ /** The parent leash added for animation. */
+ @Nullable
+ private SurfaceControl mAnimationLeash;
+
final SurfaceFreezer mSurfaceFreezer;
protected final WindowManagerService mWmService;
final TransitionController mTransitionController;
@@ -2561,11 +2566,14 @@
* @param animationFinishedCallback The callback being triggered when the animation finishes.
* @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
* cancel call to the underlying AnimationAdapter.
+ * @param snapshotAnim The animation to run for the snapshot. {@code null} if there is no
+ * snapshot.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
- @Nullable Runnable animationCancelledCallback) {
+ @Nullable Runnable animationCancelledCallback,
+ @Nullable AnimationAdapter snapshotAnim) {
if (DEBUG_ANIM) {
Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
}
@@ -2573,14 +2581,14 @@
// TODO: This should use isVisible() but because isVisible has a really weird meaning at
// the moment this doesn't work for all animatable window containers.
mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
- animationCancelledCallback, mSurfaceFreezer);
+ animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback) {
startAnimation(t, anim, hidden, type, animationFinishedCallback,
- null /* adapterAnimationCancelledCallback */);
+ null /* adapterAnimationCancelledCallback */, null /* snapshotAnim */);
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@@ -2828,21 +2836,26 @@
taskDisplayArea.setBackgroundColor(backgroundColor);
}
+ // Atomic counter to make sure the clearColor callback is only called one.
+ // It will be called twice in the case we cancel the animation without restart
+ // (in that case it will run as the cancel and finished callbacks).
+ final AtomicInteger callbackCounter = new AtomicInteger(0);
+ final Runnable clearBackgroundColorHandler = () -> {
+ if (callbackCounter.getAndIncrement() == 0) {
+ taskDisplayArea.clearBackgroundColor();
+ }
+ };
+
final Runnable cleanUpCallback = isSettingBackgroundColor
- ? taskDisplayArea::clearBackgroundColor : () -> {};
+ ? clearBackgroundColorHandler : () -> {};
startAnimation(getPendingTransaction(), adapter, !isVisible(),
- ANIMATION_TYPE_APP_TRANSITION,
- (type, anim) -> cleanUpCallback.run(),
- cleanUpCallback);
+ ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> cleanUpCallback.run(),
+ cleanUpCallback, thumbnailAdapter);
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
- if (thumbnailAdapter != null) {
- mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
- thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { });
- }
}
}
@@ -2972,6 +2985,7 @@
@Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
mLastLayer = -1;
+ mAnimationLeash = leash;
reassignLayer(t);
// Leash is now responsible for position, so set our position to 0.
@@ -2981,11 +2995,16 @@
@Override
public void onAnimationLeashLost(Transaction t) {
mLastLayer = -1;
- mSurfaceFreezer.unfreeze(t);
+ mAnimationLeash = null;
reassignLayer(t);
updateSurfacePosition(t);
}
+ @Override
+ public SurfaceControl getAnimationLeash() {
+ return mAnimationLeash;
+ }
+
private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) {
mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 438bfaf..f11fa16 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2583,13 +2583,17 @@
// an exit.
win.mAnimatingExit = true;
} else if (win.mDisplayContent.okToAnimate()
- && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)) {
- // If the wallpaper is currently behind this
- // window, we need to change both of them inside
- // of a transaction to avoid artifacts.
+ && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)
+ && win.mAttrs.type == TYPE_NOTIFICATION_SHADE) {
+ // If the wallpaper is currently behind this app window, we need to change both of them
+ // inside of a transaction to avoid artifacts.
+ // For NotificationShade, sysui is in charge of running window animation and it updates
+ // the client view visibility only after both NotificationShade and the wallpaper are
+ // hidden. So we don't need to care about exit animation, but can destroy its surface
+ // immediately.
win.mAnimatingExit = true;
} else {
- boolean stopped = win.mActivityRecord != null ? win.mActivityRecord.mAppStopped : true;
+ boolean stopped = win.mActivityRecord == null || win.mActivityRecord.mAppStopped;
// We set mDestroying=true so ActivityRecord#notifyAppStopped in-to destroy surfaces
// will later actually destroy the surface if we do not do so here. Normally we leave
// this to the exit animation.
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index 9e48045..6751b80 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -57,6 +57,11 @@
MockScribe(InternalResourceService irs) {
super(irs);
}
+
+ @Override
+ void postWrite() {
+ // Do nothing
+ }
}
@Before
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
new file mode 100644
index 0000000..e2a37ee
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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.tare;
+
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.SparseArrayMap;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Tests for various Scribe behavior, including reading and writing correctly from file.
+ *
+ * atest FrameworksServicesTests:ScribeTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ScribeTest {
+ private static final String TAG = "ScribeTest";
+
+ private static final int TEST_USER_ID = 27;
+ private static final String TEST_PACKAGE = "com.android.test";
+
+ private MockitoSession mMockingSession;
+ private Scribe mScribeUnderTest;
+ private File mTestFileDir;
+
+ @Mock
+ private InternalResourceService mIrs;
+ @Mock
+ private UserManagerInternal mUserManagerInternal;
+
+ private Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(LocalServices.class)
+ .startMocking();
+ doReturn(mUserManagerInternal)
+ .when(() -> LocalServices.getService(UserManagerInternal.class));
+ when(mIrs.getLock()).thenReturn(new Object());
+ when(mIrs.isEnabled()).thenReturn(true);
+ when(mUserManagerInternal.getUserIds()).thenReturn(new int[]{TEST_USER_ID});
+ mTestFileDir = new File(getContext().getFilesDir(), "scribe_test");
+ //noinspection ResultOfMethodCallIgnored
+ mTestFileDir.mkdirs();
+ Log.d(TAG, "Saving data to '" + mTestFileDir + "'");
+ mScribeUnderTest = new Scribe(mIrs, mTestFileDir);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mScribeUnderTest.tearDownLocked();
+ if (mTestFileDir.exists() && !mTestFileDir.delete()) {
+ Log.w(TAG, "Failed to delete test file directory");
+ }
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void testWriteHighLevelStateToDisk() {
+ long lastReclamationTime = System.currentTimeMillis();
+ long narcsInCirculation = 2000L;
+
+ Ledger ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
+ ledger.recordTransaction(new Ledger.Transaction(0, 1000L, 1, null, 2000));
+ // Negative ledger balance shouldn't affect the total circulation value.
+ ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID + 1, TEST_PACKAGE);
+ ledger.recordTransaction(new Ledger.Transaction(0, 1000L, 1, null, -5000));
+ mScribeUnderTest.setLastReclamationTimeLocked(lastReclamationTime);
+ mScribeUnderTest.writeImmediatelyForTesting();
+
+ mScribeUnderTest.loadFromDiskLocked();
+
+ assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
+ assertEquals(narcsInCirculation, mScribeUnderTest.getNarcsInCirculationLocked());
+ }
+
+ @Test
+ public void testWritingEmptyLedgerToDisk() {
+ final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
+ mScribeUnderTest.writeImmediatelyForTesting();
+
+ mScribeUnderTest.loadFromDiskLocked();
+ assertLedgersEqual(ogLedger, mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
+ }
+
+ @Test
+ public void testWritingPopulatedLedgerToDisk() {
+ final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
+ ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51));
+ ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52));
+ ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3));
+ mScribeUnderTest.writeImmediatelyForTesting();
+
+ mScribeUnderTest.loadFromDiskLocked();
+ assertLedgersEqual(ogLedger, mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
+ }
+
+ @Test
+ public void testWritingMultipleLedgersToDisk() {
+ final SparseArrayMap<String, Ledger> ledgers = new SparseArrayMap<>();
+ final int numUsers = 3;
+ final int numLedgers = 5;
+ final int[] userIds = new int[numUsers];
+ when(mUserManagerInternal.getUserIds()).thenReturn(userIds);
+ for (int u = 0; u < numUsers; ++u) {
+ final int userId = TEST_USER_ID + u;
+ userIds[u] = userId;
+ for (int l = 0; l < numLedgers; ++l) {
+ final String pkgName = TEST_PACKAGE + l;
+ final Ledger ledger = mScribeUnderTest.getLedgerLocked(userId, pkgName);
+ ledger.recordTransaction(new Ledger.Transaction(
+ 0, 1000L * u + l, 1, null, 51L * u + l));
+ ledger.recordTransaction(new Ledger.Transaction(
+ 1500L * u + l, 2000L * u + l, 2 * u + l, "green" + u + l, 52L * u + l));
+ ledger.recordTransaction(new Ledger.Transaction(
+ 2500L * u + l, 3000L * u + l, 3 * u + l, "blue" + u + l, 3L * u + l));
+ ledgers.add(userId, pkgName, ledger);
+ }
+ }
+ mScribeUnderTest.writeImmediatelyForTesting();
+
+ mScribeUnderTest.loadFromDiskLocked();
+ ledgers.forEach((userId, pkgName, ledger)
+ -> assertLedgersEqual(ledger, mScribeUnderTest.getLedgerLocked(userId, pkgName)));
+ }
+
+ @Test
+ public void testDiscardLedgerFromDisk() {
+ final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
+ ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51));
+ ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52));
+ ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3));
+ mScribeUnderTest.writeImmediatelyForTesting();
+
+ mScribeUnderTest.loadFromDiskLocked();
+ assertLedgersEqual(ogLedger, mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
+
+ mScribeUnderTest.discardLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
+ mScribeUnderTest.writeImmediatelyForTesting();
+
+ // Make sure there's no more saved ledger.
+ mScribeUnderTest.loadFromDiskLocked();
+ assertLedgersEqual(new Ledger(),
+ mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
+ }
+
+ private void assertLedgersEqual(Ledger expected, Ledger actual) {
+ if (expected == null) {
+ assertNull(actual);
+ return;
+ }
+ assertNotNull(actual);
+ assertEquals(expected.getCurrentBalance(), actual.getCurrentBalance());
+ List<Ledger.Transaction> expectedTransactions = expected.getTransactions();
+ List<Ledger.Transaction> actualTransactions = actual.getTransactions();
+ assertEquals(expectedTransactions.size(), actualTransactions.size());
+ for (int i = 0; i < expectedTransactions.size(); ++i) {
+ assertTransactionsEqual(expectedTransactions.get(i), actualTransactions.get(i));
+ }
+ }
+
+ private void assertTransactionsEqual(Ledger.Transaction expected, Ledger.Transaction actual) {
+ if (expected == null) {
+ assertNull(actual);
+ return;
+ }
+ assertNotNull(actual);
+ assertEquals(expected.startTimeMs, actual.startTimeMs);
+ assertEquals(expected.endTimeMs, actual.endTimeMs);
+ assertEquals(expected.eventId, actual.eventId);
+ assertEquals(expected.tag, actual.tag);
+ assertEquals(expected.delta, actual.delta);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index a94690e..c1d9857 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -339,18 +339,6 @@
}
@Test
- public void getStringValue_GlobalSetting_BasicSanity() {
- when(mStorageAdapter.retrieveGlobalSetting(
- Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
- HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM))
- .thenReturn(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
- HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
- assertThat(hdmiCecConfig.getStringValue(
- HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
- .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
- }
-
- @Test
public void getStringValue_SharedPref_BasicSanity() {
when(mStorageAdapter.retrieveSharedPref(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
@@ -429,16 +417,6 @@
}
@Test
- public void setStringValue_GlobalSetting_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
- hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
- HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
- verify(mStorageAdapter).storeGlobalSetting(
- Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
- HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
- }
-
- @Test
public void setStringValue_SharedPref_BasicSanity() {
HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setStringValue(
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 82140f4..5d0e34a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -43,6 +43,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -893,6 +894,33 @@
}
@Test
+ public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ setupTaskFragmentRemoteAnimation(organizer, adapter);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
+ createTask(mDisplayContent), organizer);
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+ activity.allDrawn = true;
+ // Set wallpaper as visible.
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare a transition.
+ prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+
+ // Should not be overridden when there is wallpaper in the transition.
+ verify(mDisplayContent.mAppTransition, never())
+ .overridePendingAppTransitionRemote(adapter, false /* sync */);
+ }
+
+ @Test
public void testTransitionGoodToGoForTaskFragments() {
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final Task task = createTask(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 68053eb..bbeb980 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -25,6 +25,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
@@ -52,6 +53,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -1106,6 +1108,71 @@
verify(surfaceAnimator, never()).setRelativeLayer(any(), any(), anyInt());
}
+ @Test
+ public void testStartChangeTransitionWhenPreviousIsNotFinished() {
+ final WindowContainer container = createTaskFragmentWithParentTask(
+ createTask(mDisplayContent), false);
+ container.mSurfaceControl = mock(SurfaceControl.class);
+ final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
+ final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ spyOn(container);
+ spyOn(surfaceAnimator);
+ spyOn(surfaceFreezer);
+ doReturn(t).when(container).getPendingTransaction();
+ doReturn(t).when(container).getSyncTransaction();
+
+ // Leash and snapshot created for change transition.
+ container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
+ // Can't really take a snapshot, manually set one.
+ surfaceFreezer.mSnapshot = mock(SurfaceFreezer.Snapshot.class);
+
+ assertNotNull(surfaceFreezer.mLeash);
+ assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
+
+ // Start animation: surfaceAnimator take over the leash and snapshot from surfaceFreezer.
+ container.applyAnimationUnchecked(null /* lp */, true /* enter */,
+ TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */,
+ null /* sources */);
+
+ assertNull(surfaceFreezer.mLeash);
+ assertNull(surfaceFreezer.mSnapshot);
+ assertNotNull(surfaceAnimator.mLeash);
+ assertNotNull(surfaceAnimator.mSnapshot);
+ final SurfaceControl prevLeash = surfaceAnimator.mLeash;
+ final SurfaceFreezer.Snapshot prevSnapshot = surfaceAnimator.mSnapshot;
+
+ // Prepare another change transition.
+ container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
+ surfaceFreezer.mSnapshot = mock(SurfaceFreezer.Snapshot.class);
+
+ assertNotNull(surfaceFreezer.mLeash);
+ assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
+ assertNotEquals(prevLeash, container.getAnimationLeash());
+
+ // Start another animation before the previous one is finished, it should reset the previous
+ // one, but not change the current one.
+ container.applyAnimationUnchecked(null /* lp */, true /* enter */,
+ TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */,
+ null /* sources */);
+
+ verify(container, never()).onAnimationLeashLost(any());
+ verify(surfaceFreezer, never()).unfreeze(any());
+ assertNotNull(surfaceAnimator.mLeash);
+ assertNotNull(surfaceAnimator.mSnapshot);
+ assertEquals(surfaceAnimator.mLeash, container.getAnimationLeash());
+ assertNotEquals(prevLeash, surfaceAnimator.mLeash);
+ assertNotEquals(prevSnapshot, surfaceAnimator.mSnapshot);
+
+ // Clean up after animation finished.
+ surfaceAnimator.mInnerAnimationFinishedCallback.onAnimationFinished(
+ ANIMATION_TYPE_APP_TRANSITION, surfaceAnimator.getAnimation());
+
+ verify(container).onAnimationLeashLost(any());
+ assertNull(surfaceAnimator.mLeash);
+ assertNull(surfaceAnimator.mSnapshot);
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java
index e9698ad..0aa4b58 100644
--- a/telephony/java/android/telephony/BarringInfo.java
+++ b/telephony/java/android/telephony/BarringInfo.java
@@ -28,7 +28,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.List;
import java.util.Objects;
/**
@@ -269,42 +268,6 @@
mBarringServiceInfos = barringServiceInfos;
}
- /** @hide */
- public static BarringInfo create(
- @NonNull android.hardware.radio.V1_5.CellIdentity halBarringCellId,
- @NonNull List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos) {
- CellIdentity ci = CellIdentity.create(halBarringCellId);
- SparseArray<BarringServiceInfo> serviceInfos = new SparseArray<>();
-
- for (android.hardware.radio.V1_5.BarringInfo halBarringInfo : halBarringInfos) {
- if (halBarringInfo.barringType
- == android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL) {
- if (halBarringInfo.barringTypeSpecificInfo.getDiscriminator()
- != android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
- .hidl_discriminator.conditional) {
- // this is an error case where the barring info is conditional but the
- // conditional barring fields weren't included
- continue;
- }
- android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
- .Conditional conditionalInfo =
- halBarringInfo.barringTypeSpecificInfo.conditional();
- serviceInfos.put(
- halBarringInfo.serviceType, new BarringServiceInfo(
- halBarringInfo.barringType, // will always be CONDITIONAL here
- conditionalInfo.isBarred,
- conditionalInfo.factor,
- conditionalInfo.timeSeconds));
- } else {
- // Barring type is either NONE or UNCONDITIONAL
- serviceInfos.put(
- halBarringInfo.serviceType, new BarringServiceInfo(
- halBarringInfo.barringType, false, 0, 0));
- }
- }
- return new BarringInfo(ci, serviceInfos);
- }
-
/**
* Get the BarringServiceInfo for a specified service.
*
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 4b57d71..3e4e244 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,11 +34,6 @@
}
/** @hide */
- public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
- mIsEndcAvailable = cellConfig.isEndcAvailable;
- }
-
- /** @hide */
public CellConfigLte(boolean isEndcAvailable) {
mIsEndcAvailable = isEndcAvailable;
}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 15147da..06cfd67 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -20,7 +20,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.hardware.radio.V1_0.CellInfoType;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -359,104 +358,4 @@
return true;
}
-
- /** @hide */
- public static CellIdentity create(android.hardware.radio.V1_0.CellIdentity cellIdentity) {
- if (cellIdentity == null) return null;
- switch(cellIdentity.cellInfoType) {
- case CellInfoType.GSM: {
- if (cellIdentity.cellIdentityGsm.size() == 1) {
- return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
- }
- break;
- }
- case CellInfoType.WCDMA: {
- if (cellIdentity.cellIdentityWcdma.size() == 1) {
- return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
- }
- break;
- }
- case CellInfoType.TD_SCDMA: {
- if (cellIdentity.cellIdentityTdscdma.size() == 1) {
- return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
- }
- break;
- }
- case CellInfoType.LTE: {
- if (cellIdentity.cellIdentityLte.size() == 1) {
- return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
- }
- break;
- }
- case CellInfoType.CDMA: {
- if (cellIdentity.cellIdentityCdma.size() == 1) {
- return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
- }
- break;
- }
- case CellInfoType.NONE: break;
- default: break;
- }
- return null;
- }
-
- /** @hide */
- public static CellIdentity create(android.hardware.radio.V1_2.CellIdentity cellIdentity) {
- if (cellIdentity == null) return null;
- switch(cellIdentity.cellInfoType) {
- case CellInfoType.GSM: {
- if (cellIdentity.cellIdentityGsm.size() == 1) {
- return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
- }
- break;
- }
- case CellInfoType.WCDMA: {
- if (cellIdentity.cellIdentityWcdma.size() == 1) {
- return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
- }
- break;
- }
- case CellInfoType.TD_SCDMA: {
- if (cellIdentity.cellIdentityTdscdma.size() == 1) {
- return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
- }
- break;
- }
- case CellInfoType.LTE: {
- if (cellIdentity.cellIdentityLte.size() == 1) {
- return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
- }
- break;
- }
- case CellInfoType.CDMA: {
- if (cellIdentity.cellIdentityCdma.size() == 1) {
- return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
- }
- break;
- }
- case CellInfoType.NONE: break;
- default: break;
- }
- return null;
- }
-
- /** @hide */
- public static CellIdentity create(android.hardware.radio.V1_5.CellIdentity ci) {
- if (ci == null) return null;
- switch (ci.getDiscriminator()) {
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.gsm:
- return new CellIdentityGsm(ci.gsm());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.cdma:
- return new CellIdentityCdma(ci.cdma());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.lte:
- return new CellIdentityLte(ci.lte());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.wcdma:
- return new CellIdentityWcdma(ci.wcdma());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.tdscdma:
- return new CellIdentityTdscdma(ci.tdscdma());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.nr:
- return new CellIdentityNr(ci.nr());
- default: return null;
- }
- }
}
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 58a01e9..ba3a192 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -112,17 +112,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityCdma(@NonNull android.hardware.radio.V1_0.CellIdentityCdma cid) {
- this(cid.networkId, cid.systemId, cid.baseStationId, cid.longitude, cid.latitude, "", "");
- }
-
- /** @hide */
- public CellIdentityCdma(@NonNull android.hardware.radio.V1_2.CellIdentityCdma cid) {
- this(cid.base.networkId, cid.base.systemId, cid.base.baseStationId, cid.base.longitude,
- cid.base.latitude, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
- }
-
private CellIdentityCdma(@NonNull CellIdentityCdma cid) {
this(cid.mNetworkId, cid.mSystemId, cid.mBasestationId, cid.mLongitude, cid.mLatitude,
cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index a3bec33..2516a79 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -101,30 +101,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityGsm(@NonNull android.hardware.radio.V1_0.CellIdentityGsm cid) {
- this(cid.lac, cid.cid, cid.arfcn,
- cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic,
- cid.mcc, cid.mnc, "", "", new ArraySet<>());
- }
-
- /** @hide */
- public CellIdentityGsm(@NonNull android.hardware.radio.V1_2.CellIdentityGsm cid) {
- this(cid.base.lac, cid.base.cid, cid.base.arfcn,
- cid.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.bsic, cid.base.mcc,
- cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
- new ArraySet<>());
- }
-
- /** @hide */
- public CellIdentityGsm(@NonNull android.hardware.radio.V1_5.CellIdentityGsm cid) {
- this(cid.base.base.lac, cid.base.base.cid, cid.base.base.arfcn,
- cid.base.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE
- : cid.base.base.bsic, cid.base.base.mcc,
- cid.base.base.mnc, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns);
- }
-
private CellIdentityGsm(@NonNull CellIdentityGsm cid) {
this(cid.mLac, cid.mCid, cid.mArfcn, cid.mBsic, cid.mMccStr,
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns);
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index bd92d00a..4db00cf 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -136,31 +136,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityLte(@NonNull android.hardware.radio.V1_0.CellIdentityLte cid) {
- this(cid.ci, cid.pci, cid.tac, cid.earfcn, new int[] {},
- CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "", new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityLte(@NonNull android.hardware.radio.V1_2.CellIdentityLte cid) {
- this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, new int[] {},
- cid.bandwidth, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
- cid.operatorNames.alphaShort, new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityLte(@NonNull android.hardware.radio.V1_5.CellIdentityLte cid) {
- this(cid.base.base.ci, cid.base.base.pci, cid.base.base.tac, cid.base.base.earfcn,
- cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.bandwidth,
- cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns,
- cid.optionalCsgInfo.getDiscriminator()
- == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
- ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo())
- : null);
- }
-
private CellIdentityLte(@NonNull CellIdentityLte cid) {
this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBands, cid.mBandwidth, cid.mMccStr,
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 4f50521..6aeb482 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -65,7 +65,6 @@
}
/**
- *
* @param pci Physical Cell Id in range [0, 1007].
* @param tac 24-bit Tracking Area Code.
* @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
@@ -100,21 +99,6 @@
}
/** @hide */
- public CellIdentityNr(@NonNull android.hardware.radio.V1_4.CellIdentityNr cid) {
- this(cid.pci, cid.tac, cid.nrarfcn, new int[] {}, cid.mcc, cid.mnc, cid.nci,
- cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
- new ArraySet<>());
- }
-
- /** @hide */
- public CellIdentityNr(@NonNull android.hardware.radio.V1_5.CellIdentityNr cid) {
- this(cid.base.pci, cid.base.tac, cid.base.nrarfcn,
- cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.mcc,
- cid.base.mnc, cid.base.nci, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns);
- }
-
- /** @hide */
@Override
public @NonNull CellIdentityNr sanitizeLocationInfo() {
return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mNrArfcn,
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index ec07d54..13d9373 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -113,31 +113,6 @@
}
/** @hide */
- public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_0.CellIdentityTdscdma cid) {
- this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "",
- Collections.emptyList(), null);
- }
-
- /** @hide */
- public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_2.CellIdentityTdscdma cid) {
- this(cid.base.mcc, cid.base.mnc, cid.base.lac, cid.base.cid, cid.base.cpid,
- cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
- Collections.emptyList(), null);
- }
-
- /** @hide */
- public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_5.CellIdentityTdscdma cid) {
- this(cid.base.base.mcc, cid.base.base.mnc, cid.base.base.lac, cid.base.base.cid,
- cid.base.base.cpid, cid.base.uarfcn, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort,
- cid.additionalPlmns,
- cid.optionalCsgInfo.getDiscriminator()
- == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
- ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo())
- : null);
- }
-
- /** @hide */
@Override
public @NonNull CellIdentityTdscdma sanitizeLocationInfo() {
return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index b04a51d..9b463da 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -107,30 +107,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityWcdma(@NonNull android.hardware.radio.V1_0.CellIdentityWcdma cid) {
- this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "",
- new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityWcdma(@NonNull android.hardware.radio.V1_2.CellIdentityWcdma cid) {
- this(cid.base.lac, cid.base.cid, cid.base.psc, cid.base.uarfcn,
- cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
- cid.operatorNames.alphaShort, new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityWcdma(@NonNull android.hardware.radio.V1_5.CellIdentityWcdma cid) {
- this(cid.base.base.lac, cid.base.base.cid, cid.base.base.psc, cid.base.base.uarfcn,
- cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns,
- cid.optionalCsgInfo.getDiscriminator()
- == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
- ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo())
- : null);
- }
-
private CellIdentityWcdma(@NonNull CellIdentityWcdma cid) {
this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr,
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 189a4b8..2b2df24 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -20,7 +20,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
-import android.hardware.radio.V1_4.CellInfo.Info;
import android.os.Parcel;
import android.os.Parcelable;
@@ -150,6 +149,13 @@
private long mTimeStamp;
/** @hide */
+ protected CellInfo(int cellConnectionStatus, boolean registered, long timestamp) {
+ mCellConnectionStatus = cellConnectionStatus;
+ mRegistered = registered;
+ mTimeStamp = timestamp;
+ }
+
+ /** @hide */
protected CellInfo() {
this.mRegistered = false;
this.mTimeStamp = Long.MAX_VALUE;
@@ -321,131 +327,4 @@
return new CellInfo[size];
}
};
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_0.CellInfo ci) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = ci.timeStamp;
- this.mCellConnectionStatus = CONNECTION_UNKNOWN;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_2.CellInfo ci) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = ci.timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- this.mRegistered = ci.isRegistered;
- this.mTimeStamp = timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
- if (ci == null) return null;
- switch(ci.cellInfoType) {
- case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
- case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
- case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_2.CellInfo ci) {
- if (ci == null) return null;
- switch(ci.cellInfoType) {
- case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
- case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
- case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- if (ci == null) return null;
- switch (ci.info.getDiscriminator()) {
- case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci, timeStamp);
- case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci, timeStamp);
- case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp);
- case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp);
- case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp);
- case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- if (ci == null) return null;
- switch (ci.ratSpecificInfo.getDiscriminator()) {
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
- return new CellInfoGsm(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
- return new CellInfoCdma(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.lte:
- return new CellInfoLte(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
- return new CellInfoWcdma(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
- return new CellInfoTdscdma(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.nr:
- return new CellInfoNr(ci, timeStamp);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- if (ci == null) return null;
- switch (ci.ratSpecificInfo.getDiscriminator()) {
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
- return new CellInfoGsm(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
- return new CellInfoCdma(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.lte:
- return new CellInfoLte(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
- return new CellInfoWcdma(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
- return new CellInfoTdscdma(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.nr:
- return new CellInfoNr(ci, timeStamp);
- default: return null;
- }
- }
}
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index dbb30d2..aa8cff5 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -52,48 +52,11 @@
}
/** @hide */
- public CellInfoCdma(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoCdma cic = ci.cdma.get(0);
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.cdma.get(0);
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma();
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma();
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+ public CellInfoCdma(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityCdma cellIdentityCdma, CellSignalStrengthCdma cellSignalStrengthCdma) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityCdma = cellIdentityCdma;
+ mCellSignalStrengthCdma = cellSignalStrengthCdma;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index e1d996e..76e825b 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -51,43 +51,11 @@
}
/** @hide */
- public CellInfoGsm(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoGsm cig = ci.gsm.get(0);
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoGsm cig = ci.gsm.get(0);
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm();
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm();
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+ public CellInfoGsm(int cellConnectionStatus, boolean registered, long timeStamp,
+ CellIdentityGsm cellIdentityGsm, CellSignalStrengthGsm cellSignalStrengthGsm) {
+ super(cellConnectionStatus, registered, timeStamp);
+ mCellIdentityGsm = cellIdentityGsm;
+ mCellSignalStrengthGsm = cellSignalStrengthGsm;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 39b320a..2d176d5 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -56,48 +56,13 @@
}
/** @hide */
- public CellInfoLte(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoLte cil = ci.lte.get(0);
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoLte cil = ci.lte.get(0);
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
- mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
- mCellConfig = new CellConfigLte(cil.cellConfig);
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoLte cil = ci.ratSpecificInfo.lte();
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_6.CellInfoLte cil = ci.ratSpecificInfo.lte();
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
+ public CellInfoLte(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityLte cellIdentityLte, CellSignalStrengthLte cellSignalStrengthLte,
+ CellConfigLte cellConfig) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityLte = cellIdentityLte;
+ mCellSignalStrengthLte = cellSignalStrengthLte;
+ mCellConfig = cellConfig;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index 12e6a38..37fac24 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -53,27 +53,11 @@
}
/** @hide */
- public CellInfoNr(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_4.CellInfoNr cil = ci.info.nr();
- mCellIdentity = new CellIdentityNr(cil.cellidentity);
- mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrength);
- }
-
- /** @hide */
- public CellInfoNr(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoNr cil = ci.ratSpecificInfo.nr();
- mCellIdentity = new CellIdentityNr(cil.cellIdentityNr);
- mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
- }
-
- /** @hide */
- public CellInfoNr(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_6.CellInfoNr cil = ci.ratSpecificInfo.nr();
- mCellIdentity = new CellIdentityNr(cil.cellIdentityNr);
- mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
+ public CellInfoNr(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityNr cellIdentityNr, CellSignalStrengthNr cellSignalStrengthNr) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentity = cellIdentityNr;
+ mCellSignalStrength = cellSignalStrengthNr;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 994b317..d8db429 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -54,43 +54,12 @@
}
/** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoTdscdma cit = ci.tdscdma.get(0);
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.tdscdma.get(0);
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma();
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma();
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+ public CellInfoTdscdma(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityTdscdma cellIdentityTdscdma,
+ CellSignalStrengthTdscdma cellSignalStrengthTdscdma) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityTdscdma = cellIdentityTdscdma;
+ mCellSignalStrengthTdscdma = cellSignalStrengthTdscdma;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index 62ac0b8..dc8e1fe 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -49,43 +49,11 @@
}
/** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoWcdma ciw = ci.wcdma.get(0);
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.wcdma.get(0);
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma();
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma();
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+ public CellInfoWcdma(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityWcdma cellIdentityWcdma, CellSignalStrengthWcdma cellSignalStrengthWcdma) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityWcdma = cellIdentityWcdma;
+ mCellSignalStrengthWcdma = cellSignalStrengthWcdma;
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index e089657..9727ab7 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -108,7 +108,7 @@
// Range for RSSI in ASU (0-31, 99) as defined in TS 27.007 8.69
/** @hide */
- protected static final int getRssiDbmFromAsu(int asu) {
+ public static final int getRssiDbmFromAsu(int asu) {
if (asu > 31 || asu < 0) return CellInfo.UNAVAILABLE;
return -113 + (2 * asu);
}
@@ -122,7 +122,7 @@
// Range for RSCP in ASU (0-96, 255) as defined in TS 27.007 8.69
/** @hide */
- protected static final int getRscpDbmFromAsu(int asu) {
+ public static final int getRscpDbmFromAsu(int asu) {
if (asu > 96 || asu < 0) return CellInfo.UNAVAILABLE;
return asu - 120;
}
@@ -136,7 +136,7 @@
// Range for SNR in ASU (0-49, 255) as defined in TS 27.007 8.69
/** @hide */
- protected static final int getEcNoDbFromAsu(int asu) {
+ public static final int getEcNoDbFromAsu(int asu) {
if (asu > 49 || asu < 0) return CellInfo.UNAVAILABLE;
return -24 + (asu / 2);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index d00049c..5298e67 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -78,13 +78,6 @@
}
/** @hide */
- public CellSignalStrengthCdma(android.hardware.radio.V1_0.CdmaSignalStrength cdma,
- android.hardware.radio.V1_0.EvdoSignalStrength evdo) {
- // Convert from HAL values as part of construction.
- this(-cdma.dbm, -cdma.ecio, -evdo.dbm, -evdo.ecio, evdo.signalNoiseRatio);
- }
-
- /** @hide */
public CellSignalStrengthCdma(CellSignalStrengthCdma s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 51e1ebc..7b78084 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -67,16 +67,6 @@
}
/** @hide */
- public CellSignalStrengthGsm(android.hardware.radio.V1_0.GsmSignalStrength gsm) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(gsm.signalStrength), gsm.bitErrorRate, gsm.timingAdvance);
-
- if (mRssi == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
public CellSignalStrengthGsm(CellSignalStrengthGsm s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 9211482..e8633dd 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -166,25 +166,6 @@
}
/** @hide */
- public CellSignalStrengthLte(android.hardware.radio.V1_0.LteSignalStrength lte) {
- // Convert from HAL values as part of construction.
- this(convertRssiAsuToDBm(lte.signalStrength),
- lte.rsrp != CellInfo.UNAVAILABLE ? -lte.rsrp : lte.rsrp,
- lte.rsrq != CellInfo.UNAVAILABLE ? -lte.rsrq : lte.rsrq,
- convertRssnrUnitFromTenDbToDB(lte.rssnr), lte.cqi, lte.timingAdvance);
- }
-
- /** @hide */
- public CellSignalStrengthLte(android.hardware.radio.V1_6.LteSignalStrength lte) {
- // Convert from HAL values as part of construction.
- this(convertRssiAsuToDBm(lte.base.signalStrength),
- lte.base.rsrp != CellInfo.UNAVAILABLE ? -lte.base.rsrp : lte.base.rsrp,
- lte.base.rsrq != CellInfo.UNAVAILABLE ? -lte.base.rsrq : lte.base.rsrq,
- convertRssnrUnitFromTenDbToDB(lte.base.rssnr), lte.cqiTableIndex, lte.base.cqi,
- lte.base.timingAdvance);
- }
-
- /** @hide */
public CellSignalStrengthLte(CellSignalStrengthLte s) {
copyFrom(s);
}
@@ -617,11 +598,13 @@
Rlog.w(LOG_TAG, s);
}
- private static int convertRssnrUnitFromTenDbToDB(int rssnr) {
+ /** @hide */
+ public static int convertRssnrUnitFromTenDbToDB(int rssnr) {
return rssnr / 10;
}
- private static int convertRssiAsuToDBm(int rssiAsu) {
+ /** @hide */
+ public static int convertRssiAsuToDBm(int rssiAsu) {
if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) {
return CellInfo.UNAVAILABLE;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 6ada32e..cd22abd 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -202,29 +202,12 @@
}
/**
- * @hide
- * @param ss signal strength from modem.
- */
- public CellSignalStrengthNr(android.hardware.radio.V1_4.NrSignalStrength ss) {
- this(flip(ss.csiRsrp), flip(ss.csiRsrq), ss.csiSinr, flip(ss.ssRsrp), flip(ss.ssRsrq),
- ss.ssSinr);
- }
-
- /**
- * @hide
- * @param ss signal strength from modem.
- */
- public CellSignalStrengthNr(android.hardware.radio.V1_6.NrSignalStrength ss) {
- this(flip(ss.base.csiRsrp), flip(ss.base.csiRsrq), ss.base.csiSinr, ss.csiCqiTableIndex,
- ss.csiCqiReport, flip(ss.base.ssRsrp), flip(ss.base.ssRsrq), ss.base.ssSinr);
- }
-
- /**
* Flip sign cell strength value when taking in the value from hal
* @param val cell strength value
* @return flipped value
+ * @hide
*/
- private static int flip(int val) {
+ public static int flip(int val) {
return val != CellInfo.UNAVAILABLE ? -val : val;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index e96f200..8a7c70e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -75,28 +75,6 @@
}
/** @hide */
- public CellSignalStrengthTdscdma(android.hardware.radio.V1_0.TdScdmaSignalStrength tdscdma) {
- // Convert from HAL values as part of construction.
- this(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
- tdscdma.rscp != CellInfo.UNAVAILABLE ? -tdscdma.rscp : tdscdma.rscp);
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
- public CellSignalStrengthTdscdma(android.hardware.radio.V1_2.TdscdmaSignalStrength tdscdma) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(tdscdma.signalStrength),
- tdscdma.bitErrorRate, getRscpDbmFromAsu(tdscdma.rscp));
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
public CellSignalStrengthTdscdma(CellSignalStrengthTdscdma s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 8b14b74..f30440d 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -95,30 +95,6 @@
}
/** @hide */
- public CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(wcdma.signalStrength), wcdma.bitErrorRate,
- CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE);
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
- public CellSignalStrengthWcdma(android.hardware.radio.V1_2.WcdmaSignalStrength wcdma) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(wcdma.base.signalStrength),
- wcdma.base.bitErrorRate,
- getRscpDbmFromAsu(wcdma.rscp),
- getEcNoDbFromAsu(wcdma.ecno));
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
index e926272..bf418ab 100644
--- a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
+++ b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
@@ -44,12 +44,6 @@
mCsgIdentity = csgIdentity;
}
- /** @hide */
- public ClosedSubscriberGroupInfo(
- @NonNull android.hardware.radio.V1_5.ClosedSubscriberGroupInfo csgInfo) {
- this(csgInfo.csgIndication, csgInfo.homeNodebName, csgInfo.csgIdentity);
- }
-
/**
* Indicates whether the cell is restricted to only CSG members.
*
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 484eb1f..5affb62 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -612,7 +612,7 @@
/**
* Get the channel number of the current primary serving cell, or -1 if unknown
*
- * <p>This is EARFCN for LTE, UARFCN for UMTS, and ARFCN for GSM.
+ * <p>This is NRARFCN for NR, EARFCN for LTE, UARFCN for UMTS, and ARFCN for GSM.
*
* @return Channel number of primary serving cell
*/
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index b317c55..b7bc467 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -144,64 +144,6 @@
mTimestampMillis = SystemClock.elapsedRealtime();
}
- /**
- * Constructor for Radio HAL V1.0
- *
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_0.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gw),
- new CellSignalStrengthWcdma(),
- new CellSignalStrengthTdscdma(signalStrength.tdScdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr());
- }
-
- /**
- * Constructor for Radio HAL V1.2
- *
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_2.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gsm),
- new CellSignalStrengthWcdma(signalStrength.wcdma),
- new CellSignalStrengthTdscdma(signalStrength.tdScdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr());
- }
-
- /**
- * Constructor for Radio HAL V1.4.
- *
- * @param signalStrength signal strength reported from modem.
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_4.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gsm),
- new CellSignalStrengthWcdma(signalStrength.wcdma),
- new CellSignalStrengthTdscdma(signalStrength.tdscdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr(signalStrength.nr));
- }
-
- /**
- * Constructor for Radio HAL V1.6.
- *
- * @param signalStrength signal strength reported from modem.
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_6.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gsm),
- new CellSignalStrengthWcdma(signalStrength.wcdma),
- new CellSignalStrengthTdscdma(signalStrength.tdscdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr(signalStrength.nr));
- }
-
private CellSignalStrength getPrimary() {
// This behavior is intended to replicate the legacy behavior of getLevel() by prioritizing
// newer faster RATs for default/for display purposes.