Merge "Fix fingerprint on lockscreen preivew" into udc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index ce381b6..e08200b 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -22,7 +22,6 @@
import android.app.AppOpsManager;
import android.app.AppOpsManager.PackageOps;
import android.app.IActivityManager;
-import android.app.UidObserver;
import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -54,6 +53,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.StatLogger;
+import com.android.modules.expresslog.Counter;
import com.android.server.AppStateTrackerProto.ExemptedPackage;
import com.android.server.AppStateTrackerProto.RunAnyInBackgroundRestrictedPackages;
import com.android.server.usage.AppStandbyInternal;
@@ -79,6 +79,9 @@
public class AppStateTrackerImpl implements AppStateTracker {
private static final boolean DEBUG = false;
+ private static final String APP_RESTRICTION_COUNTER_METRIC_ID =
+ "battery.value_app_background_restricted";
+
private final Object mLock = new Object();
private final Context mContext;
@@ -748,6 +751,9 @@
} catch (RemoteException e) {
// Shouldn't happen
}
+ if (restricted) {
+ Counter.logIncrementWithUid(APP_RESTRICTION_COUNTER_METRIC_ID, uid);
+ }
synchronized (mLock) {
if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index c540517..0a7bffc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -49,8 +49,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
+import com.android.modules.expresslog.Histogram;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.AppSchedulingModuleThread;
import com.android.server.IoThread;
import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;
import com.android.server.job.controllers.JobStatus;
@@ -94,6 +96,7 @@
/** Threshold to adjust how often we want to write to the db. */
private static final long JOB_PERSIST_DELAY = 2000L;
+ private static final long SCHEDULED_JOB_HIGH_WATER_MARK_PERIOD_MS = 30 * 60_000L;
@VisibleForTesting
static final String JOB_FILE_SPLIT_PREFIX = "jobs_";
private static final int ALL_UIDS = -1;
@@ -131,6 +134,30 @@
private JobStorePersistStats mPersistInfo = new JobStorePersistStats();
+ /**
+ * Separately updated value of the JobSet size to avoid recalculating it frequently for logging
+ * purposes. Continue to use {@link JobSet#size()} for the up-to-date and accurate value.
+ */
+ private int mCurrentJobSetSize = 0;
+ private int mScheduledJob30MinHighWaterMark = 0;
+ private static final Histogram sScheduledJob30MinHighWaterMarkLogger = new Histogram(
+ "job_scheduler.value_hist_scheduled_job_30_min_high_water_mark",
+ new Histogram.ScaledRangeOptions(15, 1, 99, 1.5f));
+ private final Runnable mScheduledJobHighWaterMarkLoggingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ AppSchedulingModuleThread.getHandler().removeCallbacks(this);
+ synchronized (mLock) {
+ sScheduledJob30MinHighWaterMarkLogger.logSample(mScheduledJob30MinHighWaterMark);
+ mScheduledJob30MinHighWaterMark = mJobSet.size();
+ }
+ // The count doesn't need to be logged at exact times. Logging based on system uptime
+ // should be fine.
+ AppSchedulingModuleThread.getHandler()
+ .postDelayed(this, SCHEDULED_JOB_HIGH_WATER_MARK_PERIOD_MS);
+ }
+ };
+
/** Used by the {@link JobSchedulerService} to instantiate the JobStore. */
static JobStore get(JobSchedulerService jobManagerService) {
synchronized (sSingletonLock) {
@@ -183,6 +210,9 @@
mXmlTimestamp = mJobsFile.exists()
? mJobsFile.getLastModifiedTime() : mJobFileDirectory.lastModified();
mRtcGood = (sSystemClock.millis() > mXmlTimestamp);
+
+ AppSchedulingModuleThread.getHandler().postDelayed(
+ mScheduledJobHighWaterMarkLoggingRunnable, SCHEDULED_JOB_HIGH_WATER_MARK_PERIOD_MS);
}
private void init() {
@@ -252,7 +282,10 @@
* @param jobStatus Job to add.
*/
public void add(JobStatus jobStatus) {
- mJobSet.add(jobStatus);
+ if (mJobSet.add(jobStatus)) {
+ mCurrentJobSetSize++;
+ maybeUpdateHighWaterMark();
+ }
if (jobStatus.isPersisted()) {
mPendingJobWriteUids.put(jobStatus.getUid(), true);
maybeWriteStatusToDiskAsync();
@@ -267,7 +300,10 @@
*/
@VisibleForTesting
public void addForTesting(JobStatus jobStatus) {
- mJobSet.add(jobStatus);
+ if (mJobSet.add(jobStatus)) {
+ mCurrentJobSetSize++;
+ maybeUpdateHighWaterMark();
+ }
if (jobStatus.isPersisted()) {
mPendingJobWriteUids.put(jobStatus.getUid(), true);
}
@@ -303,6 +339,7 @@
}
return false;
}
+ mCurrentJobSetSize--;
if (removeFromPersisted && jobStatus.isPersisted()) {
mPendingJobWriteUids.put(jobStatus.getUid(), true);
maybeWriteStatusToDiskAsync();
@@ -315,7 +352,9 @@
*/
@VisibleForTesting
public void removeForTesting(JobStatus jobStatus) {
- mJobSet.remove(jobStatus);
+ if (mJobSet.remove(jobStatus)) {
+ mCurrentJobSetSize--;
+ }
if (jobStatus.isPersisted()) {
mPendingJobWriteUids.put(jobStatus.getUid(), true);
}
@@ -327,6 +366,7 @@
*/
public void removeJobsOfUnlistedUsers(int[] keepUserIds) {
mJobSet.removeJobsOfUnlistedUsers(keepUserIds);
+ mCurrentJobSetSize = mJobSet.size();
}
/** Note a change in the specified JobStatus that necessitates writing job state to disk. */
@@ -342,6 +382,7 @@
public void clear() {
mJobSet.clear();
mPendingJobWriteUids.put(ALL_UIDS, true);
+ mCurrentJobSetSize = 0;
maybeWriteStatusToDiskAsync();
}
@@ -352,6 +393,7 @@
public void clearForTesting() {
mJobSet.clear();
mPendingJobWriteUids.put(ALL_UIDS, true);
+ mCurrentJobSetSize = 0;
}
void setUseSplitFiles(boolean useSplitFiles) {
@@ -442,6 +484,12 @@
mJobSet.forEachJobForSourceUid(sourceUid, functor);
}
+ private void maybeUpdateHighWaterMark() {
+ if (mScheduledJob30MinHighWaterMark < mCurrentJobSetSize) {
+ mScheduledJob30MinHighWaterMark = mCurrentJobSetSize;
+ }
+ }
+
/** Version of the db schema. */
private static final int JOBS_FILE_VERSION = 1;
/**
@@ -1125,6 +1173,12 @@
if (needFileMigration) {
migrateJobFilesAsync();
}
+
+ // Log the count immediately after loading from boot.
+ mCurrentJobSetSize = numJobs;
+ mScheduledJob30MinHighWaterMark = mCurrentJobSetSize;
+ mScheduledJobHighWaterMarkLoggingRunnable.run();
+
if (mCompletionLatch != null) {
mCompletionLatch.countDown();
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9346223..e42e526 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2367,6 +2367,7 @@
method public static boolean isApp(int);
field public static final int MIN_SECONDARY_USER_ID = 10; // 0xa
field public static final int USER_ALL = -1; // 0xffffffff
+ field public static final int USER_CURRENT = -2; // 0xfffffffe
field public static final int USER_NULL = -10000; // 0xffffd8f0
field public static final int USER_SYSTEM = 0; // 0x0
}
@@ -2375,10 +2376,12 @@
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createProfileForUser(@Nullable String, @NonNull String, int, int, @Nullable String[]);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getAliveUsers();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getBootUser();
method public int getMainDisplayIdAssignedToUser();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.Set<java.lang.String> getPreInstallableSystemPackages(@NonNull String);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers();
method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isUserTypeEnabled(@NonNull String);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 9e59ee4..0e5cbe2 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -60,13 +60,16 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.LongSparseArray;
import android.util.LongSparseLongArray;
import android.util.Pools;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -179,6 +182,8 @@
*/
@SystemService(Context.APP_OPS_SERVICE)
public class AppOpsManager {
+ private static final String LOG_TAG = "AppOpsManager";
+
/**
* This is a subtle behavior change to {@link #startWatchingMode}.
*
@@ -7517,6 +7522,7 @@
*/
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(int code, int uid, @Mode int mode) {
+ logAnySeriousModeChanges(code, uid, null, mode);
try {
mService.setUidMode(code, uid, mode);
} catch (RemoteException e) {
@@ -7537,6 +7543,7 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(@NonNull String appOp, int uid, @Mode int mode) {
+ logAnySeriousModeChanges(strOpToOp(appOp), uid, null, mode);
try {
mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
} catch (RemoteException e) {
@@ -7572,11 +7579,32 @@
}
}
+ private void logAnySeriousModeChanges(int code, int uid, String packageName, @Mode int mode) {
+ // TODO (b/280869337): Remove this once we have the required data.
+ if (code != OP_RUN_ANY_IN_BACKGROUND || mode == MODE_ALLOWED) {
+ return;
+ }
+ final StringBuilder log = new StringBuilder("Attempt to change RUN_ANY_IN_BACKGROUND to ")
+ .append(modeToName(mode))
+ .append(" for uid: ")
+ .append(UserHandle.formatUid(uid))
+ .append(" package: ")
+ .append(packageName)
+ .append(" by: ")
+ .append(mContext.getOpPackageName());
+ if (Process.myUid() == Process.SYSTEM_UID) {
+ Slog.wtfStack(LOG_TAG, log.toString());
+ } else {
+ Log.w(LOG_TAG, log.toString());
+ }
+ }
+
/** @hide */
@UnsupportedAppUsage
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(int code, int uid, String packageName, @Mode int mode) {
+ logAnySeriousModeChanges(code, uid, packageName, mode);
try {
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
@@ -7599,6 +7627,7 @@
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(@NonNull String op, int uid, @Nullable String packageName,
@Mode int mode) {
+ logAnySeriousModeChanges(strOpToOp(op), uid, packageName, mode);
try {
mService.setMode(strOpToOp(op), uid, packageName, mode);
} catch (RemoteException e) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 27270d9..d6592d5 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -765,10 +765,6 @@
@Nullable
public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component,
@Nullable Bundle startActivityOptions, @NonNull UserHandle user) {
- if (mContext.checkSelfPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
- != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Only allowed for recents.");
- }
logErrorForInvalidProfileAccess(user);
if (DEBUG) {
Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user);
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index a89d17b..50be5c4 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -91,7 +91,7 @@
/**
* The version name of this package, as specified by the <manifest>
* tag's {@link android.R.styleable#AndroidManifest_versionName versionName}
- * attribute.
+ * attribute, or null if there was none.
*/
public String versionName;
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java
index 9ebb058..3fc3be5 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/ui/RequestInfo.java
@@ -52,6 +52,12 @@
@NonNull public static final String TYPE_UNDEFINED = "android.credentials.ui.TYPE_UNDEFINED";
/** Type value for a getCredential request. */
@NonNull public static final String TYPE_GET = "android.credentials.ui.TYPE_GET";
+ /** Type value for a getCredential request that utilizes the credential registry.
+ *
+ * @hide
+ **/
+ @NonNull public static final String TYPE_GET_VIA_REGISTRY =
+ "android.credentials.ui.TYPE_GET_VIA_REGISTRY";
/** Type value for a createCredential request. */
@NonNull public static final String TYPE_CREATE = "android.credentials.ui.TYPE_CREATE";
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 069c264..dcf1a47 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -1136,7 +1136,10 @@
Printer indentedPrinter = PrefixPrinter.create(printer, " ");
synchronized (mLock) {
if (directories != null) {
- directories.add(new File(mConfiguration.path).getParent());
+ String parent = new File(mConfiguration.path).getParent();
+ if (parent != null) {
+ directories.add(parent);
+ }
}
boolean isCompatibilityWalEnabled = mConfiguration.isLegacyCompatibilityWalEnabled();
printer.println("Connection pool for " + mConfiguration.path + ":");
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 6cd32ff..17bbe14 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -233,7 +233,7 @@
*/
public static boolean useTouchpadNaturalScrolling(@NonNull Context context) {
return Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_NATURAL_SCROLLING, 0, UserHandle.USER_CURRENT) == 1;
+ Settings.System.TOUCHPAD_NATURAL_SCROLLING, 1, UserHandle.USER_CURRENT) == 1;
}
/**
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index 22f5902..f9a2dbb 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -144,6 +144,9 @@
int errorCode;
switch (status) {
+ case RadioTuner.TUNER_RESULT_CANCELED:
+ errorCode = RadioTuner.ERROR_CANCELLED;
+ break;
case RadioManager.STATUS_PERMISSION_DENIED:
case RadioManager.STATUS_DEAD_OBJECT:
errorCode = RadioTuner.ERROR_SERVER_DIED;
@@ -152,10 +155,16 @@
case RadioManager.STATUS_NO_INIT:
case RadioManager.STATUS_BAD_VALUE:
case RadioManager.STATUS_INVALID_OPERATION:
+ case RadioTuner.TUNER_RESULT_INTERNAL_ERROR:
+ case RadioTuner.TUNER_RESULT_INVALID_ARGUMENTS:
+ case RadioTuner.TUNER_RESULT_INVALID_STATE:
+ case RadioTuner.TUNER_RESULT_NOT_SUPPORTED:
+ case RadioTuner.TUNER_RESULT_UNKNOWN_ERROR:
Log.i(TAG, "Got an error with no mapping to the legacy API (" + status
+ "), doing a best-effort conversion to ERROR_SCAN_TIMEOUT");
// fall through
case RadioManager.STATUS_TIMED_OUT:
+ case RadioTuner.TUNER_RESULT_TIMEOUT:
default:
errorCode = RadioTuner.ERROR_SCAN_TIMEOUT;
}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 301b412..bfff4db 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -2306,7 +2306,7 @@
Looper looper = handler != null ? handler.getLooper() : Looper.getMainLooper();
try {
return new SoundTriggerModule(getService(), moduleId, listener, looper,
- middlemanIdentity, originatorIdentity);
+ middlemanIdentity, originatorIdentity, false);
} catch (Exception e) {
Log.e(TAG, "", e);
return null;
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 48d4ea4..8813a17 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -83,7 +83,8 @@
*/
public SoundTriggerModule(@NonNull ISoundTriggerMiddlewareService service,
int moduleId, @NonNull SoundTrigger.StatusListener listener, @NonNull Looper looper,
- @NonNull Identity middlemanIdentity, @NonNull Identity originatorIdentity) {
+ @NonNull Identity middlemanIdentity, @NonNull Identity originatorIdentity,
+ boolean isTrusted) {
mId = moduleId;
mEventHandlerDelegate = new EventHandlerDelegate(listener, looper);
@@ -91,7 +92,8 @@
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
mService = service.attachAsMiddleman(moduleId, middlemanIdentity,
originatorIdentity,
- mEventHandlerDelegate);
+ mEventHandlerDelegate,
+ isTrusted);
}
mService.asBinder().linkToDeath(mEventHandlerDelegate, 0);
} catch (RemoteException e) {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 2c31e32..94971b8 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -107,42 +107,22 @@
private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER = 2;
private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_OFF = 3;
- // System properties related to ANGLE and legacy GLES graphics drivers.
- private static final String PROPERTY_EGL_SYSTEM_DRIVER = "ro.hardware.egl";
- // TODO (b/224558229): Properly add this to the list of system properties for a device:
- private static final String PROPERTY_EGL_LEGACY_DRIVER = "ro.hardware.egl_legacy";
-
// Values for ANGLE_GL_DRIVER_ALL_ANGLE
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_ON = 1;
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_OFF = 0;
- private static final int ANGLE_GL_DRIVER_ALL_LEGACY = -1;
// Values for ANGLE_GL_DRIVER_SELECTION_VALUES
private static final String ANGLE_GL_DRIVER_CHOICE_DEFAULT = "default";
private static final String ANGLE_GL_DRIVER_CHOICE_ANGLE = "angle";
- private static final String ANGLE_GL_DRIVER_CHOICE_LEGACY = "legacy";
- // The following value is a deprecated choice for "legacy"
private static final String ANGLE_GL_DRIVER_CHOICE_NATIVE = "native";
- // Values returned by getDriverForPackage() and getDefaultDriverToUse() (avoid returning
- // strings for performance reasons)
- private static final int ANGLE_GL_DRIVER_TO_USE_LEGACY = 0;
- private static final int ANGLE_GL_DRIVER_TO_USE_ANGLE = 1;
-
private ClassLoader mClassLoader;
private String mLibrarySearchPaths;
private String mLibraryPermittedPaths;
private GameManager mGameManager;
- private boolean mAngleIsSystemDriver = false;
- private boolean mNoLegacyDriver = false;
- // When ANGLE is the system driver, this is the name of the legacy driver.
- //
- // TODO (b/224558229): This is temporarily set to a value that works for testing, until
- // PROPERTY_EGL_LEGACY_DRIVER has been properly plumbed and this becomes broadly available.
- private String mEglLegacyDriver = "mali";
-
private int mAngleOptInIndex = -1;
+ private boolean mEnabledByGameMode = false;
/**
* Set up GraphicsEnvironment
@@ -159,24 +139,6 @@
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
- // Determine if ANGLE is the system driver, as this will determine other logic
- final String eglSystemDriver = SystemProperties.get(PROPERTY_EGL_SYSTEM_DRIVER);
- Log.v(TAG, "GLES system driver is '" + eglSystemDriver + "'");
- mAngleIsSystemDriver = eglSystemDriver.equals(ANGLE_DRIVER_NAME);
- if (mAngleIsSystemDriver) {
- // Lookup the legacy driver, to send down to the EGL loader
- final String eglLegacyDriver = SystemProperties.get(PROPERTY_EGL_LEGACY_DRIVER);
- if (eglLegacyDriver.isEmpty()) {
- mNoLegacyDriver = true;
- // TBD/TODO: Do we need this?:
- mEglLegacyDriver = eglSystemDriver;
- }
- } else {
- // TBD/TODO: Do we need this?:
- mEglLegacyDriver = eglSystemDriver;
- }
- Log.v(TAG, "Legacy GLES driver is '" + mEglLegacyDriver + "'");
-
// Setup ANGLE and pass down ANGLE details to the C++ code
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
boolean useAngle = false;
@@ -185,10 +147,6 @@
useAngle = true;
setGpuStats(ANGLE_DRIVER_NAME, ANGLE_DRIVER_VERSION_NAME, ANGLE_DRIVER_VERSION_CODE,
0, packageName, getVulkanVersion(pm));
- } else if (mNoLegacyDriver) {
- // TBD: The following should never happen--does it?
- Log.e(TAG, "Unexpected problem with the ANGLE for use with: '" + packageName + "'");
- useAngle = true;
}
}
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@@ -242,12 +200,10 @@
private boolean shouldUseAngle(Context context, Bundle coreSettings, String packageName) {
if (TextUtils.isEmpty(packageName)) {
Log.v(TAG, "No package name specified; use the system driver");
- return mAngleIsSystemDriver ? true : false;
+ return false;
}
- final int driverToUse = getDriverForPackage(context, coreSettings, packageName);
- boolean yesOrNo = driverToUse == ANGLE_GL_DRIVER_TO_USE_ANGLE;
- return yesOrNo;
+ return shouldUseAngleInternal(context, coreSettings, packageName);
}
private int getVulkanVersion(PackageManager pm) {
@@ -455,43 +411,25 @@
return ai;
}
- /**
- * Return the appropriate "default" driver, unless overridden by isAngleEnabledByGameMode().
- */
- private int getDefaultDriverToUse(Context context, String packageName) {
- if (mAngleIsSystemDriver || isAngleEnabledByGameMode(context, packageName)) {
- return ANGLE_GL_DRIVER_TO_USE_ANGLE;
- } else {
- return ANGLE_GL_DRIVER_TO_USE_LEGACY;
- }
- }
-
/*
* Determine which GLES "driver" should be used for the package, taking into account the
* following factors (in priority order):
*
* 1) The semi-global switch (i.e. Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE; which is set by
* the "angle_gl_driver_all_angle" setting; which forces a driver for all processes that
- * start after the Java run time is up), if it forces a choice; otherwise ...
+ * start after the Java run time is up), if it forces a choice;
* 2) The per-application switch (i.e. Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS and
* Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES; which corresponds to the
* “angle_gl_driver_selection_pkgs” and “angle_gl_driver_selection_values” settings); if it
* forces a choice;
- * - Workaround Note: ANGLE and Vulkan currently have issues with applications that use YUV
- * target functionality. The ANGLE broadcast receiver code will apply a "deferlist" at
- * the first boot of a newly-flashed device. However, there is a gap in time between
- * when applications can start and when the deferlist is applied. For now, assume that
- * if ANGLE is the system driver and Settings.Global.ANGLE_DEFERLIST is empty, that the
- * deferlist has not yet been applied. In this case, select the Legacy driver.
- * otherwise ...
- * 3) Use ANGLE if isAngleEnabledByGameMode() returns true; otherwise ...
- * 4) The global switch (i.e. use the system driver, whether ANGLE or legacy;
- * a.k.a. mAngleIsSystemDriver, which is set by the device’s “ro.hardware.egl” property)
- *
- * Factors 1 and 2 are decided by this method. Factors 3 and 4 are decided by
- * getDefaultDriverToUse().
+ * 3) Use ANGLE if isAngleEnabledByGameMode() returns true;
*/
- private int getDriverForPackage(Context context, Bundle bundle, String packageName) {
+ private boolean shouldUseAngleInternal(Context context, Bundle bundle, String packageName) {
+ // Make sure we have a good package name
+ if (TextUtils.isEmpty(packageName)) {
+ return false;
+ }
+
// Check the semi-global switch (i.e. once system has booted enough) for whether ANGLE
// should be forced on or off for "all appplications"
final int allUseAngle;
@@ -504,16 +442,7 @@
}
if (allUseAngle == ANGLE_GL_DRIVER_ALL_ANGLE_ON) {
Log.v(TAG, "Turn on ANGLE for all applications.");
- return ANGLE_GL_DRIVER_TO_USE_ANGLE;
- }
- if (allUseAngle == ANGLE_GL_DRIVER_ALL_LEGACY) {
- Log.v(TAG, "Disable ANGLE for all applications.");
- return ANGLE_GL_DRIVER_TO_USE_LEGACY;
- }
-
- // Make sure we have a good package name
- if (TextUtils.isEmpty(packageName)) {
- return getDefaultDriverToUse(context, packageName);
+ return true;
}
// Get the per-application settings lists
@@ -522,61 +451,46 @@
contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS);
final List<String> optInValues = getGlobalSettingsString(
contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES);
- final List<String> angleDeferlist = getGlobalSettingsString(
- contentResolver, bundle, Settings.Global.ANGLE_DEFERLIST);
Log.v(TAG, "Currently set values for:");
- Log.v(TAG, " angle_gl_driver_selection_pkgs =" + optInPackages);
- Log.v(TAG, " angle_gl_driver_selection_values =" + optInValues);
+ Log.v(TAG, " angle_gl_driver_selection_pkgs=" + optInPackages);
+ Log.v(TAG, " angle_gl_driver_selection_values=" + optInValues);
- // If ANGLE is the system driver AND the deferlist has not yet been applied, select the
- // Legacy driver
- if (mAngleIsSystemDriver && angleDeferlist.size() == 0) {
- Log.v(TAG, "ANGLE deferlist (" + Settings.Global.ANGLE_DEFERLIST + ") has not been "
- + "applied, defaulting to legacy driver");
- return ANGLE_GL_DRIVER_TO_USE_LEGACY;
- }
+ mEnabledByGameMode = isAngleEnabledByGameMode(context, packageName);
// Make sure we have good settings to use
if (optInPackages.size() != optInValues.size()) {
- Log.w(TAG,
+ Log.v(TAG,
"Global.Settings values are invalid: "
+ "number of packages: "
+ optInPackages.size() + ", "
+ "number of values: "
+ optInValues.size());
- return getDefaultDriverToUse(context, packageName);
+ return mEnabledByGameMode;
}
- // See if this application is listed in the per-application settings lists
+ // See if this application is listed in the per-application settings list
final int pkgIndex = getPackageIndex(packageName, optInPackages);
if (pkgIndex < 0) {
- // The application is NOT listed in the per-application settings lists; and so use the
- // system driver (i.e. either ANGLE or the Legacy driver)
- Log.v(TAG, "getDriverForPackage(): No per-application setting");
- return getDefaultDriverToUse(context, packageName);
+ Log.v(TAG, packageName + " is not listed in per-application setting");
+ return mEnabledByGameMode;
}
mAngleOptInIndex = pkgIndex;
- Log.v(TAG,
- "getDriverForPackage(): using per-application switch: "
- + optInValues.get(pkgIndex));
- // The application IS listed in the per-application settings lists; and so use the
- // setting--choosing the current system driver if the setting is "default" (i.e. either
- // ANGLE or the Legacy driver)
- String rtnValue = optInValues.get(pkgIndex);
+ // The application IS listed in the per-application settings list; and so use the
+ // setting--choosing the current system driver if the setting is "default"
+ String optInValue = optInValues.get(pkgIndex);
Log.v(TAG,
"ANGLE Developer option for '" + packageName + "' "
- + "set to: '" + rtnValue + "'");
- if (rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE)) {
- return ANGLE_GL_DRIVER_TO_USE_ANGLE;
- } else if (rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)
- || rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_LEGACY)) {
- return ANGLE_GL_DRIVER_TO_USE_LEGACY;
+ + "set to: '" + optInValue + "'");
+ if (optInValue.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE)) {
+ return true;
+ } else if (optInValue.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)) {
+ return false;
} else {
// The user either chose default or an invalid value; go with the default driver or what
- // the game dashboard indicates
- return getDefaultDriverToUse(context, packageName);
+ // the game mode indicates
+ return mEnabledByGameMode;
}
}
@@ -631,9 +545,7 @@
* the C++ GraphicsEnv class.
*
* If ANGLE will be used, GraphicsEnv::setAngleInfo() will be called to enable ANGLE to be
- * properly used. Otherwise, GraphicsEnv::setLegacyDriverInfo() will be called to
- * enable the legacy GLES driver (e.g. when ANGLE is the system driver) to be identified and
- * used.
+ * properly used.
*
* @param context
* @param bundle
@@ -646,7 +558,6 @@
String packageName) {
if (!shouldUseAngle(context, bundle, packageName)) {
- setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
@@ -655,13 +566,13 @@
// If the developer has specified a debug package over ADB, attempt to find it
String anglePkgName = getAngleDebugPackage(context, bundle);
if (!anglePkgName.isEmpty()) {
- Log.i(TAG, "ANGLE debug package enabled: " + anglePkgName);
+ Log.v(TAG, "ANGLE debug package enabled: " + anglePkgName);
try {
// Note the debug package does not have to be pre-installed
angleInfo = pm.getApplicationInfo(anglePkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "ANGLE debug package '" + anglePkgName + "' not installed");
- setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
+ // If the debug package is specified but not found, abort.
+ Log.v(TAG, "ANGLE debug package '" + anglePkgName + "' not installed");
return false;
}
}
@@ -670,8 +581,7 @@
if (angleInfo == null) {
anglePkgName = getAnglePackageName(pm);
if (TextUtils.isEmpty(anglePkgName)) {
- Log.w(TAG, "Failed to find ANGLE package.");
- setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
+ Log.v(TAG, "Failed to find ANGLE package.");
return false;
}
@@ -681,8 +591,7 @@
angleInfo = pm.getApplicationInfo(anglePkgName,
PackageManager.MATCH_SYSTEM_ONLY);
} catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
- setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
+ Log.v(TAG, "ANGLE package '" + anglePkgName + "' not installed");
return false;
}
}
@@ -697,14 +606,13 @@
+ abi;
if (DEBUG) {
- Log.v(TAG, "ANGLE package libs: " + paths);
+ Log.d(TAG, "ANGLE package libs: " + paths);
}
// If we make it to here, ANGLE will be used. Call setAngleInfo() with the package name,
// and features to use.
final String[] features = getAngleEglFeatures(context, bundle);
- setAngleInfo(
- paths, packageName, mAngleIsSystemDriver, ANGLE_GL_DRIVER_CHOICE_ANGLE, features);
+ setAngleInfo(paths, packageName, ANGLE_GL_DRIVER_CHOICE_ANGLE, features);
return true;
}
@@ -994,9 +902,7 @@
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
private static native void setAngleInfo(String path, String appPackage,
- boolean angleIsSystemDriver, String devOptIn, String[] features);
- private static native void setLegacyDriverInfo(
- String appPackage, boolean angleIsSystemDriver, String legacyDriverName);
+ String devOptIn, String[] features);
private static native boolean getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable();
private static native void nativeToggleAngleAsSystemDriver(boolean enabled);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 4ce9184..ef39010 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -56,6 +56,7 @@
/** @hide A user id to indicate the currently active user */
@UnsupportedAppUsage
+ @TestApi
public static final @UserIdInt int USER_CURRENT = -2;
/** @hide A user handle to indicate the current user of the device */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5bcbaa1..8606687 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4224,7 +4224,8 @@
android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.CREATE_USERS
})
- public List<UserInfo> getUsers() {
+ @TestApi
+ public @NonNull List<UserInfo> getUsers() {
return getUsers(/*excludePartial= */ true, /* excludeDying= */ false,
/* excludePreCreated= */ true);
}
@@ -4245,6 +4246,7 @@
android.Manifest.permission.MANAGE_USERS,
android.Manifest.permission.CREATE_USERS
})
+ @TestApi
public @NonNull List<UserInfo> getAliveUsers() {
return getUsers(/*excludePartial= */ true, /* excludeDying= */ true,
/* excludePreCreated= */ true);
@@ -4271,8 +4273,7 @@
* Returns information for all users on this device, based on the filtering parameters.
*
* @deprecated Pre-created users are deprecated and no longer supported.
- * Use {@link #getUsers()}, {@link #getUsers(boolean)}, or {@link #getAliveUsers()}
- * instead.
+ * Use {@link #getUsers()}, or {@link #getAliveUsers()} instead.
* @hide
*/
@Deprecated
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 77c0067..ac6b2b2 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -1293,7 +1293,8 @@
USER_MISSED_NO_VIBRATE,
USER_MISSED_CALL_SCREENING_SERVICE_SILENCED,
USER_MISSED_CALL_FILTERS_TIMEOUT,
- USER_MISSED_NEVER_RANG
+ USER_MISSED_NEVER_RANG,
+ USER_MISSED_NOT_RUNNING
})
@Retention(RetentionPolicy.SOURCE)
public @interface MissedReason {}
@@ -1391,6 +1392,13 @@
public static final long USER_MISSED_NEVER_RANG = 1 << 23;
/**
+ * When {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE}, set this bit when
+ * the user receiving the call is not running (i.e. work profile paused).
+ * @hide
+ */
+ public static final long USER_MISSED_NOT_RUNNING = 1 << 24;
+
+ /**
* Where the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#MISSED_TYPE},
* indicates factors which may have lead the user to miss the call.
* <P>Type: INTEGER</P>
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 196bac2..cd76754 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -1106,6 +1106,16 @@
mTransformedTextUpdate.before = before;
mTransformedTextUpdate.after = after;
}
+ // When there is a transformed text, we have to reflow the DynamicLayout based on
+ // the transformed indices instead of the range in base text.
+ // For example,
+ // base text: abcd > abce
+ // updated range: where = 3, before = 1, after = 1
+ // transformed text: abxxcd > abxxce
+ // updated range: where = 5, before = 1, after = 1
+ //
+ // Because the transformedText is udapted simultaneously with the base text,
+ // the range must be transformed before the base text changes.
transformedText.originalToTransformed(mTransformedTextUpdate);
}
}
@@ -1113,9 +1123,20 @@
public void onTextChanged(CharSequence s, int where, int before, int after) {
final DynamicLayout dynamicLayout = mLayout.get();
if (dynamicLayout != null && dynamicLayout.mDisplay instanceof OffsetMapping) {
- where = mTransformedTextUpdate.where;
- before = mTransformedTextUpdate.before;
- after = mTransformedTextUpdate.after;
+ if (mTransformedTextUpdate != null && mTransformedTextUpdate.where >= 0) {
+ where = mTransformedTextUpdate.where;
+ before = mTransformedTextUpdate.before;
+ after = mTransformedTextUpdate.after;
+ // Set where to -1 so that we know if beforeTextChanged is called.
+ mTransformedTextUpdate.where = -1;
+ } else {
+ // onTextChanged is called without beforeTextChanged. Reflow the entire text.
+ where = 0;
+ // We can't get the before length from the text, use the line end of the
+ // last line instead.
+ before = dynamicLayout.getLineEnd(dynamicLayout.getLineCount() - 1);
+ after = dynamicLayout.mDisplay.length();
+ }
}
reflow(s, where, before, after);
}
diff --git a/core/java/android/text/method/InsertModeTransformationMethod.java b/core/java/android/text/method/InsertModeTransformationMethod.java
index 0c933d9..59b80f3 100644
--- a/core/java/android/text/method/InsertModeTransformationMethod.java
+++ b/core/java/android/text/method/InsertModeTransformationMethod.java
@@ -37,6 +37,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import java.lang.reflect.Array;
+
/**
* The transformation method used by handwriting insert mode.
* This transformation will insert a placeholder string to the original text at the given
@@ -309,26 +311,51 @@
return ArrayUtils.emptyArray(type);
}
- final T[] spansOriginal;
+ T[] spansOriginal = null;
if (mSpannedOriginal != null) {
final int originalStart =
transformedToOriginal(start, OffsetMapping.MAP_STRATEGY_CURSOR);
final int originalEnd =
transformedToOriginal(end, OffsetMapping.MAP_STRATEGY_CURSOR);
+ // We can't simply call SpannedString.getSpans(originalStart, originalEnd) here.
+ // When start == end SpannedString.getSpans returns spans whose spanEnd == start.
+ // For example,
+ // text: abcd span: [1, 3)
+ // getSpan(3, 3) will return the span [1, 3) but getSpan(3, 4) returns no span.
+ //
+ // This creates some special cases when originalStart == originalEnd.
+ // For example:
+ // original text: abcd span1: [1, 3) span2: [3, 4) span3: [3, 3)
+ // transformed text: abc\n\nd span1: [1, 3) span2: [5, 6) span3: [3, 3)
+ // Case 1:
+ // When start = 3 and end = 4, transformedText#getSpan(3, 4) should return span3.
+ // However, because originalStart == originalEnd == 3, originalText#getSpan(3, 3)
+ // returns span1, span2 and span3.
+ //
+ // Case 2:
+ // When start == end == 4, transformedText#getSpan(4, 4) should return nothing.
+ // However, because originalStart == originalEnd == 3, originalText#getSpan(3, 3)
+ // return span1, span2 and span3.
+ //
+ // Case 3:
+ // When start == end == 5, transformedText#getSpan(5, 5) should return span2.
+ // However, because originalStart == originalEnd == 3, originalText#getSpan(3, 3)
+ // return span1, span2 and span3.
+ //
+ // To handle the issue, we need to filter out the invalid spans.
spansOriginal = mSpannedOriginal.getSpans(originalStart, originalEnd, type);
- } else {
- spansOriginal = null;
+ spansOriginal = ArrayUtils.filter(spansOriginal,
+ size -> (T[]) Array.newInstance(type, size),
+ span -> intersect(getSpanStart(span), getSpanEnd(span), start, end));
}
- final T[] spansPlaceholder;
+ T[] spansPlaceholder = null;
if (mSpannedPlaceholder != null
&& intersect(start, end, mEnd, mEnd + mPlaceholder.length())) {
- final int placeholderStart = Math.max(start - mEnd, 0);
- final int placeholderEnd = Math.min(end - mEnd, mPlaceholder.length());
+ int placeholderStart = Math.max(start - mEnd, 0);
+ int placeholderEnd = Math.min(end - mEnd, mPlaceholder.length());
spansPlaceholder =
mSpannedPlaceholder.getSpans(placeholderStart, placeholderEnd, type);
- } else {
- spansPlaceholder = null;
}
// TODO: sort the spans based on their priority.
@@ -340,7 +367,10 @@
if (mSpannedOriginal != null) {
final int index = mSpannedOriginal.getSpanStart(tag);
if (index >= 0) {
- if (index < mEnd) {
+ // When originalSpanStart == originalSpanEnd == mEnd, the span should be
+ // considered "before" the placeholder text. So we return the originalSpanStart.
+ if (index < mEnd
+ || (index == mEnd && mSpannedOriginal.getSpanEnd(tag) == index)) {
return index;
}
return index + mPlaceholder.length();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9670735..705a2ce0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25074,7 +25074,7 @@
int viewStateIndex = 0;
if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED;
if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED;
- if (isFocused() && hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED;
+ if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED;
if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED;
if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED;
if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 34fe935..6c84f35 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11808,8 +11808,17 @@
public boolean hasSelection() {
final int selectionStart = getSelectionStart();
final int selectionEnd = getSelectionEnd();
+ final int selectionMin;
+ final int selectionMax;
+ if (selectionStart < selectionEnd) {
+ selectionMin = selectionStart;
+ selectionMax = selectionEnd;
+ } else {
+ selectionMin = selectionEnd;
+ selectionMax = selectionStart;
+ }
- return selectionStart >= 0 && selectionEnd > 0 && selectionStart != selectionEnd;
+ return selectionMin >= 0 && selectionMax > 0 && selectionMin != selectionMax;
}
String getSelectedText() {
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 617519b..fdcb87f 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -1468,6 +1468,11 @@
mHistoryLastLastWritten.setTo(mHistoryLastWritten);
final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence;
mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur);
+ if (mHistoryLastWritten.time < mHistoryLastLastWritten.time - 60000) {
+ Slog.wtf(TAG, "Significantly earlier event written to battery history:"
+ + " time=" + mHistoryLastWritten.time
+ + " previous=" + mHistoryLastLastWritten.time);
+ }
mHistoryLastWritten.tagsFirstOccurrence = hasTags;
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs;
@@ -1908,12 +1913,6 @@
in.setDataPosition(curPos + bufSize);
}
- if (DEBUG) {
- StringBuilder sb = new StringBuilder(128);
- sb.append("****************** OLD mHistoryBaseTimeMs: ");
- TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
- Slog.i(TAG, sb.toString());
- }
mHistoryBaseTimeMs = historyBaseTime;
if (DEBUG) {
StringBuilder sb = new StringBuilder(128);
@@ -1922,11 +1921,10 @@
Slog.i(TAG, sb.toString());
}
- // We are just arbitrarily going to insert 1 minute from the sample of
- // the last run until samples in this run.
if (mHistoryBaseTimeMs > 0) {
- long oldnow = mClock.elapsedRealtime();
- mHistoryBaseTimeMs = mHistoryBaseTimeMs - oldnow + 1;
+ long elapsedRealtimeMs = mClock.elapsedRealtime();
+ mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs;
+ mHistoryBaseTimeMs = mHistoryBaseTimeMs - elapsedRealtimeMs + 1;
if (DEBUG) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** ADJUSTED mHistoryBaseTimeMs: ");
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index d9152d6..01dbceb 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -50,7 +50,7 @@
}
void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName,
- jboolean angleIsSystemDriver, jstring devOptIn, jobjectArray featuresObj) {
+ jstring devOptIn, jobjectArray featuresObj) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
ScopedUtfChars devOptInChars(env, devOptIn);
@@ -74,18 +74,7 @@
}
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- angleIsSystemDriver, devOptInChars.c_str(),
- features);
-}
-
-void setLegacyDriverInfo_native(JNIEnv* env, jobject clazz, jstring appName,
- jboolean angleIsSystemDriver, jstring legacyDriverName) {
- ScopedUtfChars appNameChars(env, appName);
- ScopedUtfChars legacyDriverNameChars(env, legacyDriverName);
-
- android::GraphicsEnv::getInstance().setLegacyDriverInfo(appNameChars.c_str(),
- angleIsSystemDriver,
- legacyDriverNameChars.c_str());
+ devOptInChars.c_str(), features);
}
bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
@@ -135,10 +124,8 @@
{"setInjectLayersPrSetDumpable", "()Z",
reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
{"setAngleInfo",
- "(Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;[Ljava/lang/String;)V",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",
reinterpret_cast<void*>(setAngleInfo_native)},
- {"setLegacyDriverInfo", "(Ljava/lang/String;ZLjava/lang/String;)V",
- reinterpret_cast<void*>(setLegacyDriverInfo_native)},
{"getShouldUseAngle", "(Ljava/lang/String;)Z",
reinterpret_cast<void*>(shouldUseAngle_native)},
{"setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp
index 850755a..55995df 100644
--- a/core/jni/android_window_WindowInfosListener.cpp
+++ b/core/jni/android_window_WindowInfosListener.cpp
@@ -21,6 +21,7 @@
#include <android_runtime/Log.h>
#include <gui/DisplayInfo.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/WindowInfosUpdate.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalFrame.h>
#include <utils/Log.h>
@@ -91,8 +92,7 @@
WindowInfosListener(JNIEnv* env, jobject listener)
: mListener(env->NewWeakGlobalRef(listener)) {}
- void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,
- const std::vector<DisplayInfo>& displayInfos) override {
+ void onWindowInfosChanged(const gui::WindowInfosUpdate& update) override {
JNIEnv* env = AndroidRuntime::getJNIEnv();
LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onWindowInfoChanged.");
@@ -103,8 +103,10 @@
return;
}
- ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, windowInfos));
- ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, displayInfos));
+ ScopedLocalRef<jobjectArray> jWindowHandlesArray(env,
+ fromWindowInfos(env, update.windowInfos));
+ ScopedLocalRef<jobjectArray> jDisplayInfoArray(env,
+ fromDisplayInfos(env, update.displayInfos));
env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged,
jWindowHandlesArray.get(), jDisplayInfoArray.get());
diff --git a/core/proto/android/server/windowmanagertransitiontrace.proto b/core/proto/android/server/windowmanagertransitiontrace.proto
index a776bd2..a950a79 100644
--- a/core/proto/android/server/windowmanagertransitiontrace.proto
+++ b/core/proto/android/server/windowmanagertransitiontrace.proto
@@ -23,7 +23,7 @@
option java_multiple_files = true;
/* Represents a file full of transition entries.
- Encoded, it should start with 0x09 0x54 0x52 0x4E 0x54 0x52 0x41 0x43 0x45 (TRNTRACE), such
+ Encoded, it should start with 0x09 0x54 0x52 0x4E 0x54 0x52 0x41 0x43 0x45 (.TRNTRACE), such
that it can be easily identified. */
message TransitionTraceProto {
@@ -38,28 +38,24 @@
// Must be the first field, set to value in MagicNumber
required fixed64 magic_number = 1;
- // Transitions that don't have a finish time are considered aborted
- repeated Transition finished_transitions = 2;
-
- // Additional debugging info only collected and dumped when explicitly requested to trace
- repeated TransitionState transition_states = 3;
- repeated TransitionInfo transition_info = 4;
+ repeated Transition transitions = 2;
/* offset between real-time clock and elapsed time clock in nanoseconds.
Calculated as: 1000000 * System.currentTimeMillis() - SystemClock.elapsedRealtimeNanos() */
- optional fixed64 real_to_elapsed_time_offset_nanos = 5;
+ optional fixed64 real_to_elapsed_time_offset_nanos = 3;
}
message Transition {
- optional int32 id = 1; // Not dumped in always on tracing
- required uint64 start_transaction_id = 2;
- required uint64 finish_transaction_id = 3;
- required int64 create_time_ns = 4;
- required int64 send_time_ns = 5;
- optional int64 finish_time_ns = 6; // consider aborted if not provided
- required int32 type = 7;
+ required int32 id = 1;
+ optional uint64 start_transaction_id = 2;
+ optional uint64 finish_transaction_id = 3;
+ optional int64 create_time_ns = 4;
+ optional int64 send_time_ns = 5;
+ optional int64 finish_time_ns = 6;
+ optional int32 type = 7;
repeated Target targets = 8;
optional int32 flags = 9;
+ optional int64 abort_time_ns = 10;
}
message Target {
@@ -68,40 +64,3 @@
optional int32 window_id = 3; // Not dumped in always on tracing
optional int32 flags = 4;
}
-
-message TransitionState {
- enum State {
- COLLECTING = 0;
- PENDING = -1;
- STARTED = 1;
- PLAYING = 2;
- ABORT = 3;
- FINISHED = 4;
- }
-
- required int64 time_ns = 1;
- required int32 transition_id = 2;
- required int32 transition_type = 3;
- required State state = 4;
- required int32 flags = 5;
- repeated ChangeInfo change = 6;
- repeated com.android.server.wm.IdentifierProto participants = 7;
-}
-
-message ChangeInfo {
- required com.android.server.wm.IdentifierProto window_identifier = 1;
- required int32 transit_mode = 2;
- required bool has_changed = 3;
- required int32 change_flags = 4;
- required int32 windowing_mode = 5;
-}
-
-message TransitionInfo {
- required int32 transition_id = 1;
- repeated TransitionInfoChange change = 2;
-}
-
-message TransitionInfoChange {
- required int32 layer_id = 1;
- required int32 mode = 2;
-}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fefa79f..7e0a36d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4976,11 +4976,11 @@
android:protectionLevel="signature" />
<!-- Allows an application to subscribe to keyguard locked (i.e., showing) state.
- <p>Protection level: internal|role
- <p>Intended for use by ROLE_ASSISTANT only.
+ <p>Protection level: signature|role
+ <p>Intended for use by ROLE_ASSISTANT and signature apps only.
-->
<permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE"
- android:protectionLevel="internal|role"/>
+ android:protectionLevel="signature|role"/>
<!-- Must be required by a {@link android.service.autofill.AutofillService},
to ensure that only the system can bind to it.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7de36a71..6f7bc53 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2791,7 +2791,7 @@
<flag name="noExcludeDescendants" value="0x8" />
</attr>
- <!-- Boolean that hints the Android System that the view is credntial and associated with
+ <!-- Boolean that hints the Android System that the view is credential and associated with
CredentialManager -->
<attr name="isCredential" format="boolean" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bf141b5..17d8402 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -774,11 +774,6 @@
we rely on gravity to determine the effective orientation. -->
<bool name="config_deskDockEnablesAccelerometer">true</bool>
- <!-- Control whether nosensor and locked orientation requests are respected from the app when
- config_deskDockEnablesAccelerometer is set to false.
- TODO(b/274763533): Consider making true by default and removing this. -->
- <bool name="config_deskRespectsNoSensorAndLockedWithoutAccelerometer">false</bool>
-
<!-- Car dock behavior -->
<!-- The number of degrees to rotate the display when the device is in a car dock.
@@ -6440,4 +6435,8 @@
<bool name="config_persistBrightnessNitsForDefaultDisplay">false</bool>
<!-- Whether to request the approval before commit sessions. -->
<bool name="config_isPreApprovalRequestAvailable">true</bool>
+
+ <!-- Whether the AOSP support for app cloning building blocks is to be enabled for the
+ device. -->
+ <bool name="config_enableAppCloningBuildingBlocks">true</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c91e3cb..e3697bb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -480,6 +480,7 @@
<java-symbol type="bool" name="config_multiuserDelayUserDataLocking" />
<java-symbol type="bool" name="config_multiuserVisibleBackgroundUsers" />
<java-symbol type="bool" name="config_multiuserVisibleBackgroundUsersOnDefaultDisplay" />
+ <java-symbol type="bool" name="config_enableAppCloningBuildingBlocks" />
<java-symbol type="bool" name="config_enableTimeoutToDockUserWhenDocked" />
<java-symbol type="integer" name="config_userTypePackageWhitelistMode"/>
<java-symbol type="xml" name="config_user_types" />
@@ -1698,7 +1699,6 @@
<java-symbol type="bool" name="config_carDockEnablesAccelerometer" />
<java-symbol type="bool" name="config_customUserSwitchUi" />
<java-symbol type="bool" name="config_deskDockEnablesAccelerometer" />
- <java-symbol type="bool" name="config_deskRespectsNoSensorAndLockedWithoutAccelerometer" />
<java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
<java-symbol type="bool" name="config_enableCarDockHomeLaunch" />
<java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
index c7b82b1..6a6a951 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
@@ -750,6 +750,15 @@
}
@Test
+ public void onTuneFailed_withCanceledResult() throws Exception {
+ mTunerCallback.onTuneFailed(RadioTuner.TUNER_RESULT_CANCELED, FM_SELECTOR);
+
+ verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onTuneFailed(
+ RadioTuner.TUNER_RESULT_CANCELED, FM_SELECTOR);
+ verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onError(RadioTuner.ERROR_CANCELLED);
+ }
+
+ @Test
public void onProgramListChanged_forTunerCallbackAdapter() throws Exception {
mTunerCallback.onProgramListChanged();
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutOffsetMappingTest.java b/core/tests/coretests/src/android/text/DynamicLayoutOffsetMappingTest.java
index 76f4171..5939c06 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutOffsetMappingTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutOffsetMappingTest.java
@@ -119,6 +119,86 @@
assertLineRange(layout, /* lineBreaks */ 0, 5, 6, 8);
}
+ @Test
+ public void textWithOffsetMapping_blockBeforeTextChanged_deletion() {
+ final String text = "abcdef";
+ final SpannableStringBuilder spannable = new TestNoBeforeTextChangeSpannableString(text);
+ final CharSequence transformedText =
+ new TestOffsetMapping(spannable, 5, "\n\n");
+
+ final DynamicLayout layout = DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ // delete "cd", original text becomes "abef"
+ spannable.delete(2, 4);
+ assertThat(transformedText.toString()).isEqualTo("abe\n\nf");
+ assertLineRange(layout, /* lineBreaks */ 0, 4, 5, 6);
+
+ // delete "abe", original text becomes "f"
+ spannable.delete(0, 3);
+ assertThat(transformedText.toString()).isEqualTo("\n\nf");
+ assertLineRange(layout, /* lineBreaks */ 0, 1, 2, 3);
+ }
+
+ @Test
+ public void textWithOffsetMapping_blockBeforeTextChanged_insertion() {
+ final String text = "abcdef";
+ final SpannableStringBuilder spannable = new TestNoBeforeTextChangeSpannableString(text);
+ final CharSequence transformedText = new TestOffsetMapping(spannable, 3, "\n\n");
+
+ final DynamicLayout layout = DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ spannable.insert(3, "x");
+ assertThat(transformedText.toString()).isEqualTo("abcx\n\ndef");
+ assertLineRange(layout, /* lineBreaks */ 0, 5, 6, 9);
+
+ spannable.insert(5, "x");
+ assertThat(transformedText.toString()).isEqualTo("abcx\n\ndxef");
+ assertLineRange(layout, /* lineBreaks */ 0, 5, 6, 10);
+ }
+
+ @Test
+ public void textWithOffsetMapping_blockBeforeTextChanged_replace() {
+ final String text = "abcdef";
+ final SpannableStringBuilder spannable = new TestNoBeforeTextChangeSpannableString(text);
+ final CharSequence transformedText = new TestOffsetMapping(spannable, 3, "\n\n");
+
+ final DynamicLayout layout = DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ spannable.replace(2, 4, "xx");
+ assertThat(transformedText.toString()).isEqualTo("abxx\n\nef");
+ assertLineRange(layout, /* lineBreaks */ 0, 5, 6, 8);
+ }
+
+ @Test
+ public void textWithOffsetMapping_onlyCallOnTextChanged_notCrash() {
+ String text = "abcdef";
+ SpannableStringBuilder spannable = new SpannableStringBuilder(text);
+ CharSequence transformedText = new TestOffsetMapping(spannable, 3, "\n\n");
+
+ DynamicLayout.Builder.obtain(spannable, sTextPaint, WIDTH)
+ .setAlignment(ALIGN_NORMAL)
+ .setIncludePad(false)
+ .setDisplayText(transformedText)
+ .build();
+
+ TextWatcher[] textWatcher = spannable.getSpans(0, spannable.length(), TextWatcher.class);
+ assertThat(textWatcher.length).isEqualTo(1);
+
+ textWatcher[0].onTextChanged(spannable, 0, 2, 2);
+ }
+
private void assertLineRange(Layout layout, int... lineBreaks) {
final int lineCount = lineBreaks.length - 1;
assertThat(layout.getLineCount()).isEqualTo(lineCount);
@@ -129,6 +209,50 @@
}
/**
+ * A test SpannableStringBuilder that doesn't call beforeTextChanged. It's used to test
+ * DynamicLayout against some special cases where beforeTextChanged callback is not properly
+ * called.
+ */
+ private static class TestNoBeforeTextChangeSpannableString extends SpannableStringBuilder {
+
+ TestNoBeforeTextChangeSpannableString(CharSequence text) {
+ super(text);
+ }
+
+ @Override
+ public void setSpan(Object what, int start, int end, int flags) {
+ if (what instanceof TextWatcher) {
+ super.setSpan(new TestNoBeforeTextChangeWatcherWrapper((TextWatcher) what), start,
+ end, flags);
+ } else {
+ super.setSpan(what, start, end, flags);
+ }
+ }
+ }
+
+ /** A TextWatcherWrapper that blocks beforeTextChanged callback. */
+ private static class TestNoBeforeTextChangeWatcherWrapper implements TextWatcher {
+ private final TextWatcher mTextWatcher;
+
+ TestNoBeforeTextChangeWatcherWrapper(TextWatcher textWatcher) {
+ mTextWatcher = textWatcher;
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ mTextWatcher.onTextChanged(s, start, before, count);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mTextWatcher.afterTextChanged(s);
+ }
+ }
+
+ /**
* A test TransformedText that inserts some text at the given offset.
*/
private static class TestOffsetMapping implements OffsetMapping, CharSequence {
diff --git a/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java b/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java
index 7706d9a..9ef137b 100644
--- a/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java
+++ b/core/tests/coretests/src/android/text/method/InsertModeTransformationMethodTest.java
@@ -224,6 +224,12 @@
assertThat(spans0to2.length).isEqualTo(1);
assertThat(spans0to2[0]).isEqualTo(span1);
+ // only span2 is in the range of [3, 4).
+ // note: span1 [0, 3) is not in the range because [3, 4) is not collapsed.
+ final TestSpan[] spans3to4 = transformedText.getSpans(3, 4, TestSpan.class);
+ assertThat(spans3to4.length).isEqualTo(1);
+ assertThat(spans3to4[0]).isEqualTo(span2);
+
// span1 and span2 are in the range of [1, 6).
final TestSpan[] spans1to6 = transformedText.getSpans(1, 6, TestSpan.class);
assertThat(spans1to6.length).isEqualTo(2);
@@ -262,7 +268,7 @@
text.setSpan(span2, 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(span3, 4, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- // In the transformedText, the new ranges of the spans are:
+ // In the transformedText "abc\uFFFD def", the new ranges of the spans are:
// span1: [0, 3)
// span2: [2, 5)
// span3: [5, 6)
@@ -277,6 +283,12 @@
assertThat(spans0to2.length).isEqualTo(1);
assertThat(spans0to2[0]).isEqualTo(span1);
+ // only span2 is in the range of [3, 4).
+ // note: span1 [0, 3) is not in the range because [3, 4) is not collapsed.
+ final TestSpan[] spans3to4 = transformedText.getSpans(3, 4, TestSpan.class);
+ assertThat(spans3to4.length).isEqualTo(1);
+ assertThat(spans3to4[0]).isEqualTo(span2);
+
// span1 and span2 are in the range of [1, 5).
final TestSpan[] spans1to4 = transformedText.getSpans(1, 4, TestSpan.class);
assertThat(spans1to4.length).isEqualTo(2);
@@ -318,20 +330,143 @@
}
@Test
- public void transformedText_getSpanStartAndEnd() {
+ public void transformedText_getSpans_collapsedRange() {
final SpannableString text = new SpannableString(TEXT);
final TestSpan span1 = new TestSpan();
final TestSpan span2 = new TestSpan();
final TestSpan span3 = new TestSpan();
text.setSpan(span1, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span2, 3, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span3, 3, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ // In the transformedText "abc\n\n def", the new ranges of the spans are:
+ // span1: [0, 3)
+ // span2: [3, 3)
+ // span3: [5, 6)
+ final InsertModeTransformationMethod transformationMethod =
+ new InsertModeTransformationMethod(3, false, null);
+ final Spanned transformedText =
+ (Spanned) transformationMethod.getTransformation(text, sView);
+
+ // only span1 is in the range of [0, 0).
+ final TestSpan[] spans0to0 = transformedText.getSpans(0, 0, TestSpan.class);
+ assertThat(spans0to0.length).isEqualTo(1);
+ assertThat(spans0to0[0]).isEqualTo(span1);
+
+ // span1 and span 2 are in the range of [3, 3).
+ final TestSpan[] spans3to3 = transformedText.getSpans(3, 3, TestSpan.class);
+ assertThat(spans3to3.length).isEqualTo(2);
+ assertThat(spans3to3[0]).isEqualTo(span1);
+ assertThat(spans3to3[1]).isEqualTo(span2);
+
+ // only the span2 with collapsed range is in the range of [3, 4).
+ final TestSpan[] spans3to4 = transformedText.getSpans(3, 4, TestSpan.class);
+ assertThat(spans3to4.length).isEqualTo(1);
+ assertThat(spans3to4[0]).isEqualTo(span2);
+
+ // no span is in the range of [4, 5). (span2 is not mistakenly included.)
+ final TestSpan[] spans4to5 = transformedText.getSpans(4, 5, TestSpan.class);
+ assertThat(spans4to5).isEmpty();
+
+ // only span3 is in the range of [4, 6). (span2 is not mistakenly included.)
+ final TestSpan[] spans4to6 = transformedText.getSpans(4, 6, TestSpan.class);
+ assertThat(spans4to6.length).isEqualTo(1);
+ assertThat(spans4to6[0]).isEqualTo(span3);
+
+ // no span is in the range of [4, 4).
+ final TestSpan[] spans4to4 = transformedText.getSpans(4, 4, TestSpan.class);
+ assertThat(spans4to4.length).isEqualTo(0);
+
+ // span3 is in the range of [5, 5).
+ final TestSpan[] spans5to5 = transformedText.getSpans(5, 5, TestSpan.class);
+ assertThat(spans5to5.length).isEqualTo(1);
+ assertThat(spans5to5[0]).isEqualTo(span3);
+
+ // span3 is in the range of [6, 6).
+ final TestSpan[] spans6to6 = transformedText.getSpans(6, 6, TestSpan.class);
+ assertThat(spans6to6.length).isEqualTo(1);
+ assertThat(spans6to6[0]).isEqualTo(span3);
+ }
+
+ @Test
+ public void transformedText_getSpans_collapsedRange_singleLine() {
+ final SpannableString text = new SpannableString(TEXT);
+ final TestSpan span1 = new TestSpan();
+ final TestSpan span2 = new TestSpan();
+ final TestSpan span3 = new TestSpan();
+
+ text.setSpan(span1, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span2, 3, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span3, 3, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ // In the transformedText "abc\uFFFD def", the new ranges of the spans are:
+ // span1: [0, 3)
+ // span2: [3, 3)
+ // span3: [4, 5)
+ final InsertModeTransformationMethod transformationMethod =
+ new InsertModeTransformationMethod(3, true, null);
+ final Spanned transformedText =
+ (Spanned) transformationMethod.getTransformation(text, sView);
+
+ // only span1 is in the range of [0, 0).
+ final TestSpan[] spans0to0 = transformedText.getSpans(0, 0, TestSpan.class);
+ assertThat(spans0to0.length).isEqualTo(1);
+ assertThat(spans0to0[0]).isEqualTo(span1);
+
+ // span1 and span2 are in the range of [3, 3).
+ final TestSpan[] spans3to3 = transformedText.getSpans(3, 3, TestSpan.class);
+ assertThat(spans3to3.length).isEqualTo(2);
+ assertThat(spans3to3[0]).isEqualTo(span1);
+ assertThat(spans3to3[1]).isEqualTo(span2);
+
+ // only the span2 with collapsed range is in the range of [3, 4).
+ final TestSpan[] spans3to4 = transformedText.getSpans(3, 4, TestSpan.class);
+ assertThat(spans3to4.length).isEqualTo(1);
+ assertThat(spans3to4[0]).isEqualTo(span2);
+
+ // span3 is in the range of [4, 5). (span2 is not mistakenly included.)
+ final TestSpan[] spans4to5 = transformedText.getSpans(4, 5, TestSpan.class);
+ assertThat(spans4to5.length).isEqualTo(1);
+ assertThat(spans4to5[0]).isEqualTo(span3);
+
+ // only span3 is in the range of [4, 6). (span2 is not mistakenly included.)
+ final TestSpan[] spans4to6 = transformedText.getSpans(4, 6, TestSpan.class);
+ assertThat(spans4to6.length).isEqualTo(1);
+ assertThat(spans4to6[0]).isEqualTo(span3);
+
+ // span3 is in the range of [4, 4).
+ final TestSpan[] spans4to4 = transformedText.getSpans(4, 4, TestSpan.class);
+ assertThat(spans4to4.length).isEqualTo(1);
+ assertThat(spans4to4[0]).isEqualTo(span3);
+
+ // span3 is in the range of [5, 5).
+ final TestSpan[] spans5to5 = transformedText.getSpans(5, 5, TestSpan.class);
+ assertThat(spans5to5.length).isEqualTo(1);
+ assertThat(spans5to5[0]).isEqualTo(span3);
+ }
+
+ @Test
+ public void transformedText_getSpanStartAndEnd() {
+ final SpannableString text = new SpannableString(TEXT);
+ final TestSpan span1 = new TestSpan();
+ final TestSpan span2 = new TestSpan();
+ final TestSpan span3 = new TestSpan();
+ final TestSpan span4 = new TestSpan();
+ final TestSpan span5 = new TestSpan();
+
+ text.setSpan(span1, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(span2, 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(span3, 4, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span4, 3, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span5, 3, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// In the transformedText, the new ranges of the spans are:
// span1: [0, 3)
// span2: [2, 6)
// span3: [6, 7)
+ // span4: [3, 3)
+ // span5: [5, 6)
final InsertModeTransformationMethod transformationMethod =
new InsertModeTransformationMethod(3, false, null);
final Spanned transformedText =
@@ -345,6 +480,12 @@
assertThat(transformedText.getSpanStart(span3)).isEqualTo(6);
assertThat(transformedText.getSpanEnd(span3)).isEqualTo(7);
+
+ assertThat(transformedText.getSpanStart(span4)).isEqualTo(3);
+ assertThat(transformedText.getSpanEnd(span4)).isEqualTo(3);
+
+ assertThat(transformedText.getSpanStart(span5)).isEqualTo(5);
+ assertThat(transformedText.getSpanEnd(span5)).isEqualTo(6);
}
@Test
@@ -353,15 +494,21 @@
final TestSpan span1 = new TestSpan();
final TestSpan span2 = new TestSpan();
final TestSpan span3 = new TestSpan();
+ final TestSpan span4 = new TestSpan();
+ final TestSpan span5 = new TestSpan();
text.setSpan(span1, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(span2, 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(span3, 4, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span4, 3, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(span5, 3, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// In the transformedText, the new ranges of the spans are:
// span1: [0, 3)
// span2: [2, 5)
// span3: [5, 6)
+ // span4: [3. 3)
+ // span5: [4, 5)
final InsertModeTransformationMethod transformationMethod =
new InsertModeTransformationMethod(3, true, null);
final Spanned transformedText =
@@ -376,6 +523,12 @@
assertThat(transformedText.getSpanStart(span3)).isEqualTo(5);
assertThat(transformedText.getSpanEnd(span3)).isEqualTo(6);
+ assertThat(transformedText.getSpanStart(span4)).isEqualTo(3);
+ assertThat(transformedText.getSpanEnd(span4)).isEqualTo(3);
+
+ assertThat(transformedText.getSpanStart(span5)).isEqualTo(4);
+ assertThat(transformedText.getSpanEnd(span5)).isEqualTo(5);
+
final ReplacementSpan[] replacementSpans =
transformedText.getSpans(0, 8, ReplacementSpan.class);
assertThat(transformedText.getSpanStart(replacementSpans[0])).isEqualTo(3);
diff --git a/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto b/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto
index 6e01101..c82a70c 100644
--- a/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto
+++ b/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto
@@ -37,6 +37,9 @@
required fixed64 magic_number = 1;
repeated Transition transitions = 2;
repeated HandlerMapping handlerMappings = 3;
+ /* offset between real-time clock and elapsed time clock in nanoseconds.
+ Calculated as: 1000000 * System.currentTimeMillis() - SystemClock.elapsedRealtimeNanos() */
+ optional fixed64 real_to_elapsed_time_offset_nanos = 4;
}
message Transition {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 19eff0e..1793a3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -255,7 +255,7 @@
private boolean shouldShowBackdrop(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change) {
final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE,
- mTransitionAnimation);
+ mTransitionAnimation, false);
return a != null && a.getShowBackdrop();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index e8014af..adc0c9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -479,7 +479,7 @@
void applyThemeAttrs() {
final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
android.R.attr.dialogCornerRadius,
- android.R.attr.colorBackgroundFloating});
+ com.android.internal.R.attr.materialColorSurfaceBright});
boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
mContext.getResources());
mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index e7dede7..2832c55 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -412,7 +412,10 @@
/** Releases and re-inflates {@link DividerView} on the root surface. */
public void update(SurfaceControl.Transaction t) {
- if (!mInitialized) return;
+ if (!mInitialized) {
+ init();
+ return;
+ }
mSplitWindowManager.release(t);
mImePositionProcessor.reset();
mSplitWindowManager.init(this, mInsetsState);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 838e37a..2bbd870 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -47,6 +47,8 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import dagger.Lazy;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
@@ -55,8 +57,6 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
-import dagger.Lazy;
-
/**
* Controller to show/update compat UI components on Tasks based on whether the foreground
* activities are in compatibility mode.
@@ -284,13 +284,18 @@
ShellTaskOrganizer.TaskListener taskListener) {
CompatUIWindowManager layout = mActiveCompatLayouts.get(taskInfo.taskId);
if (layout != null) {
- // UI already exists, update the UI layout.
- if (!layout.updateCompatInfo(taskInfo, taskListener,
- showOnDisplay(layout.getDisplayId()))) {
- // The layout is no longer eligible to be shown, remove from active layouts.
+ if (layout.needsToBeRecreated(taskInfo, taskListener)) {
mActiveCompatLayouts.remove(taskInfo.taskId);
+ layout.release();
+ } else {
+ // UI already exists, update the UI layout.
+ if (!layout.updateCompatInfo(taskInfo, taskListener,
+ showOnDisplay(layout.getDisplayId()))) {
+ // The layout is no longer eligible to be shown, remove from active layouts.
+ mActiveCompatLayouts.remove(taskInfo.taskId);
+ }
+ return;
}
- return;
}
// Create a new UI layout.
@@ -433,13 +438,18 @@
private void createOrUpdateReachabilityEduLayout(TaskInfo taskInfo,
ShellTaskOrganizer.TaskListener taskListener) {
if (mActiveReachabilityEduLayout != null) {
- // UI already exists, update the UI layout.
- if (!mActiveReachabilityEduLayout.updateCompatInfo(taskInfo, taskListener,
- showOnDisplay(mActiveReachabilityEduLayout.getDisplayId()))) {
- // The layout is no longer eligible to be shown, remove from active layouts.
+ if (mActiveReachabilityEduLayout.needsToBeRecreated(taskInfo, taskListener)) {
+ mActiveReachabilityEduLayout.release();
mActiveReachabilityEduLayout = null;
+ } else {
+ // UI already exists, update the UI layout.
+ if (!mActiveReachabilityEduLayout.updateCompatInfo(taskInfo, taskListener,
+ showOnDisplay(mActiveReachabilityEduLayout.getDisplayId()))) {
+ // The layout is no longer eligible to be shown, remove from active layouts.
+ mActiveReachabilityEduLayout = null;
+ }
+ return;
}
- return;
}
// Create a new UI layout.
final Context context = getOrCreateDisplayContext(taskInfo.displayId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 6592292..d4778fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -22,7 +22,6 @@
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.app.TaskInfo.CameraCompatControlState;
@@ -53,9 +52,6 @@
private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartButtonClicked;
- @NonNull
- private TaskInfo mTaskInfo;
-
// Remember the last reported states in case visibility changes due to keyguard or IME updates.
@VisibleForTesting
boolean mHasSizeCompat;
@@ -77,7 +73,6 @@
CompatUIHintsState compatUIHintsState, CompatUIConfiguration compatUIConfiguration,
Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartButtonClicked) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
- mTaskInfo = taskInfo;
mCallback = callback;
mHasSizeCompat = taskInfo.topActivityInSizeCompat;
mCameraCompatControlState = taskInfo.cameraCompatControlState;
@@ -129,7 +124,6 @@
@Override
public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
boolean canShow) {
- mTaskInfo = taskInfo;
final boolean prevHasSizeCompat = mHasSizeCompat;
final int prevCameraCompatControlState = mCameraCompatControlState;
mHasSizeCompat = taskInfo.topActivityInSizeCompat;
@@ -149,7 +143,7 @@
/** Called when the restart button is clicked. */
void onRestartButtonClicked() {
- mOnRestartButtonClicked.accept(Pair.create(mTaskInfo, getTaskListener()));
+ mOnRestartButtonClicked.accept(Pair.create(getLastTaskInfo(), getTaskListener()));
}
/** Called when the camera treatment button is clicked. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index 9c4e79c..180498c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -26,6 +26,7 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
@@ -65,6 +66,9 @@
private DisplayLayout mDisplayLayout;
private final Rect mStableBounds;
+ @NonNull
+ private TaskInfo mTaskInfo;
+
/**
* Utility class for adding and releasing a View hierarchy for this {@link
* WindowlessWindowManager} to {@code mLeash}.
@@ -83,6 +87,7 @@
SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
DisplayLayout displayLayout) {
super(taskInfo.configuration, null /* rootSurface */, null /* hostInputToken */);
+ mTaskInfo = taskInfo;
mContext = context;
mSyncQueue = syncQueue;
mTaskConfig = taskInfo.configuration;
@@ -95,6 +100,17 @@
}
/**
+ * @return {@code true} if the instance of the specific {@link CompatUIWindowManagerAbstract}
+ * for the current task id needs to be recreated loading the related resources. This happens
+ * if the user switches between Light/Dark mode, if the device is docked/undocked or if the
+ * user switches between multi-window mode to fullscreen where the
+ * {@link ShellTaskOrganizer.TaskListener} implementation is different.
+ */
+ boolean needsToBeRecreated(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) {
+ return hasUiModeChanged(mTaskInfo, taskInfo) || hasTaskListenerChanged(taskListener);
+ }
+
+ /**
* Returns the z-order of this window which will be passed to the {@link SurfaceControl} once
* {@link #attachToParentSurface} is called.
*
@@ -195,6 +211,7 @@
@VisibleForTesting(visibility = PROTECTED)
public boolean updateCompatInfo(TaskInfo taskInfo,
ShellTaskOrganizer.TaskListener taskListener, boolean canShow) {
+ mTaskInfo = taskInfo;
final Configuration prevTaskConfig = mTaskConfig;
final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener;
mTaskConfig = taskInfo.configuration;
@@ -315,6 +332,11 @@
updateSurfacePosition();
}
+ @Nullable
+ protected TaskInfo getLastTaskInfo() {
+ return mTaskInfo;
+ }
+
/**
* Called following a change in the task bounds, display layout stable bounds, or the layout
* direction.
@@ -402,4 +424,12 @@
protected final String getTag() {
return getClass().getSimpleName();
}
+
+ protected boolean hasTaskListenerChanged(ShellTaskOrganizer.TaskListener newTaskListener) {
+ return !mTaskListener.equals(newTaskListener);
+ }
+
+ protected static boolean hasUiModeChanged(TaskInfo currentTaskInfo, TaskInfo newTaskInfo) {
+ return currentTaskInfo.configuration.uiMode != newTaskInfo.configuration.uiMode;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
index 959c50d..9a67258 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
@@ -19,7 +19,6 @@
import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
@@ -69,9 +68,6 @@
@VisibleForTesting
LetterboxEduDialogLayout mLayout;
- @NonNull
- private TaskInfo mTaskInfo;
-
/**
* The vertical margin between the dialog container and the task stable bounds (excluding
* insets).
@@ -99,7 +95,6 @@
DialogAnimationController<LetterboxEduDialogLayout> animationController,
DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
- mTaskInfo = taskInfo;
mTransitions = transitions;
mOnDismissCallback = onDismissCallback;
mAnimationController = animationController;
@@ -197,7 +192,7 @@
mLayout.setDismissOnClickListener(null);
mAnimationController.startExitAnimation(mLayout, () -> {
release();
- mOnDismissCallback.accept(Pair.create(mTaskInfo, getTaskListener()));
+ mOnDismissCallback.accept(Pair.create(getLastTaskInfo(), getTaskListener()));
});
}
@@ -210,7 +205,6 @@
@Override
public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
boolean canShow) {
- mTaskInfo = taskInfo;
mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
return super.updateCompatInfo(taskInfo, taskListener, canShow);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
index a18ab91..95bb1fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
@@ -20,7 +20,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
@@ -52,9 +51,6 @@
private final ShellExecutor mMainExecutor;
- @NonNull
- private TaskInfo mTaskInfo;
-
private boolean mIsActivityLetterboxed;
private int mLetterboxVerticalPosition;
@@ -86,7 +82,6 @@
ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout,
CompatUIConfiguration compatUIConfiguration, ShellExecutor mainExecutor) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
- mTaskInfo = taskInfo;
mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled;
mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition;
mLetterboxHorizontalPosition = taskInfo.topActivityLetterboxHorizontalPosition;
@@ -136,7 +131,6 @@
@Override
public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
boolean canShow) {
- mTaskInfo = taskInfo;
final boolean prevIsActivityLetterboxed = mIsActivityLetterboxed;
final int prevLetterboxVerticalPosition = mLetterboxVerticalPosition;
final int prevLetterboxHorizontalPosition = mLetterboxHorizontalPosition;
@@ -222,14 +216,14 @@
if (mLayout == null) {
return;
}
-
+ final TaskInfo lastTaskInfo = getLastTaskInfo();
final boolean eligibleForDisplayHorizontalEducation = mForceUpdate
- || !mCompatUIConfiguration.hasSeenHorizontalReachabilityEducation(mTaskInfo)
+ || !mCompatUIConfiguration.hasSeenHorizontalReachabilityEducation(lastTaskInfo)
|| (mHasUserDoubleTapped
&& (mLetterboxHorizontalPosition == REACHABILITY_LEFT_OR_UP_POSITION
|| mLetterboxHorizontalPosition == REACHABILITY_RIGHT_OR_BOTTOM_POSITION));
final boolean eligibleForDisplayVerticalEducation = mForceUpdate
- || !mCompatUIConfiguration.hasSeenVerticalReachabilityEducation(mTaskInfo)
+ || !mCompatUIConfiguration.hasSeenVerticalReachabilityEducation(lastTaskInfo)
|| (mHasUserDoubleTapped
&& (mLetterboxVerticalPosition == REACHABILITY_LEFT_OR_UP_POSITION
|| mLetterboxVerticalPosition == REACHABILITY_RIGHT_OR_BOTTOM_POSITION));
@@ -241,7 +235,7 @@
mLayout.handleVisibility(eligibleForDisplayHorizontalEducation,
eligibleForDisplayVerticalEducation,
mLetterboxVerticalPosition, mLetterboxHorizontalPosition, availableWidth,
- availableHeight, mCompatUIConfiguration, mTaskInfo);
+ availableHeight, mCompatUIConfiguration, lastTaskInfo);
if (!mHasLetterboxSizeChanged) {
updateHideTime();
mMainExecutor.executeDelayed(this::hideReachability, DISAPPEAR_DELAY_MS);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
index 51e5141..a770da2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
@@ -19,7 +19,6 @@
import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
@@ -67,9 +66,6 @@
*/
private final int mDialogVerticalMargin;
- @NonNull
- private TaskInfo mTaskInfo;
-
@Nullable
@VisibleForTesting
RestartDialogLayout mLayout;
@@ -95,7 +91,6 @@
DialogAnimationController<RestartDialogLayout> animationController,
CompatUIConfiguration compatUIConfiguration) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
- mTaskInfo = taskInfo;
mTransitions = transitions;
mOnDismissCallback = onDismissCallback;
mOnRestartCallback = onRestartCallback;
@@ -125,7 +120,7 @@
protected boolean eligibleToShowLayout() {
// We don't show this dialog if the user has explicitly selected so clicking on a checkbox.
return mRequestRestartDialog && !isTaskbarEduShowing() && (mLayout != null
- || mCompatUIConfiguration.shouldShowRestartDialogAgain(mTaskInfo));
+ || mCompatUIConfiguration.shouldShowRestartDialogAgain(getLastTaskInfo()));
}
@Override
@@ -143,18 +138,6 @@
mRequestRestartDialog = enabled;
}
- @Override
- public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
- boolean canShow) {
- mTaskInfo = taskInfo;
- return super.updateCompatInfo(taskInfo, taskListener, canShow);
- }
-
- boolean needsToBeRecreated(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) {
- return taskInfo.configuration.uiMode != mTaskInfo.configuration.uiMode
- || !getTaskListener().equals(taskListener);
- }
-
private void updateDialogMargins() {
if (mLayout == null) {
return;
@@ -191,6 +174,7 @@
// Dialog has already been released.
return;
}
+ final TaskInfo lastTaskInfo = getLastTaskInfo();
mLayout.setDismissOnClickListener(this::onDismiss);
mLayout.setRestartOnClickListener(dontShowAgain -> {
if (mLayout != null) {
@@ -200,9 +184,9 @@
});
}
if (dontShowAgain) {
- mCompatUIConfiguration.setDontShowRestartDialogAgain(mTaskInfo);
+ mCompatUIConfiguration.setDontShowRestartDialogAgain(lastTaskInfo);
}
- mOnRestartCallback.accept(Pair.create(mTaskInfo, getTaskListener()));
+ mOnRestartCallback.accept(Pair.create(lastTaskInfo, getTaskListener()));
});
// Focus on the dialog title for accessibility.
mLayout.getDialogTitle().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
@@ -216,7 +200,7 @@
mLayout.setDismissOnClickListener(null);
mAnimationController.startExitAnimation(mLayout, () -> {
release();
- mOnDismissCallback.accept(Pair.create(mTaskInfo, getTaskListener()));
+ mOnDismissCallback.accept(Pair.create(getLastTaskInfo(), getTaskListener()));
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 00cc57f..3ab175d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -23,6 +23,8 @@
import androidx.core.util.forEach
import androidx.core.util.keyIterator
import androidx.core.util.valueIterator
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.util.KtProtoLog
import java.util.concurrent.Executor
import java.util.function.Consumer
@@ -140,6 +142,12 @@
val added = displayData.getOrCreate(displayId).activeTasks.add(taskId)
if (added) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: add active task=%d displayId=%d",
+ taskId,
+ displayId
+ )
activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) }
}
return added
@@ -158,6 +166,9 @@
result = true
}
}
+ if (result) {
+ KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remove active task=%d", taskId)
+ }
return result
}
@@ -221,6 +232,17 @@
displayData[displayId]?.visibleTasks?.remove(taskId)
}
val newCount = getVisibleTaskCount(displayId)
+
+ if (prevCount != newCount) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: update task visibility taskId=%d visible=%b displayId=%d",
+ taskId,
+ visible,
+ displayId
+ )
+ }
+
// Check if count changed and if there was no tasks or this is the first task
if (prevCount != newCount && (prevCount == 0 || newCount == 0)) {
notifyVisibleTaskListeners(displayId, newCount > 0)
@@ -244,6 +266,11 @@
* Add (or move if it already exists) the task to the top of the ordered list.
*/
fun addOrMoveFreeformTaskToTop(taskId: Int) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: add or move task to top taskId=%d",
+ taskId
+ )
if (freeformTasksInZOrder.contains(taskId)) {
freeformTasksInZOrder.remove(taskId)
}
@@ -254,6 +281,11 @@
* Remove the task from the ordered list.
*/
fun removeFreeformTask(taskId: Int) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: remove freeform task from ordered list taskId=%d",
+ taskId
+ )
freeformTasksInZOrder.remove(taskId)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index b310938..91bb155 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -39,7 +39,6 @@
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import androidx.annotation.BinderThread
-import com.android.internal.protolog.common.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.DisplayController
@@ -56,6 +55,7 @@
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.sysui.ShellSharedConstants
import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.util.KtProtoLog
import java.util.concurrent.Executor
import java.util.function.Consumer
@@ -91,7 +91,7 @@
}
private fun onInit() {
- ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopTasksController")
+ KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopTasksController")
shellController.addExternalInterface(
ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE,
{ createExternalInterface() },
@@ -102,7 +102,7 @@
/** Show all tasks, that are part of the desktop, on top of launcher */
fun showDesktopApps(displayId: Int) {
- ProtoLog.v(WM_SHELL_DESKTOP_MODE, "showDesktopApps")
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: showDesktopApps")
val wct = WindowContainerTransaction()
// TODO(b/278084491): pass in display id
bringDesktopAppsToFront(displayId, wct)
@@ -130,8 +130,11 @@
/** Move a task to desktop */
fun moveToDesktop(task: RunningTaskInfo) {
- ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDesktop: %d", task.taskId)
-
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: moveToDesktop taskId=%d",
+ task.taskId
+ )
val wct = WindowContainerTransaction()
// Bring other apps to front first
bringDesktopAppsToFront(task.displayId, wct)
@@ -147,10 +150,12 @@
* Moves a single task to freeform and sets the taskBounds to the passed in bounds,
* startBounds
*/
- fun moveToFreeform(
- taskInfo: RunningTaskInfo,
- startBounds: Rect
- ) {
+ fun moveToFreeform(taskInfo: RunningTaskInfo, startBounds: Rect) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: moveToFreeform with bounds taskId=%d",
+ taskInfo.taskId
+ )
val wct = WindowContainerTransaction()
moveHomeTaskToFront(wct)
addMoveToDesktopChanges(wct, taskInfo.getToken())
@@ -165,10 +170,12 @@
}
/** Brings apps to front and sets freeform task bounds */
- private fun moveToDesktopWithAnimation(
- taskInfo: RunningTaskInfo,
- freeformBounds: Rect
- ) {
+ private fun moveToDesktopWithAnimation(taskInfo: RunningTaskInfo, freeformBounds: Rect) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: moveToDesktop with animation taskId=%d",
+ taskInfo.taskId
+ )
val wct = WindowContainerTransaction()
bringDesktopAppsToFront(taskInfo.displayId, wct)
addMoveToDesktopChanges(wct, taskInfo.getToken())
@@ -190,7 +197,11 @@
/** Move a task to fullscreen */
fun moveToFullscreen(task: RunningTaskInfo) {
- ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToFullscreen: %d", task.taskId)
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: moveToFullscreen taskId=%d",
+ task.taskId
+ )
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
@@ -206,6 +217,11 @@
* status bar area
*/
fun cancelMoveToFreeform(task: RunningTaskInfo, position: Point) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: cancelMoveToFreeform taskId=%d",
+ task.taskId
+ )
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -218,6 +234,11 @@
}
private fun moveToFullscreenWithAnimation(task: RunningTaskInfo, position: Point) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: moveToFullscreen with animation taskId=%d",
+ task.taskId
+ )
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
@@ -230,8 +251,14 @@
}
}
- /** Move a task to the front **/
+ /** Move a task to the front */
fun moveTaskToFront(taskInfo: RunningTaskInfo) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: moveTaskToFront taskId=%d",
+ taskInfo.taskId
+ )
+
val wct = WindowContainerTransaction()
wct.reorder(taskInfo.token, true)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -255,10 +282,10 @@
fun moveToNextDisplay(taskId: Int) {
val task = shellTaskOrganizer.getRunningTaskInfo(taskId)
if (task == null) {
- ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d not found", taskId)
+ KtProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d not found", taskId)
return
}
- ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d taskDisplayId=%d",
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d taskDisplayId=%d",
taskId, task.displayId)
val displayIds = rootTaskDisplayAreaOrganizer.displayIds.sorted()
@@ -269,7 +296,7 @@
newDisplayId = displayIds.firstOrNull { displayId -> displayId < task.displayId }
}
if (newDisplayId == null) {
- ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: next display not found")
+ KtProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: next display not found")
return
}
moveToDisplay(task, newDisplayId)
@@ -281,17 +308,17 @@
* No-op if task is already on that display per [RunningTaskInfo.displayId].
*/
private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) {
- ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDisplay: taskId=%d displayId=%d",
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDisplay: taskId=%d displayId=%d",
task.taskId, displayId)
if (task.displayId == displayId) {
- ProtoLog.d(WM_SHELL_DESKTOP_MODE, "moveToDisplay: task already on display")
+ KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "moveToDisplay: task already on display")
return
}
val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
if (displayAreaInfo == null) {
- ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToDisplay: display not found")
+ KtProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToDisplay: display not found")
return
}
@@ -316,7 +343,7 @@
}
private fun bringDesktopAppsToFront(displayId: Int, wct: WindowContainerTransaction) {
- ProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront")
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: bringDesktopAppsToFront")
val activeTasks = desktopModeTaskRepository.getActiveTasks(displayId)
// First move home to front and then other tasks on top of it
@@ -397,9 +424,9 @@
if (task.windowingMode == WINDOWING_MODE_FULLSCREEN) {
// If there are any visible desktop tasks, switch the task to freeform
if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
- ProtoLog.d(
+ KtProtoLog.d(
WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController#handleRequest: switch fullscreen task to freeform," +
+ "DesktopTasksController: switch fullscreen task to freeform on transition" +
" taskId=%d",
task.taskId
)
@@ -414,9 +441,9 @@
// If no visible desktop tasks, switch this task to freeform as the transition came
// outside of this controller
if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
- ProtoLog.d(
+ KtProtoLog.d(
WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController#handleRequest: switch freeform task to fullscreen," +
+ "DesktopTasksController: switch freeform task to fullscreen oon transition" +
" taskId=%d",
task.taskId
)
@@ -627,8 +654,6 @@
}
}
-
-
/** The interface for calls from outside the host process. */
@BinderThread
private class IDesktopModeImpl(private var controller: DesktopTasksController?) :
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
index ccbb9cf..a3803ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
@@ -1,3 +1,4 @@
# WM shell sub-module freeform owners
[email protected]
[email protected]
[email protected]
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 24d0b99..f51eb52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -180,6 +180,35 @@
return null;
}
+
+ /**
+ * Returns the source hint rect if it is valid (if provided and is contained by the current
+ * task bounds, while not smaller than the destination bounds).
+ */
+ @Nullable
+ public static Rect getValidSourceHintRect(PictureInPictureParams params, Rect sourceBounds,
+ Rect destinationBounds) {
+ Rect sourceRectHint = getValidSourceHintRect(params, sourceBounds);
+ if (!isSourceRectHintValidForEnterPip(sourceRectHint, destinationBounds)) {
+ sourceRectHint = null;
+ }
+ return sourceRectHint;
+ }
+
+ /**
+ * This is a situation in which the source rect hint on at least one axis is smaller
+ * than the destination bounds, which represents a problem because we would have to scale
+ * up that axis to fit the bounds. So instead, just fallback to the non-source hint
+ * animation in this case.
+ *
+ * @return {@code false} if the given source is too small to use for the entering animation.
+ */
+ static boolean isSourceRectHintValidForEnterPip(Rect sourceRectHint, Rect destinationBounds) {
+ return sourceRectHint != null
+ && sourceRectHint.width() > destinationBounds.width()
+ && sourceRectHint.height() > destinationBounds.height();
+ }
+
public float getDefaultAspectRatio() {
return mDefaultAspectRatio;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 6cedcf5..363d675 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1657,8 +1657,8 @@
"%s: Abort animation, invalid leash", TAG);
return null;
}
- if (isInPipDirection(direction)
- && !isSourceRectHintValidForEnterPip(sourceHintRect, destinationBounds)) {
+ if (isInPipDirection(direction) && !PipBoundsAlgorithm
+ .isSourceRectHintValidForEnterPip(sourceHintRect, destinationBounds)) {
// The given source rect hint is too small for enter PiP animation, reset it to null.
sourceHintRect = null;
}
@@ -1757,20 +1757,6 @@
}
/**
- * This is a situation in which the source rect hint on at least one axis is smaller
- * than the destination bounds, which represents a problem because we would have to scale
- * up that axis to fit the bounds. So instead, just fallback to the non-source hint
- * animation in this case.
- *
- * @return {@code false} if the given source is too small to use for the entering animation.
- */
- private boolean isSourceRectHintValidForEnterPip(Rect sourceRectHint, Rect destinationBounds) {
- return sourceRectHint != null
- && sourceRectHint.width() > destinationBounds.width()
- && sourceRectHint.height() > destinationBounds.height();
- }
-
- /**
* Sync with {@link SplitScreenController} on destination bounds if PiP is going to
* split screen.
*
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 98db707..6b8108a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -764,7 +764,7 @@
final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
int rotationDelta = deltaRotation(startRotation, endRotation);
Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
- taskInfo.pictureInPictureParams, currentBounds);
+ taskInfo.pictureInPictureParams, currentBounds, destinationBounds);
if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
// Need to get the bounds of new rotation in old rotation for fixed rotation,
computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 5c2f1438..b8373f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1538,7 +1538,7 @@
}
void finishEnterSplitScreen(SurfaceControl.Transaction t) {
- mSplitLayout.init();
+ mSplitLayout.update(t);
setDividerVisibility(true, t);
// Ensure divider surface are re-parented back into the hierarchy at the end of the
// transition. See Transition#buildFinishTransaction for more detail.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 1ee52ae..dfad8b9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -24,6 +24,7 @@
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -329,6 +330,8 @@
@ColorInt int backgroundColorForTransition = 0;
final int wallpaperTransit = getWallpaperTransitType(info);
boolean isDisplayRotationAnimationStarted = false;
+ final boolean isDreamTransition = isDreamTransition(info);
+
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.hasAllFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY
@@ -424,7 +427,7 @@
// Don't animate anything that isn't independent.
if (!TransitionInfo.isIndependent(change, info)) continue;
- Animation a = loadAnimation(info, change, wallpaperTransit);
+ Animation a = loadAnimation(info, change, wallpaperTransit, isDreamTransition);
if (a != null) {
if (isTask) {
final @TransitionType int type = info.getType();
@@ -519,6 +522,18 @@
return true;
}
+ private static boolean isDreamTransition(@NonNull TransitionInfo info) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getTaskInfo() != null
+ && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@@ -572,7 +587,8 @@
@Nullable
private Animation loadAnimation(@NonNull TransitionInfo info,
- @NonNull TransitionInfo.Change change, int wallpaperTransit) {
+ @NonNull TransitionInfo.Change change, int wallpaperTransit,
+ boolean isDreamTransition) {
Animation a;
final int type = info.getType();
@@ -630,7 +646,8 @@
// If there's a scene-transition, then jump-cut.
return null;
} else {
- a = loadAttributeAnimation(info, change, wallpaperTransit, mTransitionAnimation);
+ a = loadAttributeAnimation(
+ info, change, wallpaperTransit, mTransitionAnimation, isDreamTransition);
}
if (a != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
index 0cede90..e27e4f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
@@ -28,7 +28,6 @@
import android.util.Log;
import com.android.internal.util.TraceBuffer;
-import com.android.wm.shell.nano.HandlerMapping;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.google.protobuf.nano.MessageNano;
@@ -41,6 +40,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
+import java.util.concurrent.TimeUnit;
/**
* Helper class to collect and dump transition traces.
@@ -241,6 +241,10 @@
new com.android.wm.shell.nano.WmShellTransitionTraceProto();
proto.magicNumber = MAGIC_NUMBER_VALUE;
writeHandlerMappingToProto(proto);
+ long timeOffsetNs =
+ TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())
+ - SystemClock.elapsedRealtimeNanos();
+ proto.realToElapsedTimeOffsetNanos = timeOffsetNs;
int pid = android.os.Process.myPid();
LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
+ " from process " + pid);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index 0f4645c..19d8384 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -18,7 +18,6 @@
import static android.app.ActivityOptions.ANIM_FROM_STYLE;
import static android.app.ActivityOptions.ANIM_NONE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -63,7 +62,7 @@
@Nullable
public static Animation loadAttributeAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, int wallpaperTransit,
- @NonNull TransitionAnimation transitionAnimation) {
+ @NonNull TransitionAnimation transitionAnimation, boolean isDreamTransition) {
final int type = info.getType();
final int changeMode = change.getMode();
final int changeFlags = change.getFlags();
@@ -71,11 +70,9 @@
final boolean isTask = change.getTaskInfo() != null;
final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
final int overrideType = options != null ? options.getType() : ANIM_NONE;
- final boolean isDream =
- isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
int animAttr = 0;
boolean translucent = false;
- if (isDream) {
+ if (isDreamTransition) {
if (type == TRANSIT_OPEN) {
animAttr = enter
? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
new file mode 100644
index 0000000..9b48a54
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.util
+
+import android.util.Log
+import com.android.internal.protolog.common.IProtoLogGroup
+import com.android.wm.shell.protolog.ShellProtoLogImpl
+
+/**
+ * Log messages using an API similar to [com.android.internal.protolog.common.ProtoLog]. Useful for
+ * logging from Kotlin classes as ProtoLog does not have support for Kotlin.
+ *
+ * All messages are logged to logcat if logging is enabled for that [IProtoLogGroup].
+ */
+// TODO(b/168581922): remove once ProtoLog adds support for Kotlin
+class KtProtoLog {
+ companion object {
+ /** @see [com.android.internal.protolog.common.ProtoLog.d] */
+ fun d(group: IProtoLogGroup, messageString: String, vararg args: Any) {
+ if (ShellProtoLogImpl.isEnabled(group)) {
+ Log.d(group.tag, String.format(messageString, *args))
+ }
+ }
+
+ /** @see [com.android.internal.protolog.common.ProtoLog.v] */
+ fun v(group: IProtoLogGroup, messageString: String, vararg args: Any) {
+ if (ShellProtoLogImpl.isEnabled(group)) {
+ Log.v(group.tag, String.format(messageString, *args))
+ }
+ }
+
+ /** @see [com.android.internal.protolog.common.ProtoLog.i] */
+ fun i(group: IProtoLogGroup, messageString: String, vararg args: Any) {
+ if (ShellProtoLogImpl.isEnabled(group)) {
+ Log.i(group.tag, String.format(messageString, *args))
+ }
+ }
+
+ /** @see [com.android.internal.protolog.common.ProtoLog.w] */
+ fun w(group: IProtoLogGroup, messageString: String, vararg args: Any) {
+ if (ShellProtoLogImpl.isEnabled(group)) {
+ Log.w(group.tag, String.format(messageString, *args))
+ }
+ }
+
+ /** @see [com.android.internal.protolog.common.ProtoLog.e] */
+ fun e(group: IProtoLogGroup, messageString: String, vararg args: Any) {
+ if (ShellProtoLogImpl.isEnabled(group)) {
+ Log.e(group.tag, String.format(messageString, *args))
+ }
+ }
+
+ /** @see [com.android.internal.protolog.common.ProtoLog.wtf] */
+ fun wtf(group: IProtoLogGroup, messageString: String, vararg args: Any) {
+ if (ShellProtoLogImpl.isEnabled(group)) {
+ Log.wtf(group.tag, String.format(messageString, *args))
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 64dfc3e..deebad5 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -8,3 +8,4 @@
[email protected]
[email protected]
[email protected]
[email protected]
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index 4de5298..55781f1b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -37,6 +37,7 @@
import android.app.ActivityManager;
import android.app.TaskInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.util.Pair;
@@ -455,12 +456,21 @@
verify(mLayout).setCameraCompatHintVisibility(/* show= */ true);
}
+ @Test
+ public void testWhenDockedStateHasChanged_needsToBeRecreated() {
+ ActivityManager.RunningTaskInfo newTaskInfo = new ActivityManager.RunningTaskInfo();
+ newTaskInfo.configuration.uiMode |= Configuration.UI_MODE_TYPE_DESK;
+
+ Assert.assertTrue(mWindowManager.needsToBeRecreated(newTaskInfo, mTaskListener));
+ }
+
private static TaskInfo createTaskInfo(boolean hasSizeCompat,
@TaskInfo.CameraCompatControlState int cameraCompatControlState) {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.taskId = TASK_ID;
taskInfo.topActivityInSizeCompat = hasSizeCompat;
taskInfo.cameraCompatControlState = cameraCompatControlState;
+ taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
return taskInfo;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
index 5bcc72e..973a99c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
@@ -21,6 +21,7 @@
import android.app.ActivityManager;
import android.app.TaskInfo;
+import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
@@ -31,6 +32,8 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,63 +49,61 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class ReachabilityEduWindowManagerTest extends ShellTestCase {
-
- private static final int USER_ID = 1;
- private static final int TASK_ID = 1;
-
@Mock
private SyncTransactionQueue mSyncTransactionQueue;
@Mock
private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock
- private CompatUIController.CompatUICallback mCallback;
- @Mock
private CompatUIConfiguration mCompatUIConfiguration;
@Mock
private DisplayLayout mDisplayLayout;
-
private TestShellExecutor mExecutor;
+ private TaskInfo mTaskInfo;
+ private ReachabilityEduWindowManager mWindowManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mExecutor = new TestShellExecutor();
+ mTaskInfo = new ActivityManager.RunningTaskInfo();
+ mTaskInfo.configuration.uiMode =
+ (mTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_NIGHT_MASK)
+ | Configuration.UI_MODE_NIGHT_NO;
+ mTaskInfo.configuration.uiMode =
+ (mTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_TYPE_MASK)
+ | Configuration.UI_MODE_TYPE_NORMAL;
+ mWindowManager = createReachabilityEduWindowManager(mTaskInfo);
}
@Test
public void testCreateLayout_notEligible_doesNotCreateLayout() {
- final ReachabilityEduWindowManager windowManager = createReachabilityEduWindowManager(
- createTaskInfo(/* userId= */ USER_ID, /*isLetterboxDoubleTapEnabled */ false));
+ assertFalse(mWindowManager.createLayout(/* canShow= */ true));
- assertFalse(windowManager.createLayout(/* canShow= */ true));
+ assertNull(mWindowManager.mLayout);
+ }
- assertNull(windowManager.mLayout);
+ @Test
+ public void testWhenDockedStateHasChanged_needsToBeRecreated() {
+ ActivityManager.RunningTaskInfo newTaskInfo = new ActivityManager.RunningTaskInfo();
+ newTaskInfo.configuration.uiMode =
+ (newTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_TYPE_MASK)
+ | Configuration.UI_MODE_TYPE_DESK;
+
+ Assert.assertTrue(mWindowManager.needsToBeRecreated(newTaskInfo, mTaskListener));
+ }
+
+ @Test
+ public void testWhenDarkLightThemeHasChanged_needsToBeRecreated() {
+ ActivityManager.RunningTaskInfo newTaskInfo = new ActivityManager.RunningTaskInfo();
+ mTaskInfo.configuration.uiMode =
+ (mTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_NIGHT_MASK)
+ | Configuration.UI_MODE_NIGHT_YES;
+
+ Assert.assertTrue(mWindowManager.needsToBeRecreated(newTaskInfo, mTaskListener));
}
private ReachabilityEduWindowManager createReachabilityEduWindowManager(TaskInfo taskInfo) {
return new ReachabilityEduWindowManager(mContext, taskInfo, mSyncTransactionQueue,
mTaskListener, mDisplayLayout, mCompatUIConfiguration, mExecutor);
}
-
- private static TaskInfo createTaskInfo(int userId, boolean isLetterboxDoubleTapEnabled) {
- return createTaskInfo(userId, /* isLetterboxDoubleTapEnabled */ isLetterboxDoubleTapEnabled,
- /* topActivityLetterboxVerticalPosition */ -1,
- /* topActivityLetterboxHorizontalPosition */ -1,
- /* topActivityLetterboxWidth */ -1,
- /* topActivityLetterboxHeight */ -1);
- }
-
- private static TaskInfo createTaskInfo(int userId, boolean isLetterboxDoubleTapEnabled,
- int topActivityLetterboxVerticalPosition, int topActivityLetterboxHorizontalPosition,
- int topActivityLetterboxWidth, int topActivityLetterboxHeight) {
- ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
- taskInfo.userId = userId;
- taskInfo.taskId = TASK_ID;
- taskInfo.isLetterboxDoubleTapEnabled = isLetterboxDoubleTapEnabled;
- taskInfo.topActivityLetterboxVerticalPosition = topActivityLetterboxVerticalPosition;
- taskInfo.topActivityLetterboxHorizontalPosition = topActivityLetterboxHorizontalPosition;
- taskInfo.topActivityLetterboxWidth = topActivityLetterboxWidth;
- taskInfo.topActivityLetterboxHeight = topActivityLetterboxHeight;
- return taskInfo;
- }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/RestartDialogWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/RestartDialogWindowManagerTest.java
new file mode 100644
index 0000000..9f109a1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/RestartDialogWindowManagerTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.content.res.Configuration;
+import android.testing.AndroidTestingRunner;
+import android.util.Pair;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Consumer;
+
+/**
+ * Tests for {@link RestartDialogWindowManager}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:RestartDialogWindowManagerTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class RestartDialogWindowManagerTest extends ShellTestCase {
+
+ @Mock
+ private SyncTransactionQueue mSyncTransactionQueue;
+ @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
+ @Mock private CompatUIConfiguration mCompatUIConfiguration;
+ @Mock private Transitions mTransitions;
+ @Mock private Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnRestartCallback;
+ @Mock private Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnDismissCallback;
+ private RestartDialogWindowManager mWindowManager;
+ private TaskInfo mTaskInfo;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTaskInfo = new ActivityManager.RunningTaskInfo();
+ mTaskInfo.configuration.uiMode =
+ (mTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_NIGHT_MASK)
+ | Configuration.UI_MODE_NIGHT_NO;
+ mTaskInfo.configuration.uiMode =
+ (mTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_TYPE_MASK)
+ | Configuration.UI_MODE_TYPE_NORMAL;
+ mWindowManager = new RestartDialogWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
+ mTaskListener, new DisplayLayout(), mTransitions, mOnRestartCallback,
+ mOnDismissCallback, mCompatUIConfiguration);
+ }
+
+ @Test
+ public void testWhenDockedStateHasChanged_needsToBeRecreated() {
+ ActivityManager.RunningTaskInfo newTaskInfo = new ActivityManager.RunningTaskInfo();
+ newTaskInfo.configuration.uiMode =
+ (newTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_TYPE_MASK)
+ | Configuration.UI_MODE_TYPE_DESK;
+
+ Assert.assertTrue(mWindowManager.needsToBeRecreated(newTaskInfo, mTaskListener));
+ }
+
+ @Test
+ public void testWhenDarkLightThemeHasChanged_needsToBeRecreated() {
+ ActivityManager.RunningTaskInfo newTaskInfo = new ActivityManager.RunningTaskInfo();
+ mTaskInfo.configuration.uiMode =
+ (mTaskInfo.configuration.uiMode & ~Configuration.UI_MODE_NIGHT_MASK)
+ | Configuration.UI_MODE_NIGHT_YES;
+
+ Assert.assertTrue(mWindowManager.needsToBeRecreated(newTaskInfo, mTaskListener));
+ }
+}
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 88e3519..e21d6fb 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -45,14 +45,13 @@
// --- PointerController::DisplayInfoListener ---
void PointerController::DisplayInfoListener::onWindowInfosChanged(
- const std::vector<android::gui::WindowInfo>&,
- const std::vector<android::gui::DisplayInfo>& displayInfos) {
+ const gui::WindowInfosUpdate& update) {
std::scoped_lock lock(mLock);
if (mPointerController == nullptr) return;
// PointerController uses DisplayInfoListener's lock.
base::ScopedLockAssertion assumeLocked(mPointerController->getLock());
- mPointerController->onDisplayInfosChangedLocked(displayInfos);
+ mPointerController->onDisplayInfosChangedLocked(update.displayInfos);
}
void PointerController::DisplayInfoListener::onPointerControllerDestroyed() {
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index ca14b6e..62ee7433 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -19,6 +19,7 @@
#include <PointerControllerInterface.h>
#include <gui/DisplayEventReceiver.h>
+#include <gui/WindowInfosUpdate.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <utils/BitSet.h>
@@ -114,8 +115,7 @@
class DisplayInfoListener : public gui::WindowInfosListener {
public:
explicit DisplayInfoListener(PointerController* pc) : mPointerController(pc){};
- void onWindowInfosChanged(const std::vector<android::gui::WindowInfo>&,
- const std::vector<android::gui::DisplayInfo>&) override;
+ void onWindowInfosChanged(const gui::WindowInfosUpdate&) override;
void onPointerControllerDestroyed();
// This lock is also used by PointerController. See PointerController::getLock().
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 2378d42..8574751 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -343,7 +343,7 @@
localListenerCopy = registeredListener;
}
EXPECT_EQ(nullptr, registeredListener) << "WindowInfosListener was not unregistered";
- localListenerCopy->onWindowInfosChanged({}, {});
+ localListenerCopy->onWindowInfosChanged({{}, {}, 0, 0});
}
} // namespace android
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
index 531b3ae..bc6a259 100644
--- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
@@ -80,14 +80,16 @@
* This implies that the caller must clear its caller identity to protect from the case where
* it resides in the same process as the callee.
* - The identity of the entity on behalf of which module operations are to be performed.
- *
+ * @param isTrusted - {@code true} if the middleware should not audit data delivery, since the
+ * callback is being delivered to another trusted component which will audit access.
* listModules() must be called prior to calling this method and the provided handle must be
* one of the handles from the returned list.
*/
ISoundTriggerModule attachAsMiddleman(int handle,
in Identity middlemanIdentity,
in Identity originatorIdentity,
- ISoundTriggerCallback callback);
+ ISoundTriggerCallback callback,
+ boolean isTrusted);
/**
* Attach an injection interface interface to the ST mock HAL.
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 0289aa3..3394dd0 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -203,10 +203,16 @@
AudioProductStrategy thatStrategy = (AudioProductStrategy) o;
- return mName == thatStrategy.mName && mId == thatStrategy.mId
+ return mId == thatStrategy.mId
+ && Objects.equals(mName, thatStrategy.mName)
&& Arrays.equals(mAudioAttributesGroups, thatStrategy.mAudioAttributesGroups);
}
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mName, Arrays.hashCode(mAudioAttributesGroups));
+ }
+
/**
* @param name of the product strategy
* @param id of the product strategy
@@ -460,6 +466,12 @@
&& Arrays.equals(mAudioAttributes, thatAag.mAudioAttributes);
}
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVolumeGroupId, mLegacyStreamType,
+ Arrays.hashCode(mAudioAttributes));
+ }
+
public int getStreamType() {
return mLegacyStreamType;
}
diff --git a/media/java/android/media/tv/AdBuffer.java b/media/java/android/media/tv/AdBuffer.java
index 230d763..f2b772f 100644
--- a/media/java/android/media/tv/AdBuffer.java
+++ b/media/java/android/media/tv/AdBuffer.java
@@ -22,6 +22,8 @@
import android.os.Parcelable;
import android.os.SharedMemory;
+import java.io.IOException;
+
/**
* Buffer for advertisement data.
*/
@@ -57,6 +59,16 @@
this.mFlags = flags;
}
+ /** @hide **/
+ public static AdBuffer dupAdBuffer(AdBuffer buffer) throws IOException {
+ if (buffer == null) {
+ return null;
+ }
+ return new AdBuffer(buffer.mId, buffer.mMimeType,
+ SharedMemory.fromFileDescriptor(buffer.mBuffer.getFdDup()), buffer.mOffset,
+ buffer.mLength, buffer.mPresentationTimeUs, buffer.mFlags);
+ }
+
/**
* Gets corresponding AD request ID.
*
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
index d8cddfc..5f6b2b5 100644
--- a/media/java/android/media/tv/AdRequest.java
+++ b/media/java/android/media/tv/AdRequest.java
@@ -72,6 +72,22 @@
private final Bundle mMetadata;
private final Uri mUri;
+ /**
+ * The key for video metadata.
+ *
+ * @see #getMetadata()
+ * @hide
+ */
+ public static final String KEY_VIDEO_METADATA = "key_video_metadata";
+
+ /**
+ * The key for audio metadata.
+ *
+ * @see #getMetadata()
+ * @hide
+ */
+ public static final String KEY_AUDIO_METADATA = "key_audio_metadata";
+
public AdRequest(int id, @RequestType int requestType,
@Nullable ParcelFileDescriptor fileDescriptor, long startTime, long stopTime,
long echoInterval, @Nullable String mediaFileType, @NonNull Bundle metadata) {
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f344fd3..631ab9a 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -3737,6 +3737,10 @@
mService.notifyAdBufferReady(mToken, buffer, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } finally {
+ if (buffer != null) {
+ buffer.getSharedMemory().close();
+ }
}
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 06d1acd..7cce84a 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -1608,6 +1608,10 @@
mService.notifyAdBufferConsumed(mToken, buffer, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } finally {
+ if (buffer != null) {
+ buffer.getSharedMemory().close();
+ }
}
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 06dfe4f..ec85cc7 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -69,6 +69,7 @@
import com.android.internal.os.SomeArgs;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -1973,9 +1974,9 @@
"notifyAdBufferReady(buffer=" + buffer + ")");
}
if (mSessionCallback != null) {
- mSessionCallback.onAdBufferReady(buffer);
+ mSessionCallback.onAdBufferReady(AdBuffer.dupAdBuffer(buffer));
}
- } catch (RemoteException e) {
+ } catch (RemoteException | IOException e) {
Log.w(TAG, "error in notifyAdBuffer", e);
}
}
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java
index b66545a..266faae 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java
@@ -29,11 +29,14 @@
import android.media.AudioSystem;
import android.media.audiopolicy.AudioProductStrategy;
import android.media.audiopolicy.AudioVolumeGroup;
+import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.common.testing.EqualsTester;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -231,4 +234,26 @@
}
}
}
+
+ @Test
+ public void testEquals() {
+ final EqualsTester equalsTester = new EqualsTester();
+
+ AudioProductStrategy.getAudioProductStrategies().forEach(
+ strategy -> equalsTester.addEqualityGroup(strategy,
+ writeToAndFromParcel(strategy)));
+
+ equalsTester.testEquals();
+ }
+
+ private static AudioProductStrategy writeToAndFromParcel(
+ AudioProductStrategy audioProductStrategy) {
+ Parcel parcel = Parcel.obtain();
+ audioProductStrategy.writeToParcel(parcel, /*flags=*/0);
+ parcel.setDataPosition(0);
+ AudioProductStrategy unmarshalledAudioProductStrategy =
+ AudioProductStrategy.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ return unmarshalledAudioProductStrategy;
+ }
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index a35310c..b81339e8 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -213,7 +213,7 @@
}
}
return com.android.credentialmanager.getflow.RequestDisplayInfo(
- appName = originName
+ appName = originName?.ifEmpty { null }
?: getAppLabel(context.packageManager, requestInfo.appPackageName)
?: return null,
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
@@ -286,7 +286,8 @@
pendingIntent = credentialEntry.pendingIntent,
fillInIntent = it.frameworkExtrasIntent,
credentialType = CredentialType.UNKNOWN,
- credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
+ credentialTypeDisplayName =
+ credentialEntry.typeDisplayName?.toString().orEmpty(),
userName = credentialEntry.title.toString(),
displayName = credentialEntry.subtitle?.toString(),
icon = credentialEntry.icon.loadDrawable(context),
@@ -461,7 +462,7 @@
if (requestInfo == null) {
return null
}
- val appLabel = originName
+ val appLabel = originName?.ifEmpty { null }
?: getAppLabel(context.packageManager, requestInfo.appPackageName)
?: return null
val createCredentialRequest = requestInfo.createCredentialRequest ?: return null
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index d16120f..a258984 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -436,7 +436,8 @@
},
)
}
- if (createOptionInfo.footerDescription != null) {
+ val footerDescription = createOptionInfo.footerDescription
+ if (footerDescription != null && footerDescription.length > 0) {
item {
Divider(
thickness = 1.dp,
@@ -446,7 +447,7 @@
}
item {
Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
- BodySmallText(text = createOptionInfo.footerDescription)
+ BodySmallText(text = footerDescription)
}
}
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index e9000a8..df43863 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -27,6 +27,7 @@
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
+ "com.android.devicelock",
"com.android.extservices",
"com.android.permission",
"com.android.healthfitness",
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index d26ad1c..e6fb720 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -16,6 +16,7 @@
apex_available: [
"//apex_available:platform",
"com.android.cellbroadcast",
+ "com.android.devicelock",
"com.android.extservices",
"com.android.permission",
"com.android.adservices",
diff --git a/packages/SettingsLib/SettingsTransition/Android.bp b/packages/SettingsLib/SettingsTransition/Android.bp
index 0f9f781..48cc75d 100644
--- a/packages/SettingsLib/SettingsTransition/Android.bp
+++ b/packages/SettingsLib/SettingsTransition/Android.bp
@@ -22,6 +22,7 @@
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
+ "com.android.devicelock",
"com.android.extservices",
"com.android.permission",
"com.android.healthfitness",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
index 621e6ea..0f5862a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
@@ -20,6 +20,7 @@
import android.content.Intent
import android.os.Bundle
+import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.VisibleForTesting
@@ -40,6 +41,7 @@
import com.android.settingslib.spa.R
import com.android.settingslib.spa.framework.common.LogCategory
import com.android.settingslib.spa.framework.common.NullPageProvider
+import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
@@ -51,7 +53,7 @@
import com.android.settingslib.spa.framework.compose.localNavController
import com.android.settingslib.spa.framework.compose.rememberAnimatedNavController
import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.framework.util.PageWithEvent
+import com.android.settingslib.spa.framework.util.PageLogger
import com.android.settingslib.spa.framework.util.getDestination
import com.android.settingslib.spa.framework.util.getEntryId
import com.android.settingslib.spa.framework.util.getSessionName
@@ -87,25 +89,50 @@
setContent {
SettingsTheme {
val sppRepository by spaEnvironment.pageProviderRepository
- BrowseContent(sppRepository, intent)
+ BrowseContent(
+ sppRepository = sppRepository,
+ isPageEnabled = ::isPageEnabled,
+ initialIntent = intent,
+ )
}
}
}
+
+ open fun isPageEnabled(page: SettingsPage) = page.isEnabled()
}
@VisibleForTesting
@Composable
-fun BrowseContent(sppRepository: SettingsPageProviderRepository, initialIntent: Intent? = null) {
+internal fun BrowseContent(
+ sppRepository: SettingsPageProviderRepository,
+ isPageEnabled: (SettingsPage) -> Boolean,
+ initialIntent: Intent?,
+) {
val navController = rememberAnimatedNavController()
CompositionLocalProvider(navController.localNavController()) {
val controller = LocalNavController.current as NavControllerWrapperImpl
- controller.NavContent(sppRepository.getAllProviders())
+ controller.NavContent(sppRepository.getAllProviders()) { page ->
+ if (remember { isPageEnabled(page) }) {
+ LaunchedEffect(Unit) {
+ Log.d(TAG, "Launching page ${page.sppName}")
+ }
+ page.PageLogger()
+ page.UiLayout()
+ } else {
+ LaunchedEffect(Unit) {
+ controller.navigateBack()
+ }
+ }
+ }
controller.InitialDestination(initialIntent, sppRepository.getDefaultStartPage())
}
}
@Composable
-private fun NavControllerWrapperImpl.NavContent(allProvider: Collection<SettingsPageProvider>) {
+private fun NavControllerWrapperImpl.NavContent(
+ allProvider: Collection<SettingsPageProvider>,
+ content: @Composable (SettingsPage) -> Unit,
+) {
AnimatedNavHost(
navController = navController,
startDestination = NullPageProvider.name,
@@ -139,7 +166,7 @@
},
) { navBackStackEntry ->
val page = remember { spp.createSettingsPage(navBackStackEntry.arguments) }
- page.PageWithEvent()
+ content(page)
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
index dde4e04..a9e5e39 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
@@ -29,14 +29,12 @@
import com.android.settingslib.spa.framework.compose.NavControllerWrapper
@Composable
-internal fun SettingsPage.PageWithEvent() {
- if (!isEnabled()) return
+internal fun SettingsPage.PageLogger() {
val navController = LocalNavController.current
LifecycleEffect(
onStart = { logPageEvent(LogEvent.PAGE_ENTER, navController) },
onStop = { logPageEvent(LogEvent.PAGE_LEAVE, navController) },
)
- UiLayout()
}
private fun SettingsPage.logPageEvent(event: LogEvent, navController: NavControllerWrapper) {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
index 218f569..92d3411 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
@@ -26,6 +26,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.common.LogCategory
import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
@@ -38,8 +39,6 @@
import org.junit.Test
import org.junit.runner.RunWith
-const val WAIT_UNTIL_TIMEOUT = 1000L
-
@RunWith(AndroidJUnit4::class)
class BrowseActivityTest {
@get:Rule
@@ -49,19 +48,26 @@
private val spaLogger = SpaLoggerForTest()
@Test
- fun testBrowsePage() {
- spaLogger.reset()
- val spaEnvironment =
- SpaEnvironmentForTest(context, listOf(SppHome.createSettingsPage()), logger = spaLogger)
+ fun browseContent_onNavigate_logPageEvent() {
+ val spaEnvironment = SpaEnvironmentForTest(
+ context = context,
+ rootPages = listOf(SppHome.createSettingsPage()),
+ logger = spaLogger,
+ )
SpaEnvironmentFactory.reset(spaEnvironment)
-
val sppRepository by spaEnvironment.pageProviderRepository
val sppHome = sppRepository.getProviderOrNull("SppHome")!!
val pageHome = sppHome.createSettingsPage()
val sppLayer1 = sppRepository.getProviderOrNull("SppLayer1")!!
val pageLayer1 = sppLayer1.createSettingsPage()
- composeTestRule.setContent { BrowseContent(sppRepository) }
+ composeTestRule.setContent {
+ BrowseContent(
+ sppRepository = sppRepository,
+ isPageEnabled = SettingsPage::isEnabled,
+ initialIntent = null,
+ )
+ }
composeTestRule.onNodeWithText(sppHome.getTitle(null)).assertIsDisplayed()
spaLogger.verifyPageEvent(pageHome.id, 1, 0)
@@ -69,7 +75,7 @@
// click to layer1 page
composeTestRule.onNodeWithText("SppHome to Layer1").assertIsDisplayed().performClick()
- waitUntil(WAIT_UNTIL_TIMEOUT) {
+ waitUntil {
composeTestRule.onAllNodesWithText(sppLayer1.getTitle(null))
.fetchSemanticsNodes().size == 1
}
@@ -78,18 +84,24 @@
}
@Test
- fun testBrowseDisabledPage() {
- spaLogger.reset()
+ fun browseContent_whenDisabled_noLogPageEvent() {
val spaEnvironment = SpaEnvironmentForTest(
- context, listOf(SppDisabled.createSettingsPage()), logger = spaLogger
+ context = context,
+ rootPages = listOf(SppDisabled.createSettingsPage()),
+ logger = spaLogger,
)
SpaEnvironmentFactory.reset(spaEnvironment)
-
val sppRepository by spaEnvironment.pageProviderRepository
val sppDisabled = sppRepository.getProviderOrNull("SppDisabled")!!
val pageDisabled = sppDisabled.createSettingsPage()
- composeTestRule.setContent { BrowseContent(sppRepository) }
+ composeTestRule.setContent {
+ BrowseContent(
+ sppRepository = sppRepository,
+ isPageEnabled = SettingsPage::isEnabled,
+ initialIntent = null,
+ )
+ }
composeTestRule.onNodeWithText(sppDisabled.getTitle(null)).assertDoesNotExist()
spaLogger.verifyPageEvent(pageDisabled.id, 0, 0)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
index 338b16d..e9da88e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -46,7 +46,7 @@
) : AppRecord
abstract class AppOpPermissionListModel(
- private val context: Context,
+ protected val context: Context,
private val packageManagers: IPackageManagers = PackageManagers,
) : TogglePermissionAppListModel<AppOpPermissionRecord> {
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index eca1165..5d09a1a 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -23,6 +23,7 @@
apex_available: [
"//apex_available:platform",
"com.android.cellbroadcast",
+ "com.android.devicelock",
"com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp
index 33ba64a..dc2b52d 100644
--- a/packages/SettingsLib/Utils/Android.bp
+++ b/packages/SettingsLib/Utils/Android.bp
@@ -25,6 +25,7 @@
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
+ "com.android.devicelock",
"com.android.extservices",
"com.android.healthfitness",
"com.android.permission",
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index e9aded0..2372c80 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -67,6 +67,8 @@
<!-- SignalDrawable -->
<dimen name="signal_icon_size">15dp</dimen>
+ <!-- The size of the roaming icon in the top-left corner of the signal icon. -->
+ <dimen name="signal_icon_size_roaming">8dp</dimen>
<!-- Size of nearby icon -->
<dimen name="bt_nearby_icon_size">24dp</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 214c903..4e75792 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -244,7 +244,7 @@
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. -->
<string name="bluetooth_profile_hearing_aid">Hearing Aids</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the LE audio profile. -->
- <string name="bluetooth_profile_le_audio">LE audio</string>
+ <string name="bluetooth_profile_le_audio">LE audio (experimental)</string>
<!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. -->
<string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aids</string>
<!-- Bluetooth settings. Connection options screen. The summary for the LE audio checkbox preference when LE audio is connected. -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index adaf4a1..c45d774 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -343,7 +343,12 @@
}
@Nullable
- private WifiInfo getMainOrUnderlyingWifiInfo(NetworkCapabilities networkCapabilities) {
+ private WifiInfo getMainOrUnderlyingWifiInfo(
+ @Nullable NetworkCapabilities networkCapabilities) {
+ if (networkCapabilities == null) {
+ return null;
+ }
+
WifiInfo mainWifiInfo = getMainWifiInfo(networkCapabilities);
if (mainWifiInfo != null) {
return mainWifiInfo;
@@ -376,7 +381,10 @@
}
@Nullable
- private WifiInfo getMainWifiInfo(NetworkCapabilities networkCapabilities) {
+ private WifiInfo getMainWifiInfo(@Nullable NetworkCapabilities networkCapabilities) {
+ if (networkCapabilities == null) {
+ return null;
+ }
boolean canHaveWifiInfo = networkCapabilities.hasTransport(TRANSPORT_WIFI)
|| networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
if (!canHaveWifiInfo) {
@@ -402,7 +410,11 @@
getMainOrUnderlyingWifiInfo(networkCapabilities));
}
- private boolean connectionIsWifi(NetworkCapabilities networkCapabilities, WifiInfo wifiInfo) {
+ private boolean connectionIsWifi(
+ @Nullable NetworkCapabilities networkCapabilities, WifiInfo wifiInfo) {
+ if (networkCapabilities == null) {
+ return false;
+ }
return wifiInfo != null || networkCapabilities.hasTransport(TRANSPORT_WIFI);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
index 6e975cf..5a9a9d1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
@@ -305,4 +305,16 @@
assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue();
}
+
+ /** Regression test for b/280169520. */
+ @Test
+ public void networkCallbackNullCapabilities_noCrash() {
+ Network primaryNetwork = Mockito.mock(Network.class);
+
+ // WHEN the network capabilities are null
+ mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(
+ primaryNetwork, /* networkCapabilities= */ null);
+
+ // THEN there's no crash (no assert needed)
+ }
}
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
index 29832a0..f050a1e 100644
--- a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
@@ -78,6 +78,7 @@
android:id="@+id/mobile_roaming"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="top|start"
android:src="@drawable/stat_sys_roaming"
android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
diff --git a/packages/SystemUI/res/drawable/action_chip_background.xml b/packages/SystemUI/res/drawable/action_chip_background.xml
index 745470f..9492472 100644
--- a/packages/SystemUI/res/drawable/action_chip_background.xml
+++ b/packages/SystemUI/res/drawable/action_chip_background.xml
@@ -20,7 +20,7 @@
android:color="@color/overlay_button_ripple">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentSecondary"/>
+ <solid android:color="?androidprv:attr/materialColorSecondary"/>
<corners android:radius="@dimen/overlay_button_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/action_chip_container_background.xml b/packages/SystemUI/res/drawable/action_chip_container_background.xml
index 36083f1..2ee2710 100644
--- a/packages/SystemUI/res/drawable/action_chip_container_background.xml
+++ b/packages/SystemUI/res/drawable/action_chip_container_background.xml
@@ -18,6 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceBright"/>
<corners android:radius="@dimen/overlay_action_container_corner_radius"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/overlay_cancel.xml b/packages/SystemUI/res/drawable/circular_background.xml
similarity index 62%
rename from packages/SystemUI/res/drawable/overlay_cancel.xml
rename to packages/SystemUI/res/drawable/circular_background.xml
index 3fa12dd..4fef0d6 100644
--- a/packages/SystemUI/res/drawable/overlay_cancel.xml
+++ b/packages/SystemUI/res/drawable/circular_background.xml
@@ -16,14 +16,11 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="?androidprv:attr/colorAccentTertiary"
- android:pathData="M16,16m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"/>
- <path
- android:fillColor="?attr/overlayButtonTextColor"
- android:pathData="M23,10.41L21.59,9 16,14.59 10.41,9 9,10.41 14.59,16 9,21.59 10.41,23 16,17.41 21.59,23 23,21.59 17.41,16z"/>
-</vector>
+ android:fillColor="#ff000000"
+ android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"/>
+ </vector>
diff --git a/packages/SystemUI/res/drawable/overlay_border.xml b/packages/SystemUI/res/drawable/overlay_border.xml
index c1accdc..a59f923 100644
--- a/packages/SystemUI/res/drawable/overlay_border.xml
+++ b/packages/SystemUI/res/drawable/overlay_border.xml
@@ -18,6 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
- <corners android:radius="24dp"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceBright"/>
+ <corners android:radius="16dp"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/overlay_button_background.xml b/packages/SystemUI/res/drawable/overlay_button_background.xml
index c045048..4e5b8fb 100644
--- a/packages/SystemUI/res/drawable/overlay_button_background.xml
+++ b/packages/SystemUI/res/drawable/overlay_button_background.xml
@@ -17,12 +17,11 @@
<!-- Button background for activities downstream of overlays
(clipboard text editor, long screenshots) -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:color="@color/overlay_button_ripple">
<item android:id="@android:id/background">
<inset android:insetTop="4dp" android:insetBottom="4dp">
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ <solid android:color="#fff"/>
<corners android:radius="20dp"/>
<size android:height="40dp"/>
</shape>
@@ -31,7 +30,7 @@
<item android:id="@android:id/mask">
<inset android:insetTop="4dp" android:insetBottom="4dp">
<shape android:shape="rectangle">
- <solid android:color="?android:textColorPrimary"/>
+ <solid android:color="#000"/>
<corners android:radius="20dp"/>
<size android:height="40dp"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/overlay_button_outline.xml b/packages/SystemUI/res/drawable/overlay_button_outline.xml
new file mode 100644
index 0000000..4d91503
--- /dev/null
+++ b/packages/SystemUI/res/drawable/overlay_button_outline.xml
@@ -0,0 +1,40 @@
+<?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.
+ -->
+<!-- Button background for activities downstream of overlays
+ (clipboard text editor, long screenshots) -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/overlay_button_ripple">
+ <item android:id="@android:id/background">
+ <inset android:insetTop="4dp" android:insetBottom="4dp">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/transparent" />
+ <stroke android:width="1dp" android:color="#fff"/>
+ <corners android:radius="20dp"/>
+ <size android:height="40dp"/>
+ </shape>
+ </inset>
+ </item>
+ <item android:id="@android:id/mask">
+ <inset android:insetTop="4dp" android:insetBottom="4dp">
+ <shape android:shape="rectangle">
+ <solid android:color="#000"/>
+ <corners android:radius="20dp"/>
+ <size android:height="40dp"/>
+ </shape>
+ </inset>
+ </item>
+</ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/overlay_preview_background.xml b/packages/SystemUI/res/drawable/overlay_preview_background.xml
index 5adfaa13..d39d71e 100644
--- a/packages/SystemUI/res/drawable/overlay_preview_background.xml
+++ b/packages/SystemUI/res/drawable/overlay_preview_background.xml
@@ -17,5 +17,6 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <corners android:radius="20dp"/>
+ <!-- preview radius should be equal to [overlay border radius - overlay border width] -->
+ <corners android:radius="12dp"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/screenshot_edit_background.xml b/packages/SystemUI/res/drawable/screenshot_edit_background.xml
index a1185a2..07e5aff 100644
--- a/packages/SystemUI/res/drawable/screenshot_edit_background.xml
+++ b/packages/SystemUI/res/drawable/screenshot_edit_background.xml
@@ -20,13 +20,7 @@
android:color="@color/overlay_button_ripple">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentPrimary"/>
- <corners android:radius="16dp"/>
- </shape>
- </item>
- <item android:id="@android:id/mask">
- <shape android:shape="rectangle">
- <solid android:color="?android:textColorPrimary"/>
+ <solid android:color="?androidprv:attr/materialColorSecondaryFixedDim"/>
<corners android:radius="16dp"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/stat_sys_roaming.xml b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
index 0dd9f5a..2dd12ca 100644
--- a/packages/SystemUI/res/drawable/stat_sys_roaming.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
@@ -14,10 +14,10 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/signal_icon_size"
- android:height="@dimen/signal_icon_size"
- android:viewportWidth="17"
- android:viewportHeight="17">
+ android:width="@dimen/signal_icon_size_roaming"
+ android:height="@dimen/signal_icon_size_roaming"
+ android:viewportWidth="8"
+ android:viewportHeight="8">
<path
android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml
index 5155b77..2459eea 100644
--- a/packages/SystemUI/res/layout/app_clips_screenshot.xml
+++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml
@@ -87,19 +87,4 @@
tools:background="?android:colorBackground"
tools:minHeight="100dp"
tools:minWidth="100dp" />
-
- <com.android.systemui.screenshot.MagnifierView
- android:id="@+id/magnifier"
- android:visibility="invisible"
- android:layout_width="200dp"
- android:layout_height="200dp"
- android:elevation="2dp"
- app:layout_constraintTop_toTopOf="@id/preview"
- app:layout_constraintLeft_toLeftOf="parent"
- app:handleThickness="@dimen/screenshot_crop_handle_thickness"
- app:handleColor="?android:attr/colorAccent"
- app:scrimColor="?android:colorBackgroundFloating"
- app:scrimAlpha="128"
- app:borderThickness="4dp"
- app:borderColor="#fff" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
index cb7f40f..ae24313 100644
--- a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
+++ b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -15,6 +16,8 @@
android:paddingHorizontal="16dp"
android:background="@drawable/overlay_button_background"
android:text="@string/clipboard_edit_text_done"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnPrimary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 297cf2b..2500769 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -179,6 +179,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/overlay_dismiss_button_margin"
- android:src="@drawable/overlay_cancel"/>
+ android:background="@drawable/circular_background"
+ android:backgroundTint="?androidprv:attr/materialColorPrimaryFixedDim"
+ android:tint="?androidprv:attr/materialColorOnPrimaryFixed"
+ android:padding="4dp"
+ android:src="@drawable/ic_close"/>
</FrameLayout>
</com.android.systemui.clipboardoverlay.ClipboardOverlayView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 2927d6b..8a19c2e 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -16,9 +16,9 @@
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:background="?android:colorBackgroundFloating"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -32,7 +32,8 @@
android:layout_marginStart="8dp"
android:layout_marginTop="@dimen/long_screenshot_action_bar_top_margin"
android:background="@drawable/overlay_button_background"
- android:textColor="?android:textColorSecondary"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnPrimary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/preview" />
@@ -45,8 +46,9 @@
android:text="@android:string/cancel"
android:layout_marginStart="6dp"
android:layout_marginTop="@dimen/long_screenshot_action_bar_top_margin"
- android:background="@drawable/overlay_button_background"
- android:textColor="?android:textColorSecondary"
+ android:background="@drawable/overlay_button_outline"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
app:layout_constraintStart_toEndOf="@id/save"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/preview"
@@ -55,7 +57,7 @@
<ImageButton
android:id="@+id/share"
style="@android:style/Widget.Material.Button.Borderless"
- android:tint="?android:textColorPrimary"
+ android:tint="?androidprv:attr/materialColorOnSurface"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="8dp"
@@ -112,10 +114,10 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:handleThickness="@dimen/screenshot_crop_handle_thickness"
- app:handleColor="?android:attr/colorAccent"
- app:scrimColor="?android:colorBackgroundFloating"
+ app:handleColor="?androidprv:attr/materialColorSecondary"
+ app:scrimColor="?androidprv:attr/materialColorSurfaceContainer"
app:scrimAlpha="128"
- app:containerBackgroundColor="?android:colorBackgroundFloating"
+ app:containerBackgroundColor="?androidprv:attr/materialColorSurfaceContainer"
tools:background="?android:colorBackground"
tools:minHeight="100dp"
tools:minWidth="100dp" />
@@ -129,12 +131,11 @@
app:layout_constraintTop_toTopOf="@id/preview"
app:layout_constraintLeft_toLeftOf="parent"
app:handleThickness="@dimen/screenshot_crop_handle_thickness"
- app:handleColor="?android:attr/colorAccent"
- app:scrimColor="?android:colorBackgroundFloating"
+ app:handleColor="?androidprv:attr/materialColorSecondary"
+ app:scrimColor="?androidprv:attr/materialColorSurfaceContainer"
app:scrimAlpha="128"
app:borderThickness="4dp"
- app:borderColor="#fff"
- />
+ app:borderColor="?androidprv:attr/materialColorSurfaceBright" />
<ImageButton
android:id="@+id/edit"
@@ -146,12 +147,11 @@
android:background="@drawable/screenshot_edit_background"
android:src="@drawable/ic_screenshot_edit"
android:contentDescription="@string/screenshot_edit_label"
- android:tint="?android:textColorSecondary"
+ android:tint="?androidprv:attr/materialColorOnSecondaryFixed"
android:padding="16dp"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- />
+ app:layout_constraintEnd_toEndOf="parent"/>
<ImageView
android:id="@+id/transition"
@@ -160,7 +160,6 @@
app:layout_constraintTop_toTopOf="@id/preview"
app:layout_constraintLeft_toLeftOf="parent"
android:scaleType="centerCrop"
- android:visibility="invisible"
- />
+ android:visibility="invisible" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/media_session_end_dialog.xml b/packages/SystemUI/res/layout/media_session_end_dialog.xml
new file mode 100644
index 0000000..e1050f6
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_session_end_dialog.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/end_session_dialog"
+ android:layout_width="@dimen/large_dialog_width"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/Widget.SliceView.Panel"
+ android:gravity="center_vertical|center_horizontal"
+ android:layout_marginTop="@dimen/dialog_top_padding"
+ android:layout_marginBottom="@dimen/dialog_bottom_padding"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/end_icon"
+ android:gravity="center_vertical|center_horizontal"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:importantForAccessibility="no"/>
+
+ <TextView
+ android:id="@+id/end_session_dialog_title"
+ android:text="@string/media_output_end_session_dialog_summary"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="@dimen/dialog_side_padding"
+ android:layout_marginStart="@dimen/dialog_side_padding"
+ android:layout_marginEnd="@dimen/dialog_bottom_padding"
+ android:ellipsize="end"
+ android:gravity="center_vertical|center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textSize="24sp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end|center_vertical"
+ android:layout_marginTop="8dp"
+ android:layout_marginStart="@dimen/dialog_side_padding"
+ android:layout_marginEnd="@dimen/dialog_side_padding"
+ android:layout_marginBottom="@dimen/dialog_bottom_padding"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/cancel_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:text="@string/cancel"
+ android:ellipsize="end"
+ android:layout_gravity="end|center_vertical"
+ android:singleLine="true"
+ style="@style/Widget.Dialog.Button.BorderButton"
+ android:clickable="true"
+ android:focusable="true"/>
+ <Button
+ android:id="@+id/stop_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:text="@string/media_output_end_session_dialog_stop"
+ style="@style/Widget.Dialog.Button"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:clickable="true"
+ android:focusable="true"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/overlay_action_chip.xml b/packages/SystemUI/res/layout/overlay_action_chip.xml
index e0c20ff..e7c382f 100644
--- a/packages/SystemUI/res/layout/overlay_action_chip.xml
+++ b/packages/SystemUI/res/layout/overlay_action_chip.xml
@@ -16,12 +16,12 @@
-->
<com.android.systemui.screenshot.OverlayActionChip
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/overlay_action_chip"
android:theme="@style/FloatingOverlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/overlay_action_chip_margin_start"
- android:paddingVertical="@dimen/overlay_action_chip_margin_vertical"
android:layout_gravity="center"
android:gravity="center"
android:alpha="0.0">
@@ -33,7 +33,7 @@
android:gravity="center">
<ImageView
android:id="@+id/overlay_action_chip_icon"
- android:tint="?attr/overlayButtonTextColor"
+ android:tint="?androidprv:attr/materialColorOnSecondary"
android:layout_width="@dimen/overlay_action_chip_icon_size"
android:layout_height="@dimen/overlay_action_chip_icon_size"/>
<TextView
@@ -42,6 +42,6 @@
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="@dimen/overlay_action_chip_text_size"
- android:textColor="?attr/overlayButtonTextColor"/>
+ android:textColor="?androidprv:attr/materialColorOnSecondary"/>
</LinearLayout>
</com.android.systemui.screenshot.OverlayActionChip>
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index 7e9202c..3b728a9 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -16,6 +16,7 @@
-->
<com.android.systemui.screenshot.DraggableConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -68,7 +69,7 @@
android:layout_marginTop="@dimen/overlay_border_width_neg"
android:layout_marginEnd="@dimen/overlay_border_width_neg"
android:layout_marginBottom="@dimen/overlay_preview_container_margin"
- android:elevation="7dp"
+ android:elevation="8dp"
android:alpha="0"
android:background="@drawable/overlay_border"
app:layout_constraintStart_toStartOf="@id/actions_container_background"
@@ -83,7 +84,7 @@
android:layout_marginStart="@dimen/overlay_border_width"
android:layout_marginBottom="@dimen/overlay_border_width"
android:layout_gravity="center"
- android:elevation="7dp"
+ android:elevation="8dp"
android:contentDescription="@string/screenshot_edit_description"
android:scaleType="fitEnd"
android:background="@drawable/overlay_preview_background"
@@ -93,17 +94,17 @@
app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"/>
<ImageView
android:id="@+id/screenshot_badge"
- android:layout_width="48dp"
- android:layout_height="48dp"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
android:visibility="gone"
- android:elevation="8dp"
+ android:elevation="9dp"
app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"/>
<FrameLayout
android:id="@+id/screenshot_dismiss_button"
android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
- android:elevation="10dp"
+ android:elevation="11dp"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@id/screenshot_preview"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
@@ -115,7 +116,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/overlay_dismiss_button_margin"
- android:src="@drawable/overlay_cancel"/>
+ android:background="@drawable/circular_background"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
+ android:tint="?androidprv:attr/materialColorOnPrimary"
+ android:padding="4dp"
+ android:src="@drawable/ic_close"/>
</FrameLayout>
<ImageView
android:id="@+id/screenshot_scrollable_preview"
@@ -150,8 +155,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_max="450dp"
- app:layout_constraintHorizontal_bias="0"
- >
+ app:layout_constraintHorizontal_bias="0">
<include layout="@layout/screenshot_work_profile_first_run" />
<include layout="@layout/screenshot_detection_notice" />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
index 392d845..78cd718 100644
--- a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
+++ b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/work_profile_first_run"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -33,9 +34,13 @@
android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
android:contentDescription="@string/screenshot_dismiss_work_profile">
<ImageView
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
android:layout_gravity="center"
- android:src="@drawable/overlay_cancel"/>
+ android:background="@drawable/circular_background"
+ android:backgroundTint="?androidprv:attr/materialColorSurfaceContainerHigh"
+ android:tint="?androidprv:attr/materialColorOnSurface"
+ android:padding="2dp"
+ android:src="@drawable/ic_close"/>
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index aff0e80..bf0b8a6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -342,23 +342,22 @@
<dimen name="screenshot_crop_handle_thickness">3dp</dimen>
- <dimen name="long_screenshot_action_bar_top_margin">8dp</dimen>
+ <dimen name="long_screenshot_action_bar_top_margin">4dp</dimen>
<!-- Dimensions shared between "overlays" (clipboard and screenshot preview UIs) -->
<!-- Constrained size of the floating overlay preview -->
<dimen name="overlay_x_scale">80dp</dimen>
<!-- Radius of the chip background on floating overlay actions -->
- <dimen name="overlay_button_corner_radius">8dp</dimen>
+ <dimen name="overlay_button_corner_radius">16dp</dimen>
<!-- Margin between successive chips -->
<dimen name="overlay_action_chip_margin_start">8dp</dimen>
- <!-- Padding to make tappable chip height 48dp (18+11+11+4+4) -->
- <dimen name="overlay_action_chip_margin_vertical">4dp</dimen>
- <dimen name="overlay_action_chip_padding_vertical">11dp</dimen>
- <dimen name="overlay_action_chip_icon_size">18sp</dimen>
+ <dimen name="overlay_action_chip_padding_vertical">12dp</dimen>
+ <dimen name="overlay_action_chip_icon_size">24sp</dimen>
<!-- Padding on each side of the icon for icon-only chips -->
- <dimen name="overlay_action_chip_icon_only_padding_horizontal">14dp</dimen>
+ <dimen name="overlay_action_chip_icon_only_padding_horizontal">12dp</dimen>
<!-- Padding at the edges of the chip for icon-and-text chips -->
- <dimen name="overlay_action_chip_padding_horizontal">12dp</dimen>
+ <dimen name="overlay_action_chip_padding_start">12dp</dimen>
+ <dimen name="overlay_action_chip_padding_end">16dp</dimen>
<!-- Spacing between chip icon and chip text -->
<dimen name="overlay_action_chip_spacing">8dp</dimen>
<dimen name="overlay_action_chip_text_size">14sp</dimen>
@@ -368,8 +367,8 @@
<dimen name="overlay_action_container_margin_horizontal">8dp</dimen>
<dimen name="overlay_action_container_margin_bottom">6dp</dimen>
<dimen name="overlay_bg_protection_height">242dp</dimen>
- <dimen name="overlay_action_container_corner_radius">18dp</dimen>
- <dimen name="overlay_action_container_padding_vertical">4dp</dimen>
+ <dimen name="overlay_action_container_corner_radius">20dp</dimen>
+ <dimen name="overlay_action_container_padding_vertical">8dp</dimen>
<dimen name="overlay_action_container_padding_right">8dp</dimen>
<dimen name="overlay_action_container_padding_end">8dp</dimen>
<dimen name="overlay_dismiss_button_tappable_size">48dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c57fef1..70fdc20 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2684,6 +2684,10 @@
<string name="media_output_group_title_speakers_and_displays">Speakers & Displays</string>
<!-- Title for Suggested Devices group. [CHAR LIMIT=NONE] -->
<string name="media_output_group_title_suggested_device">Suggested Devices</string>
+ <!-- Summary for end session dialog. [CHAR LIMIT=NONE] -->
+ <string name="media_output_end_session_dialog_summary">Stop your shared session to move media to another device</string>
+ <!-- Button text for stopping session [CHAR LIMIT=60] -->
+ <string name="media_output_end_session_dialog_stop">Stop</string>
<!-- Media Output Broadcast Dialog -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9d0cc11..cee2135 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -782,10 +782,12 @@
</style>
<style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <item name="android:colorBackground">?androidprv:attr/materialColorSurfaceContainer</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightNavigationBar">true</item>
- <item name="android:navigationBarColor">?android:attr/colorBackgroundFloating</item>
+ <item name="android:statusBarColor">?androidprv:attr/materialColorSurfaceContainer</item>
+ <item name="android:navigationBarColor">?androidprv:attr/materialColorSurfaceContainerHighest</item>
<item name="android:windowActivityTransitions">true</item>
</style>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index d8bf570..676f342 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -179,6 +179,20 @@
}
/**
+ * Set alpha directly to mView will clip clock, so we set alpha to clock face instead
+ */
+ public void setAlpha(float alpha) {
+ ClockController clock = getClock();
+ if (clock != null) {
+ clock.getLargeClock().getView().setAlpha(alpha);
+ clock.getSmallClock().getView().setAlpha(alpha);
+ }
+ if (mStatusArea != null) {
+ mStatusArea.setAlpha(alpha);
+ }
+ }
+
+ /**
* Attach the controller to the view it relates to.
*/
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 0982030..58807e4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -184,6 +185,7 @@
}
mAppearAnimator.setDuration(ANIMATION_DURATION);
mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
+ mAppearAnimator.addListener(getAnimationListener(CUJ_LOCKSCREEN_PIN_APPEAR));
mAppearAnimator.start();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 693268d..1cbcb9d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -264,8 +264,7 @@
*/
@Override
public void finish(boolean strongAuth, int targetUserId) {
- if (mFeatureFlags.isEnabled(Flags.PREVENT_BYPASS_KEYGUARD)
- && !mKeyguardStateController.canDismissLockScreen() && !strongAuth) {
+ if (!mKeyguardStateController.canDismissLockScreen() && !strongAuth) {
Log.e(TAG,
"Tried to dismiss keyguard when lockscreen is not dismissible and user "
+ "was not authenticated with a primary security method "
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index d8e1eb0f..2313609 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -135,4 +135,31 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Trace.endSection();
}
+
+ /**
+ * Clock content will be clipped when goes beyond bounds,
+ * so we setAlpha for all views except clock
+ */
+ public void setAlpha(float alpha, boolean excludeClock) {
+ if (!excludeClock) {
+ setAlpha(alpha);
+ return;
+ }
+ if (alpha == 1 || alpha == 0) {
+ setAlpha(alpha);
+ }
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child == mStatusViewContainer) {
+ for (int j = 0; j < mStatusViewContainer.getChildCount(); j++) {
+ View innerChild = mStatusViewContainer.getChildAt(j);
+ if (innerChild != mClockView) {
+ innerChild.setAlpha(alpha);
+ }
+ }
+ } else {
+ child.setAlpha(alpha);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 794eeda..af47466 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -180,7 +180,8 @@
*/
public void setAlpha(float alpha) {
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
- mView.setAlpha(alpha);
+ mView.setAlpha(alpha, true);
+ mKeyguardClockSwitchController.setAlpha(alpha);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 5499d2c..f04fdfff 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -23,6 +23,7 @@
import android.view.DisplayInfo
import android.view.Surface
import android.view.View
+import androidx.annotation.VisibleForTesting
import com.airbnb.lottie.LottieAnimationView
import com.android.settingslib.widget.LottieColorUtils
import com.android.systemui.R
@@ -133,13 +134,19 @@
}
}
- private fun getIconContentDescription(@BiometricState newState: Int): CharSequence? {
+ @VisibleForTesting
+ fun getIconContentDescription(@BiometricState newState: Int): CharSequence? {
val id = when (newState) {
STATE_IDLE,
STATE_AUTHENTICATING_ANIMATING_IN,
STATE_AUTHENTICATING,
STATE_PENDING_CONFIRMATION,
- STATE_AUTHENTICATED -> R.string.security_settings_sfps_enroll_find_sensor_message
+ STATE_AUTHENTICATED ->
+ if (isSideFps) {
+ R.string.security_settings_sfps_enroll_find_sensor_message
+ } else {
+ R.string.fingerprint_dialog_touch_sensor
+ }
STATE_ERROR,
STATE_HELP -> R.string.biometric_dialog_try_again
else -> null
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 92aff06..e600632 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -189,7 +189,7 @@
authorizedPanelsRepository.addAuthorizedPanels(
setOf(serviceInfo.componentName.packageName)
)
- val selected = SelectedItem.PanelItem(appName, componentName)
+ val selected = SelectedItem.PanelItem(appName, serviceInfo.componentName)
controlsController.setPreferredSelection(selected)
animateExitAndFinish()
openControlsOrigin()
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b446724..a4d4a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -206,11 +206,6 @@
"wallpaper_picker_ui_for_aiwp"
)
- /** Whether to inflate the bouncer view on a background thread. */
- // TODO(b/273341787): Tracking Bug
- @JvmField
- val PREVENT_BYPASS_KEYGUARD = releasedFlag(230, "prevent_bypass_keyguard")
-
/** Whether to use a new data source for intents to run on keyguard dismissal. */
@JvmField
val REFACTOR_KEYGUARD_DISMISS_INTENT = unreleasedFlag(231, "refactor_keyguard_dismiss_intent")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b5ddc2e..552e5ea 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2941,9 +2941,12 @@
if (mSurfaceBehindRemoteAnimationFinishedCallback != null) {
try {
mSurfaceBehindRemoteAnimationFinishedCallback.onAnimationFinished();
+ } catch (Throwable t) {
+ // The surface may no longer be available. Just capture the exception
+ Log.w(TAG, "Surface behind remote animation callback failed, and it's probably ok: "
+ + t.getMessage());
+ } finally {
mSurfaceBehindRemoteAnimationFinishedCallback = null;
- } catch (RemoteException e) {
- e.printStackTrace();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt
index 568db2f..e7803c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt
@@ -31,7 +31,9 @@
VibrationEffect.startComposition()
.apply {
val vibrationDelayMs =
- (ShakeAnimationDuration.inWholeMilliseconds / ShakeAnimationCycles * 2).toInt()
+ (ShakeAnimationDuration.inWholeMilliseconds / (ShakeAnimationCycles * 2))
+ .toInt()
+
val vibrationCount = ShakeAnimationCycles.toInt() * 2
repeat(vibrationCount) {
addPrimitive(
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 f50a7a8..d949cf56f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -37,11 +37,13 @@
import androidx.core.widget.CompoundButtonCompat;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Adapter for media output dialog.
@@ -52,6 +54,7 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final float DEVICE_DISCONNECTED_ALPHA = 0.5f;
private static final float DEVICE_CONNECTED_ALPHA = 1f;
+ protected List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>();
public MediaOutputAdapter(MediaOutputController controller) {
super(controller);
@@ -59,6 +62,13 @@
}
@Override
+ public void updateItems() {
+ mMediaItemList.clear();
+ mMediaItemList.addAll(mController.getMediaItemList());
+ notifyDataSetChanged();
+ }
+
+ @Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
super.onCreateViewHolder(viewGroup, viewType);
@@ -79,14 +89,14 @@
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
if (mController.isAdvancedLayoutSupported()) {
- if (position >= mController.getMediaItemList().size()) {
+ if (position >= mMediaItemList.size()) {
if (DEBUG) {
Log.d(TAG, "Incorrect position: " + position + " list size: "
- + mController.getMediaItemList().size());
+ + mMediaItemList.size());
}
return;
}
- MediaItem currentMediaItem = mController.getMediaItemList().get(position);
+ MediaItem currentMediaItem = mMediaItemList.get(position);
switch (currentMediaItem.getMediaItemType()) {
case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
((MediaGroupDividerViewHolder) viewHolder).onBind(currentMediaItem.getTitle());
@@ -119,11 +129,11 @@
@Override
public long getItemId(int position) {
if (mController.isAdvancedLayoutSupported()) {
- if (position >= mController.getMediaItemList().size()) {
+ if (position >= mMediaItemList.size()) {
Log.d(TAG, "Incorrect position for item id: " + position);
return position;
}
- MediaItem currentMediaItem = mController.getMediaItemList().get(position);
+ MediaItem currentMediaItem = mMediaItemList.get(position);
return currentMediaItem.getMediaDevice().isPresent()
? currentMediaItem.getMediaDevice().get().getId().hashCode()
: position;
@@ -143,12 +153,12 @@
@Override
public int getItemViewType(int position) {
if (mController.isAdvancedLayoutSupported()
- && position >= mController.getMediaItemList().size()) {
+ && position >= mMediaItemList.size()) {
Log.d(TAG, "Incorrect position for item type: " + position);
return MediaItem.MediaItemType.TYPE_GROUP_DIVIDER;
}
return mController.isAdvancedLayoutSupported()
- ? mController.getMediaItemList().get(position).getMediaItemType()
+ ? mMediaItemList.get(position).getMediaItemType()
: super.getItemViewType(position);
}
@@ -156,7 +166,7 @@
public int getItemCount() {
// Add extra one for "pair new"
return mController.isAdvancedLayoutSupported()
- ? mController.getMediaItemList().size()
+ ? mMediaItemList.size()
: mController.getMediaDevices().size() + 1;
}
@@ -482,6 +492,14 @@
}
private void onItemClick(View view, MediaDevice device) {
+ if (mController.isCurrentOutputDeviceHasSessionOngoing()) {
+ showCustomEndSessionDialog(device);
+ } else {
+ transferOutput(device);
+ }
+ }
+
+ private void transferOutput(MediaDevice device) {
if (mController.isAnyDeviceTransferring()) {
return;
}
@@ -496,6 +514,14 @@
notifyDataSetChanged();
}
+ @VisibleForTesting
+ void showCustomEndSessionDialog(MediaDevice device) {
+ MediaSessionReleaseDialog mediaSessionReleaseDialog = new MediaSessionReleaseDialog(
+ mContext, () -> transferOutput(device), mController.getColorButtonBackground(),
+ mController.getColorItemContent());
+ mediaSessionReleaseDialog.show();
+ }
+
private void cancelMuteAwaitConnection() {
mController.cancelMuteAwaitConnection();
notifyDataSetChanged();
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 73ab5272..151dbb2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -81,6 +81,11 @@
mIsInitVolumeFirstTime = true;
}
+ /**
+ * Refresh current dataset
+ */
+ public abstract void updateItems();
+
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
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 08e47a0..770e4df 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -382,7 +382,7 @@
&& currentActivePosition < mAdapter.getItemCount()) {
mAdapter.notifyItemChanged(currentActivePosition);
} else {
- mAdapter.notifyDataSetChanged();
+ mAdapter.updateItems();
}
} else {
mMediaOutputController.setRefreshing(false);
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 8e014c6..822644b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -783,6 +783,12 @@
currentConnectedMediaDevice);
}
+ boolean isCurrentOutputDeviceHasSessionOngoing() {
+ MediaDevice currentConnectedMediaDevice = getCurrentConnectedMediaDevice();
+ return currentConnectedMediaDevice != null
+ && (currentConnectedMediaDevice.isHostForOngoingSession());
+ }
+
public boolean isAdvancedLayoutSupported() {
return mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSessionReleaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSessionReleaseDialog.java
new file mode 100644
index 0000000..2680a2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSessionReleaseDialog.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 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.media.dialog;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+/**
+ * Confirmation dialog for releasing media session
+ */
+
+public class MediaSessionReleaseDialog extends SystemUIDialog {
+
+ private View mDialogView;
+
+ private final Context mContext;
+ private final View.OnClickListener mPositiveButtonListener;
+ private final ColorFilter mButtonColorFilter;
+ private final int mIconColor;
+
+ public MediaSessionReleaseDialog(Context context, Runnable runnable, int buttonColor,
+ int iconColor) {
+ super(context, R.style.Theme_SystemUI_Dialog_Media);
+ mContext = getContext();
+ mPositiveButtonListener = (v) -> {
+ runnable.run();
+ dismiss();
+ };
+ mButtonColorFilter = new PorterDuffColorFilter(
+ buttonColor,
+ PorterDuff.Mode.SRC_IN);
+ mIconColor = iconColor;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mDialogView = LayoutInflater.from(mContext).inflate(R.layout.media_session_end_dialog,
+ null);
+ final Window window = getWindow();
+ window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
+ window.setContentView(mDialogView);
+
+ final WindowManager.LayoutParams lp = window.getAttributes();
+ lp.gravity = Gravity.CENTER;
+ lp.width = (int) (mContext.getResources().getDisplayMetrics().widthPixels * 0.90);
+
+ ImageView headerIcon = mDialogView.requireViewById(R.id.end_icon);
+ headerIcon.setImageDrawable(mContext.getDrawable(R.drawable.media_output_status_failed));
+ headerIcon.setImageTintList(
+ ColorStateList.valueOf(mIconColor));
+
+ Button stopButton = mDialogView.requireViewById(R.id.stop_button);
+ stopButton.setOnClickListener(mPositiveButtonListener);
+ stopButton.getBackground().setColorFilter(mButtonColorFilter);
+
+ Button cancelButton = mDialogView.requireViewById(R.id.cancel_button);
+ cancelButton.setOnClickListener((v) -> dismiss());
+ cancelButton.getBackground().setColorFilter(mButtonColorFilter);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 2312c70..4bc7ec8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -343,22 +343,24 @@
} else {
String editorPackage = getString(R.string.config_screenshotEditor);
Intent intent = new Intent(Intent.ACTION_EDIT);
- if (!TextUtils.isEmpty(editorPackage)) {
- intent.setComponent(ComponentName.unflattenFromString(editorPackage));
- }
intent.setDataAndType(uri, "image/png");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ Bundle options = null;
- mTransitionView.setImageBitmap(mOutputBitmap);
- mTransitionView.setVisibility(View.VISIBLE);
- mTransitionView.setTransitionName(
- ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
- // TODO: listen for transition completing instead of finishing onStop
- mTransitionStarted = true;
- startActivity(intent,
- ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView,
- ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle());
+ // Skip shared element transition for implicit edit intents
+ if (!TextUtils.isEmpty(editorPackage)) {
+ intent.setComponent(ComponentName.unflattenFromString(editorPackage));
+ mTransitionView.setImageBitmap(mOutputBitmap);
+ mTransitionView.setVisibility(View.VISIBLE);
+ mTransitionView.setTransitionName(
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
+ options = ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView,
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle();
+ // TODO: listen for transition completing instead of finishing onStop
+ mTransitionStarted = true;
+ }
+ startActivity(intent, options);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
index 860bfe37..13678b0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
@@ -121,13 +121,15 @@
LinearLayout.LayoutParams textParams =
(LinearLayout.LayoutParams) mTextView.getLayoutParams();
if (hasText) {
- int paddingHorizontal = mContext.getResources().getDimensionPixelSize(
- R.dimen.overlay_action_chip_padding_horizontal);
+ int paddingStart = mContext.getResources().getDimensionPixelSize(
+ R.dimen.overlay_action_chip_padding_start);
int spacing = mContext.getResources().getDimensionPixelSize(
R.dimen.overlay_action_chip_spacing);
- iconParams.setMarginStart(paddingHorizontal);
+ int paddingEnd = mContext.getResources().getDimensionPixelSize(
+ R.dimen.overlay_action_chip_padding_end);
+ iconParams.setMarginStart(paddingStart);
iconParams.setMarginEnd(spacing);
- textParams.setMarginEnd(paddingHorizontal);
+ textParams.setMarginEnd(paddingEnd);
} else {
int paddingHorizontal = mContext.getResources().getDimensionPixelSize(
R.dimen.overlay_action_chip_icon_only_padding_horizontal);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 560ea8a..313410a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -604,6 +604,7 @@
}
updateAodIconsVisibility(animate, false /* force */);
updateAodNotificationIcons();
+ updateAodIconColors();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index bd5815aa..7bbb03b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -304,10 +304,11 @@
ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
- // If we are launching a work activity and require to launch
- // separate work challenge, we defer the activity action and cancel
- // notification until work challenge is unlocked.
- if (isActivityIntent) {
+ // If the notification should be cancelled on click and we are launching a work activity in
+ // a locked profile with separate challenge, we defer the activity action and cancelling of
+ // the notification until work challenge is unlocked. If the notification shouldn't be
+ // cancelled, the work challenge will be shown by ActivityManager if necessary anyway.
+ if (isActivityIntent && shouldAutoCancel(entry.getSbn())) {
final int userId = intent.getCreatorUserHandle().getIdentifier();
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
&& mKeyguardManager.isDeviceLocked(userId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index eec91a0..e1ffae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -259,7 +259,7 @@
*/
override val isDefaultConnectionFailed: StateFlow<Boolean> =
combine(
- mobileConnectionsRepo.mobileIsDefault,
+ mobileIsDefault,
mobileConnectionsRepo.defaultConnectionIsValidated,
forcingCellularValidation,
) { mobileIsDefault, defaultConnectionIsValidated, forcingCellularValidation ->
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index d74906a..eed7950 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -154,10 +154,6 @@
pendingScrimReadyCallback = onReady
}
} else if (isFolded && !isFoldHandled && alwaysOnEnabled && isDozing) {
- // Screen turning on for the first time after folding and we are already dozing
- // We should play the folding to AOD animation
- isFoldHandled = true
-
setAnimationState(playing = true)
getShadeFoldAnimator().prepareFoldToAodAnimation()
@@ -173,6 +169,13 @@
// No animation, call ready callback immediately
onReady.run()
}
+
+ if (isFolded) {
+ // Any time the screen turns on, this state needs to be reset if the device has been
+ // folded. Reaching this line implies AOD has been shown in one way or another,
+ // if enabled
+ isFoldHandled = true
+ }
}
/** Called when keyguard scrim opaque changed */
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index fb73845..d8e2a38 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -134,6 +134,7 @@
private KeyguardClockSwitchController mController;
private View mSliceView;
+ private LinearLayout mStatusArea;
private FakeExecutor mExecutor;
@Before
@@ -195,8 +196,8 @@
mSliceView = new View(getContext());
when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(
- new LinearLayout(getContext()));
+ mStatusArea = new LinearLayout(getContext());
+ when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
}
@Test
@@ -401,6 +402,15 @@
assertNull(mController.getClock());
}
+ @Test
+ public void testSetAlpha_setClockAlphaForCLockFace() {
+ mController.onViewAttached();
+ mController.setAlpha(0.5f);
+ verify(mLargeClockView).setAlpha(0.5f);
+ verify(mSmallClockView).setAlpha(0.5f);
+ assertEquals(0.5f, mStatusArea.getAlpha(), 0.0f);
+ }
+
private void verifyAttachment(VerificationMode times) {
verify(mClockRegistry, times).registerClockChangeListener(
any(ClockRegistry.ClockChangeListener.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index 8a05a37..65ddb53 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -64,7 +64,6 @@
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
@@ -398,26 +397,6 @@
}
@Test
- public void showNextSecurityScreenOrFinish_DeviceNotSecure_prevent_bypass_on() {
- when(mFeatureFlags.isEnabled(Flags.PREVENT_BYPASS_KEYGUARD)).thenReturn(true);
- // GIVEN the current security method is SimPin
- when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
- when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false);
- mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin);
-
- // WHEN a request is made from the SimPin screens to show the next security method
- when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.None);
- mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
- /* authenticated= */true,
- TARGET_USER_ID,
- /* bypassSecondaryLockScreen= */true,
- SecurityMode.SimPin);
-
- // THEN the next security method of None will dismiss keyguard.
- verify(mViewMediatorCallback).keyguardDone(anyBoolean(), anyInt());
- }
-
- @Test
public void showNextSecurityScreenOrFinish_ignoresCallWhenSecurityMethodHasChanged() {
//GIVEN current security mode has been set to PIN
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.PIN);
@@ -608,7 +587,6 @@
@Test
public void testSecurityCallbackFinish_cannotDismissLockScreenAndNotStrongAuth() {
- when(mFeatureFlags.isEnabled(Flags.PREVENT_BYPASS_KEYGUARD)).thenReturn(true);
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
mKeyguardSecurityContainerController.finish(false, 0);
verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
index 508aea5..a8c281c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -24,6 +24,8 @@
get() = keyguardStatusView.findViewById(R.id.status_view_media_container)
private val statusViewContainer: ViewGroup
get() = keyguardStatusView.findViewById(R.id.status_view_container)
+ private val clockView: ViewGroup
+ get() = keyguardStatusView.findViewById(R.id.keyguard_clock_container)
private val childrenExcludingMedia
get() = statusViewContainer.children.filter { it != mediaView }
@@ -56,4 +58,12 @@
assertThat(it.translationY).isEqualTo(translationY)
}
}
+
+ @Test
+ fun setAlphaExcludeClock() {
+ keyguardStatusView.setAlpha(0.5f, /* excludeClock= */true)
+ assertThat(statusViewContainer.alpha).isNotEqualTo(0.5f)
+ assertThat(mediaView.alpha).isEqualTo(0.5f)
+ assertThat(clockView.alpha).isNotEqualTo(0.5f)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
new file mode 100644
index 0000000..cac618b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 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.biometrics
+
+import android.content.Context
+import android.hardware.biometrics.SensorProperties
+import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.FingerprintSensorProperties
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.view.ViewGroup.LayoutParams
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.airbnb.lottie.LottieAnimationView
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenEver
+import org.mockito.junit.MockitoJUnit
+
+private const val SENSOR_ID = 1
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AuthBiometricFingerprintIconControllerTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var iconView: LottieAnimationView
+ @Mock private lateinit var iconViewOverlay: LottieAnimationView
+ @Mock private lateinit var layoutParam: LayoutParams
+ @Mock private lateinit var fingerprintManager: FingerprintManager
+
+ private lateinit var controller: AuthBiometricFingerprintIconController
+
+ @Before
+ fun setUp() {
+ context.addMockSystemService(Context.FINGERPRINT_SERVICE, fingerprintManager)
+ whenEver(iconView.layoutParams).thenReturn(layoutParam)
+ whenEver(iconViewOverlay.layoutParams).thenReturn(layoutParam)
+ }
+
+ @Test
+ fun testIconContentDescription_SfpsDevice() {
+ setupFingerprintSensorProperties(FingerprintSensorProperties.TYPE_POWER_BUTTON)
+ controller = AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay)
+
+ assertThat(controller.getIconContentDescription(AuthBiometricView.STATE_AUTHENTICATING))
+ .isEqualTo(
+ context.resources.getString(
+ R.string.security_settings_sfps_enroll_find_sensor_message
+ )
+ )
+ }
+
+ @Test
+ fun testIconContentDescription_NonSfpsDevice() {
+ setupFingerprintSensorProperties(FingerprintSensorProperties.TYPE_UDFPS_OPTICAL)
+ controller = AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay)
+
+ assertThat(controller.getIconContentDescription(AuthBiometricView.STATE_AUTHENTICATING))
+ .isEqualTo(context.resources.getString(R.string.fingerprint_dialog_touch_sensor))
+ }
+
+ private fun setupFingerprintSensorProperties(sensorType: Int) {
+ whenEver(fingerprintManager.sensorPropertiesInternal)
+ .thenReturn(
+ listOf(
+ FingerprintSensorPropertiesInternal(
+ SENSOR_ID,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ listOf() /* componentInfo */,
+ sensorType,
+ true /* halControlsIllumination */,
+ true /* resetLockoutRequiresHardwareAuthToken */,
+ listOf() /* sensorLocations */
+ )
+ )
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
index 8dfd223..b2e37cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
@@ -190,6 +191,9 @@
val setCaptor: ArgumentCaptor<Set<String>> = argumentCaptor()
verify(authorizedPanelsRepository).addAuthorizedPanels(capture(setCaptor))
assertThat(setCaptor.value).containsExactly(info.componentName.packageName)
+ val selectedComponentCaptor: ArgumentCaptor<SelectedItem> = argumentCaptor()
+ verify(controlsController).setPreferredSelection(capture(selectedComponentCaptor))
+ assertThat(selectedComponentCaptor.value.componentName).isEqualTo(info.componentName)
assertThat(activityRule.activity.triedToFinish).isTrue()
}
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 7f7952f..faca8a91d 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
@@ -26,6 +26,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,6 +35,7 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -60,6 +62,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
[email protected](setAsMainLooper = true)
public class MediaOutputAdapterTest extends SysuiTestCase {
private static final String TEST_DEVICE_NAME_1 = "test_device_name_1";
@@ -116,6 +119,7 @@
mMediaItems.add(new MediaItem(mMediaDevice2));
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mSpyMediaOutputSeekbar = spy(mViewHolder.mSeekBar);
@@ -202,9 +206,11 @@
public void advanced_onBindViewHolder_bindPairNew_verifyView() {
when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaItems.add(new MediaItem());
+ mMediaOutputAdapter.updateItems();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -223,6 +229,7 @@
Collectors.toList()));
when(mMediaOutputController.getSessionName()).thenReturn(TEST_SESSION_NAME);
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.getItemCount();
@@ -243,6 +250,7 @@
Collectors.toList()));
when(mMediaOutputController.getSessionName()).thenReturn(null);
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.getItemCount();
@@ -602,9 +610,11 @@
public void advanced_onItemClick_clickPairNew_verifyLaunchBluetoothPairing() {
when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaItems.add(new MediaItem());
+ mMediaOutputAdapter.updateItems();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
mViewHolder.mContainerLayout.performClick();
@@ -613,6 +623,7 @@
@Test
public void onItemClick_clickDevice_verifyConnectDevice() {
+ when(mMediaOutputController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(false);
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -623,6 +634,21 @@
}
@Test
+ public void onItemClick_clickDeviceWithSessionOngoing_verifyShowsDialog() {
+ when(mMediaOutputController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(true);
+ assertThat(mMediaDevice2.getState()).isEqualTo(
+ LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
+ MediaOutputAdapter.MediaDeviceViewHolder spyMediaDeviceViewHolder = spy(mViewHolder);
+
+ mMediaOutputAdapter.onBindViewHolder(spyMediaDeviceViewHolder, 0);
+ mMediaOutputAdapter.onBindViewHolder(spyMediaDeviceViewHolder, 1);
+ spyMediaDeviceViewHolder.mContainerLayout.performClick();
+
+ verify(mMediaOutputController, never()).connectDevice(mMediaDevice2);
+ verify(spyMediaDeviceViewHolder).showCustomEndSessionDialog(mMediaDevice2);
+ }
+
+ @Test
public void onItemClick_clicksWithMutingExpectedDeviceExist_cancelsMuteAwaitConnection() {
when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(false);
when(mMediaOutputController.hasMutingExpectedDevice()).thenReturn(true);
@@ -700,6 +726,7 @@
mMediaItems.stream().map((item) -> item.getMediaDevice().get()).collect(
Collectors.toList()));
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
List<MediaDevice> selectableDevices = new ArrayList<>();
@@ -734,4 +761,18 @@
verify(mMediaOutputController).setCurrentColorScheme(wallpaperColors, true);
}
+
+ @Test
+ public void updateItems_controllerItemsUpdated_notUpdatesInAdapterUntilUpdateItems() {
+ when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(true);
+ mMediaOutputAdapter.updateItems();
+ List<MediaItem> updatedList = new ArrayList<>();
+ updatedList.add(new MediaItem());
+ when(mMediaOutputController.getMediaItemList()).thenReturn(updatedList);
+ assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaItems.size());
+
+ mMediaOutputAdapter.updateItems();
+
+ assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(updatedList.size());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index f206409..480d59c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -239,7 +239,7 @@
when(mMediaOutputBaseAdapter.isDragging()).thenReturn(false);
mMediaOutputBaseDialogImpl.refresh();
- verify(mMediaOutputBaseAdapter).notifyDataSetChanged();
+ verify(mMediaOutputBaseAdapter).updateItems();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 6e1ab58..1c219da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -361,6 +361,21 @@
job.cancel()
}
+ @Test
+ fun failedConnection_carrierMergedDefault_notValidated_failed() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.hasCarrierMergedConnection.value = true
+ connectionsRepository.defaultConnectionIsValidated.value = false
+ yield()
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
/** Regression test for b/275076959. */
@Test
fun failedConnection_dataSwitchInSameGroup_notFailed() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index 8fc0a1a..6298506 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -200,6 +200,31 @@
}
@Test
+ fun onFolded_onScreenTurningOnWithoutDozingThenWithDozing_doesNotLogLatency() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.listenForDozing(this)
+ keyguardRepository.setDozing(false)
+ setAodEnabled(enabled = true)
+
+ yield()
+
+ fold()
+ simulateScreenTurningOn()
+ reset(latencyTracker)
+
+ // Now enable dozing and trigger a second run through the aod animation code. It should
+ // not rerun the animation
+ keyguardRepository.setDozing(true)
+ yield()
+ simulateScreenTurningOn()
+
+ verify(latencyTracker, never()).onActionStart(any())
+ verify(latencyTracker, never()).onActionEnd(any())
+
+ job.cancel()
+ }
+
+ @Test
fun onFolded_animationCancelled_doesNotLogLatency() =
runBlocking(IMMEDIATE) {
val job = underTest.listenForDozing(this)
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 7463061..a324b2f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -2551,6 +2551,9 @@
@Override
public void attachAccessibilityOverlayToWindow(int accessibilityWindowId, SurfaceControl sc)
throws RemoteException {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setTrustedOverlay(sc, true).apply();
+ t.close();
synchronized (mLock) {
RemoteAccessibilityConnection connection =
mA11yWindowManager.getConnectionLocked(
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e894f1c..2d1290c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -5329,9 +5329,8 @@
mA11yOverlayLayers.remove(displayId);
return;
}
- SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
- transaction.reparent(sc, parent);
- transaction.apply();
- transaction.close();
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.reparent(sc, parent).setTrustedOverlay(sc, true).apply();
+ t.close();
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index d290c361..fb94af6 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1581,6 +1581,13 @@
// TODO(b/266379948): Ideally wait for PCC request to finish for a while more
// (say 100ms) before proceeding further on.
+ processResponseLockedForPcc(response, response.getClientState(), requestFlags);
+ }
+
+
+ @GuardedBy("mLock")
+ private void processResponseLockedForPcc(@NonNull FillResponse response,
+ @Nullable Bundle newClientState, int flags) {
if (DBG) {
Slog.d(TAG, "DBG: Initial response: " + response);
}
@@ -1588,12 +1595,15 @@
response = getEffectiveFillResponse(response);
if (isEmptyResponse(response)) {
// Treat it as a null response.
- processNullResponseLocked(requestId, requestFlags);
+ processNullResponseLocked(
+ response != null ? response.getRequestId() : 0,
+ flags);
+ return;
}
if (DBG) {
Slog.d(TAG, "DBG: Processed response: " + response);
}
- processResponseLocked(response, null, requestFlags);
+ processResponseLocked(response, newClientState, flags);
}
}
@@ -2490,7 +2500,10 @@
if (sDebug) Slog.d(TAG, "Updating client state from auth dataset");
mClientState = newClientState;
}
- final Dataset dataset = (Dataset) result;
+ Dataset dataset = (Dataset) result;
+ FillResponse temp = new FillResponse.Builder().addDataset(dataset).build();
+ temp = getEffectiveFillResponse(temp);
+ dataset = temp.getDatasets().get(0);
final Dataset oldDataset = authenticatedResponse.getDatasets().get(datasetIdx);
if (!isAuthResultDatasetEphemeral(oldDataset, data)) {
authenticatedResponse.getDatasets().set(datasetIdx, dataset);
@@ -4665,10 +4678,8 @@
setViewStatesLocked(oldResponse, ViewState.STATE_INITIAL, true);
// Move over the id
newResponse.setRequestId(oldResponse.getRequestId());
- // Replace the old response
- mResponses.put(newResponse.getRequestId(), newResponse);
// Now process the new response
- processResponseLocked(newResponse, newClientState, 0);
+ processResponseLockedForPcc(newResponse, newClientState, 0);
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/SoundTriggerInternal.java b/services/core/java/com/android/server/SoundTriggerInternal.java
index f184574..f8830ea 100644
--- a/services/core/java/com/android/server/SoundTriggerInternal.java
+++ b/services/core/java/com/android/server/SoundTriggerInternal.java
@@ -47,7 +47,14 @@
int STATUS_OK = SoundTrigger.STATUS_OK;
// Attach to a specific underlying STModule
- Session attach(@NonNull IBinder client, ModuleProperties underlyingModule);
+ /**
+ * Attach to a specific underlying STModule.
+ * @param client - Binder token representing the app client for death notifications
+ * @param underlyingModule - Properties of the underlying STModule to attach to
+ * @param isTrusted - {@code true} if callbacks will be appropriately AppOps attributed by
+ * a trusted component prior to delivery to the ultimate client.
+ */
+ Session attach(@NonNull IBinder client, ModuleProperties underlyingModule, boolean isTrusted);
// Enumerate possible STModules to attach to
List<ModuleProperties> listModuleProperties(Identity originatorIdentity);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a888a0b..8ce1829 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2497,13 +2497,10 @@
final File systemDir = SystemServiceManager.ensureSystemDir();
// TODO: Move creation of battery stats service outside of activity manager service.
- mBatteryStatsService = new BatteryStatsService(systemContext, systemDir,
- BackgroundThread.get().getHandler());
- mBatteryStatsService.getActiveStatistics().readLocked();
- mBatteryStatsService.scheduleWriteToDisk();
+ mBatteryStatsService = BatteryStatsService.create(systemContext, systemDir,
+ BackgroundThread.getHandler(), this);
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
- mBatteryStatsService.getActiveStatistics().setCallback(this);
mOomAdjProfiler.batteryPowerChanged(mOnBattery);
mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 6360e2a0..36da888 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -399,6 +399,20 @@
mCpuWakeupStats = new CpuWakeupStats(context, R.xml.irq_device_map, mHandler);
}
+ /**
+ * Creates an instance of BatteryStatsService and restores data from stored state.
+ */
+ public static BatteryStatsService create(Context context, File systemDir, Handler handler,
+ BatteryStatsImpl.BatteryCallback callback) {
+ BatteryStatsService service = new BatteryStatsService(context, systemDir, handler);
+ service.mStats.setCallback(callback);
+ synchronized (service.mStats) {
+ service.mStats.readLocked();
+ }
+ service.scheduleWriteToDisk();
+ return service;
+ }
+
public void publish() {
LocalServices.addService(BatteryStatsInternal.class, new LocalService());
ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index d7b22a8..c393213 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2300,6 +2300,8 @@
final Process.ProcessStartResult startResult;
boolean regularZygote = false;
+ app.mProcessGroupCreated = false;
+ app.mSkipProcessGroupCreation = false;
if (hostingRecord.usesWebviewZygote()) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
@@ -2328,18 +2330,28 @@
isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,
allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
+ // By now the process group should have been created by zygote.
+ app.mProcessGroupCreated = true;
}
if (!regularZygote) {
// webview and app zygote don't have the permission to create the nodes
- final int res = Process.createProcessGroup(uid, startResult.pid);
- if (res < 0) {
- if (res == -OsConstants.ESRCH) {
- Slog.e(ActivityManagerService.TAG, "Unable to create process group for "
- + app.processName + " (" + startResult.pid + ")");
- } else {
- throw new AssertionError("Unable to create process group for "
- + app.processName + " (" + startResult.pid + ")");
+ synchronized (app) {
+ if (!app.mSkipProcessGroupCreation) {
+ // If we're not told to skip the process group creation, go create it.
+ final int res = Process.createProcessGroup(uid, startResult.pid);
+ if (res < 0) {
+ if (res == -OsConstants.ESRCH) {
+ Slog.e(ActivityManagerService.TAG,
+ "Unable to create process group for "
+ + app.processName + " (" + startResult.pid + ")");
+ } else {
+ throw new AssertionError("Unable to create process group for "
+ + app.processName + " (" + startResult.pid + ")");
+ }
+ } else {
+ app.mProcessGroupCreated = true;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 0417b8c..4ec813e 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -424,6 +424,16 @@
*/
Runnable mSuccessorStartRunnable;
+ /**
+ * Whether or not the process group of this process has been created.
+ */
+ volatile boolean mProcessGroupCreated;
+
+ /**
+ * Whether or not we should skip the process group creation.
+ */
+ volatile boolean mSkipProcessGroupCreation;
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startUptime, long startElapsedTime) {
this.mStartUid = startUid;
@@ -1192,8 +1202,26 @@
EventLog.writeEvent(EventLogTags.AM_KILL,
userId, mPid, processName, mState.getSetAdj(), reason);
Process.killProcessQuiet(mPid);
- if (!asyncKPG) Process.sendSignalToProcessGroup(uid, mPid, OsConstants.SIGKILL);
- ProcessList.killProcessGroup(uid, mPid);
+ final boolean killProcessGroup;
+ if (mHostingRecord != null
+ && (mHostingRecord.usesWebviewZygote() || mHostingRecord.usesAppZygote())) {
+ synchronized (ProcessRecord.this) {
+ killProcessGroup = mProcessGroupCreated;
+ if (!killProcessGroup) {
+ // The process group hasn't been created, request to skip it.
+ mSkipProcessGroupCreation = true;
+ }
+ }
+ } else {
+ killProcessGroup = true;
+ }
+ if (killProcessGroup) {
+ if (asyncKPG) {
+ ProcessList.killProcessGroup(uid, mPid);
+ } else {
+ Process.sendSignalToProcessGroup(uid, mPid, OsConstants.SIGKILL);
+ }
+ }
} else {
mPendingStart = false;
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a110169..1f3795a 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -44,6 +44,7 @@
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_SANDBOXED;
+import static android.app.AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
import static android.app.AppOpsManager.OP_VIBRATE;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
@@ -1769,6 +1770,11 @@
@Override
public void setUidMode(int code, int uid, int mode) {
setUidMode(code, uid, mode, null);
+ if (code == OP_RUN_ANY_IN_BACKGROUND) {
+ // TODO (b/280869337): Remove this once we have the required data.
+ Slog.wtfStack(TAG, "setUidMode called for RUN_ANY_IN_BACKGROUND by uid: "
+ + UserHandle.formatUid(Binder.getCallingUid()));
+ }
}
private void setUidMode(int code, int uid, int mode,
@@ -1944,6 +1950,17 @@
@Override
public void setMode(int code, int uid, @NonNull String packageName, int mode) {
setMode(code, uid, packageName, mode, null);
+ final int callingUid = Binder.getCallingUid();
+ if (code == OP_RUN_ANY_IN_BACKGROUND && mode != MODE_ALLOWED) {
+ // TODO (b/280869337): Remove this once we have the required data.
+ final String callingPackage = ArrayUtils.firstOrNull(getPackagesForUid(callingUid));
+ Slog.wtfStack(TAG,
+ "RUN_ANY_IN_BACKGROUND for package " + packageName + " changed to mode: "
+ + modeToName(mode) + " via setMode. Calling package: " + callingPackage
+ + ", calling uid: " + UserHandle.formatUid(callingUid)
+ + ", calling pid: " + Binder.getCallingPid()
+ + ", system pid: " + Process.myPid());
+ }
}
void setMode(int code, int uid, @NonNull String packageName, int mode,
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 773df37..1d8bef1 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1031,7 +1031,8 @@
synchronized (rolesMap) {
Pair<Integer, Integer> key = new Pair<>(useCase, role);
if (!rolesMap.containsKey(key)) {
- return AudioSystem.SUCCESS;
+ // trying to remove a role for a device that wasn't set
+ return AudioSystem.BAD_VALUE;
}
List<AudioDeviceAttributes> roleDevices = rolesMap.get(key);
List<AudioDeviceAttributes> appliedDevices = new ArrayList<>();
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index aece17e7..4aa256d 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -78,6 +78,23 @@
/*package*/ static final String ACTION_CHECK_MUSIC_ACTIVE =
"com.android.server.audio.action.CHECK_MUSIC_ACTIVE";
+ /**
+ * Property to force the index based safe volume warnings. Note that usually when the
+ * CSD warnings are active the safe volume warnings are deactivated. In combination with
+ * {@link SoundDoseHelper#SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE} both approaches can be active
+ * at the same time.
+ */
+ private static final String SYSTEM_PROPERTY_SAFEMEDIA_FORCE = "audio.safemedia.force";
+ /** Property for bypassing the index based safe volume approach. */
+ private static final String SYSTEM_PROPERTY_SAFEMEDIA_BYPASS = "audio.safemedia.bypass";
+ /**
+ * Property to force the CSD warnings. Note that usually when the CSD warnings are active the
+ * safe volume warnings are deactivated. In combination with
+ * {@link SoundDoseHelper#SYSTEM_PROPERTY_SAFEMEDIA_FORCE} both approaches can be active
+ * at the same time.
+ */
+ private static final String SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE = "audio.safemedia.csd.force";
+
// mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
// It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
// or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
@@ -830,56 +847,64 @@
}
private void onConfigureSafeMedia(boolean force, String caller) {
+ updateCsdEnabled(caller);
+
synchronized (mSafeMediaVolumeStateLock) {
int mcc = mContext.getResources().getConfiguration().mcc;
if ((mMcc != mcc) || ((mMcc == 0) && force)) {
mSafeMediaVolumeIndex = mContext.getResources().getInteger(
com.android.internal.R.integer.config_safe_media_volume_index) * 10;
-
initSafeMediaVolumeIndex();
- boolean safeMediaVolumeEnabled =
- SystemProperties.getBoolean("audio.safemedia.force", false)
- || mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_safe_media_volume_enabled);
- boolean safeMediaVolumeBypass =
- SystemProperties.getBoolean("audio.safemedia.bypass", false);
+ updateSafeMediaVolume_l(caller);
- // The persisted state is either "disabled" or "active": this is the state applied
- // next time we boot and cannot be "inactive"
- int persistedState;
- if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
- persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
- // The state can already be "inactive" here if the user has forced it before
- // the 30 seconds timeout for forced configuration. In this case we don't reset
- // it to "active".
- if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
- if (mMusicActiveMs == 0) {
- mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
- enforceSafeMediaVolume(caller);
- } else {
- // We have existing playback time recorded, already confirmed.
- mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
- mLastMusicActiveTimeMs = 0;
- }
- }
- } else {
- persistedState = SAFE_MEDIA_VOLUME_DISABLED;
- mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
- }
mMcc = mcc;
- mAudioHandler.sendMessageAtTime(
- mAudioHandler.obtainMessage(MSG_PERSIST_SAFE_VOLUME_STATE,
- persistedState, /*arg2=*/0,
- /*obj=*/null), /*delay=*/0);
}
-
- updateCsdEnabled(caller);
}
}
+ @GuardedBy("mSafeMediaVolumeStateLock")
+ private void updateSafeMediaVolume_l(String caller) {
+ boolean safeMediaVolumeEnabled =
+ SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_FORCE, false)
+ || (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_safe_media_volume_enabled)
+ && !mEnableCsd.get());
+ boolean safeMediaVolumeBypass =
+ SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_BYPASS, false);
+
+ // The persisted state is either "disabled" or "active": this is the state applied
+ // next time we boot and cannot be "inactive"
+ int persistedState;
+ if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
+ persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
+ // The state can already be "inactive" here if the user has forced it before
+ // the 30 seconds timeout for forced configuration. In this case we don't reset
+ // it to "active".
+ if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
+ if (mMusicActiveMs == 0) {
+ mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+ enforceSafeMediaVolume(caller);
+ } else {
+ // We have existing playback time recorded, already confirmed.
+ mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
+ mLastMusicActiveTimeMs = 0;
+ }
+ }
+ } else {
+ persistedState = SAFE_MEDIA_VOLUME_DISABLED;
+ mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
+ }
+
+ mAudioHandler.sendMessageAtTime(
+ mAudioHandler.obtainMessage(MSG_PERSIST_SAFE_VOLUME_STATE,
+ persistedState, /*arg2=*/0,
+ /*obj=*/null), /*delay=*/0);
+ }
+
private void updateCsdEnabled(String caller) {
- boolean newEnableCsd = SystemProperties.getBoolean("audio.safemedia.force", false);
+ boolean newEnableCsd = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE,
+ false);
if (!newEnableCsd) {
final String featureFlagEnableCsdValue = DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_MEDIA,
@@ -895,6 +920,10 @@
if (mEnableCsd.compareAndSet(!newEnableCsd, newEnableCsd)) {
Log.i(TAG, caller + ": enable CSD " + newEnableCsd);
initCsd();
+
+ synchronized (mSafeMediaVolumeStateLock) {
+ updateSafeMediaVolume_l(caller);
+ }
}
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index da822fa..3e31bd1 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -892,9 +892,8 @@
* @return true/false if contact sharing is enabled/disabled
*/
protected boolean isContactSharingAllowedForCloneProfile() {
- // TODO(b/253449368): This method should also check for the config controlling
- // all app-cloning features.
- return mAppCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks();
+ return mContext.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks)
+ && mAppCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks();
}
/**
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 9b1a80be..0bd6dff 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1330,7 +1330,11 @@
@Override
public PendingIntent getActivityLaunchIntent(String callingPackage, ComponentName component,
UserHandle user) {
- ensureShortcutPermission(callingPackage);
+ if (mContext.checkPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS,
+ injectBinderCallingPid(), injectBinderCallingUid())
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Permission START_TASKS_FROM_RECENTS required");
+ }
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
throw new ActivityNotFoundException("Activity could not be found");
}
diff --git a/services/core/java/com/android/server/pm/NoFilteringResolver.java b/services/core/java/com/android/server/pm/NoFilteringResolver.java
index 3923890..ccd5b0e 100644
--- a/services/core/java/com/android/server/pm/NoFilteringResolver.java
+++ b/services/core/java/com/android/server/pm/NoFilteringResolver.java
@@ -23,6 +23,7 @@
import android.content.pm.ResolveInfo;
import android.os.Binder;
+import com.android.internal.R;
import com.android.internal.config.appcloning.AppCloningDeviceConfigHelper;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.resolution.ComponentResolverApi;
@@ -61,7 +62,8 @@
long flags) {
final long token = Binder.clearCallingIdentity();
try {
- return appCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks()
+ return context.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks)
+ && appCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks()
&& (resolveForStart || (((flags & PackageManager.MATCH_CLONE_PROFILE) != 0)
&& hasPermission(context, Manifest.permission.QUERY_CLONED_APPS)));
} finally {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 1c89ec4..3c5ad2a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1573,7 +1573,7 @@
@Override
public void reportUserMayRequestUnlock(int userId) throws RemoteException {
enforceReportPermission();
- mHandler.obtainMessage(MSG_USER_MAY_REQUEST_UNLOCK, userId).sendToTarget();
+ mHandler.obtainMessage(MSG_USER_MAY_REQUEST_UNLOCK, userId, /*arg2=*/ 0).sendToTarget();
}
@Override
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 88c9042..1f5c1cf 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2629,6 +2629,10 @@
getSessionLocked(sessionState).notifyAdBufferReady(buffer);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in notifyAdBuffer", e);
+ } finally {
+ if (buffer != null) {
+ buffer.getSharedMemory().close();
+ }
}
}
} finally {
@@ -3891,10 +3895,13 @@
return;
}
try {
- mSessionState.client.onAdBufferConsumed(
- buffer, mSessionState.seq);
+ mSessionState.client.onAdBufferConsumed(buffer, mSessionState.seq);
} catch (RemoteException e) {
Slog.e(TAG, "error in onAdBufferConsumed", e);
+ } finally {
+ if (buffer != null) {
+ buffer.getSharedMemory().close();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 80cb085..e6273d3 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -2007,6 +2007,10 @@
getSessionLocked(sessionState).notifyAdBufferConsumed(buffer);
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in notifyAdBufferConsumed", e);
+ } finally {
+ if (buffer != null) {
+ buffer.getSharedMemory().close();
+ }
}
}
} finally {
@@ -3063,6 +3067,10 @@
mSessionState.mClient.onAdBufferReady(buffer, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onAdBuffer", e);
+ } finally {
+ if (buffer != null) {
+ buffer.getSharedMemory().close();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index c40d72c..6b90181 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1159,9 +1159,10 @@
}
return;
}
+ transition.collect(topFocusedRootTask);
+ executeMultiWindowFullscreenRequest(fullscreenRequest, topFocusedRootTask);
r.mTransitionController.requestStartTransition(transition, topFocusedRootTask,
null /* remoteTransition */, null /* displayChange */);
- executeMultiWindowFullscreenRequest(fullscreenRequest, topFocusedRootTask);
transition.setReady(topFocusedRootTask, true);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0b572df..f35343c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3555,7 +3555,10 @@
mRootWindowContainer.forAllDisplays(displayContent -> {
mKeyguardController.keyguardGoingAway(displayContent.getDisplayId(), flags);
});
- getWallpaperManagerInternal().onKeyguardGoingAway();
+ WallpaperManagerInternal wallpaperManagerInternal = getWallpaperManagerInternal();
+ if (wallpaperManagerInternal != null) {
+ wallpaperManagerInternal.onKeyguardGoingAway();
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index be52e5a..76fd6932 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -184,7 +184,6 @@
private final boolean mCarDockEnablesAccelerometer;
private final boolean mDeskDockEnablesAccelerometer;
- private final boolean mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer;
private final AccessibilityManager mAccessibilityManager;
private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
private final ScreenshotHelper mScreenshotHelper;
@@ -394,8 +393,6 @@
final Resources r = mContext.getResources();
mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
- mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer =
- r.getBoolean(R.bool.config_deskRespectsNoSensorAndLockedWithoutAccelerometer);
mCanSystemBarsBeShownByUser = !r.getBoolean(
R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean(
R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction);
@@ -707,10 +704,6 @@
return mDeskDockEnablesAccelerometer;
}
- boolean isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer() {
- return mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer;
- }
-
public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
mPersistentVrModeEnabled = persistentVrModeEnabled;
}
@@ -2514,8 +2507,6 @@
pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
pw.print(" mDeskDockEnablesAccelerometer=");
pw.println(mDeskDockEnablesAccelerometer);
- pw.print(" mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer=");
- pw.println(mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer);
pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index a3d233d..87de0f6 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -1239,10 +1239,6 @@
mDisplayPolicy.isCarDockEnablesAccelerometer();
final boolean deskDockEnablesAccelerometer =
mDisplayPolicy.isDeskDockEnablesAccelerometer();
- final boolean deskDockRespectsNoSensorAndLockedWithoutAccelerometer =
- mDisplayPolicy.isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer()
- && (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED
- || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
@Surface.Rotation
final int preferredRotation;
@@ -1263,10 +1259,10 @@
|| dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
|| dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
&& (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)
- && !deskDockRespectsNoSensorAndLockedWithoutAccelerometer) {
+ && !(orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED
+ || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)) {
// Ignore sensor when in desk dock unless explicitly enabled.
- // This case can override the behavior of NOSENSOR, and can also
- // enable 180 degree rotation while docked.
+ // This case can enable 180 degree rotation while docked.
preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
} else if (hdmiPlugged && mDemoHdmiRotationLock) {
// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 50bf38b..bfd0d96 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -314,7 +314,6 @@
mLogger.mCreateWallTimeMs = System.currentTimeMillis();
mLogger.mCreateTimeNs = SystemClock.elapsedRealtimeNanos();
- controller.mTransitionTracer.logState(this);
}
@Nullable
@@ -532,7 +531,6 @@
mLogger.mSyncId = mSyncId;
mLogger.mCollectTimeNs = SystemClock.elapsedRealtimeNanos();
- mController.mTransitionTracer.logState(this);
}
/**
@@ -555,7 +553,6 @@
applyReady();
mLogger.mStartTimeNs = SystemClock.elapsedRealtimeNanos();
- mController.mTransitionTracer.logState(this);
mController.updateAnimatingState(mTmpTransaction);
// merge into the next-time the global transaction is applied. This is too-early to set
@@ -1232,7 +1229,6 @@
validateVisibility();
mState = STATE_FINISHED;
- mController.mTransitionTracer.logState(this);
// Rotation change may be deferred while there is a display change transition, so check
// again in case there is a new pending change.
if (hasParticipatedDisplay && !mController.useShellTransitionsRotation()) {
@@ -1261,6 +1257,7 @@
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Aborting Transition: %d", mSyncId);
mState = STATE_ABORT;
+ mLogger.mAbortTimeNs = SystemClock.elapsedRealtimeNanos();
mController.mTransitionTracer.logAbortedTransition(this);
// Syncengine abort will call through to onTransactionReady()
mSyncEngine.abort(mSyncId);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index c9316bf..b697ab1 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -941,7 +941,6 @@
}
mPlayingTransitions.add(transition);
updateRunningRemoteAnimation(transition, true /* isPlaying */);
- mTransitionTracer.logState(transition);
// Sync engine should become idle after this, so the idle listener will check the queue.
}
@@ -1122,7 +1121,6 @@
mLatestOnTopTasksReported.clear();
}
}
- mTransitionTracer.logState(transition);
// This is called during Transition.abort whose codepath will eventually check the queue
// via sync-engine idle.
}
@@ -1416,12 +1414,11 @@
long mReadyTimeNs;
long mSendTimeNs;
long mFinishTimeNs;
+ long mAbortTimeNs;
TransitionRequestInfo mRequest;
WindowContainerTransaction mStartWCT;
int mSyncId;
TransitionInfo mInfo;
- ProtoOutputStream mProtoOutputStream = new ProtoOutputStream();
- long mProtoToken;
private String buildOnSendLog() {
StringBuilder sb = new StringBuilder("Sent Transition #").append(mSyncId)
diff --git a/services/core/java/com/android/server/wm/TransitionTracer.java b/services/core/java/com/android/server/wm/TransitionTracer.java
index 6aac81b..afc1492 100644
--- a/services/core/java/com/android/server/wm/TransitionTracer.java
+++ b/services/core/java/com/android/server/wm/TransitionTracer.java
@@ -50,10 +50,11 @@
private static final int ALWAYS_ON_TRACING_CAPACITY = 15 * 1024; // 15 KB
private static final int ACTIVE_TRACING_BUFFER_CAPACITY = 5000 * 1024; // 5 MB
static final String WINSCOPE_EXT = ".winscope";
- private static final String TRACE_FILE = "/data/misc/wmtrace/transition_trace" + WINSCOPE_EXT;
+ private static final String TRACE_FILE =
+ "/data/misc/wmtrace/wm_transition_trace" + WINSCOPE_EXT;
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
- private final TransitionTraceBuffer mTraceBuffer = new TransitionTraceBuffer();
+ private final TraceBuffer mTraceBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY);
private final Object mEnabledLock = new Object();
private volatile boolean mActiveTracingEnabled = false;
@@ -72,18 +73,22 @@
*/
public void logSentTransition(Transition transition, ArrayList<ChangeInfo> targets,
TransitionInfo info) {
- // Dump the info to proto that will not be available when the transition finishes or
- // is canceled
- final ProtoOutputStream outputStream = transition.mLogger.mProtoOutputStream;
- transition.mLogger.mProtoToken = outputStream
- .start(com.android.server.wm.shell.TransitionTraceProto.FINISHED_TRANSITIONS);
+ final ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long protoToken = outputStream
+ .start(com.android.server.wm.shell.TransitionTraceProto.TRANSITIONS);
+ outputStream.write(com.android.server.wm.shell.Transition.ID, transition.getSyncId());
+ outputStream.write(com.android.server.wm.shell.Transition.CREATE_TIME_NS,
+ transition.mLogger.mCreateTimeNs);
+ outputStream.write(com.android.server.wm.shell.Transition.SEND_TIME_NS,
+ transition.mLogger.mSendTimeNs);
outputStream.write(com.android.server.wm.shell.Transition.START_TRANSACTION_ID,
transition.getStartTransaction().getId());
outputStream.write(com.android.server.wm.shell.Transition.FINISH_TRANSACTION_ID,
transition.getFinishTransaction().getId());
dumpTransitionTargetsToProto(outputStream, transition, targets);
+ outputStream.end(protoToken);
- logTransitionInfo(transition, info);
+ mTraceBuffer.add(outputStream);
}
/**
@@ -93,17 +98,15 @@
* @param transition The transition that has finished.
*/
public void logFinishedTransition(Transition transition) {
- if (transition.mLogger.mProtoToken == 0) {
- // Transition finished but never sent, so open token never added
- final ProtoOutputStream outputStream = transition.mLogger.mProtoOutputStream;
- transition.mLogger.mProtoToken = outputStream
- .start(com.android.server.wm.shell.TransitionTraceProto.FINISHED_TRANSITIONS);
- }
+ final ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long protoToken = outputStream
+ .start(com.android.server.wm.shell.TransitionTraceProto.TRANSITIONS);
+ outputStream.write(com.android.server.wm.shell.Transition.ID, transition.getSyncId());
+ outputStream.write(com.android.server.wm.shell.Transition.FINISH_TIME_NS,
+ transition.mLogger.mFinishTimeNs);
+ outputStream.end(protoToken);
- // Dump the rest of the transition's info that wasn't dumped during logSentTransition
- dumpFinishedTransitionToProto(transition.mLogger.mProtoOutputStream, transition);
- transition.mLogger.mProtoOutputStream.end(transition.mLogger.mProtoToken);
- mTraceBuffer.pushTransitionProto(transition.mLogger.mProtoOutputStream);
+ mTraceBuffer.add(outputStream);
}
/**
@@ -113,38 +116,15 @@
* @param transition The transition that has been aborted
*/
public void logAbortedTransition(Transition transition) {
- // We don't care about aborted transitions unless actively tracing
- if (!mActiveTracingEnabled) {
- return;
- }
- logFinishedTransition(transition);
- }
-
- /**
- * Records the current state of a transition in the transition trace (if it is running).
- * @param transition the transition that we want to record the state of.
- */
- public void logState(com.android.server.wm.Transition transition) {
- if (!mActiveTracingEnabled) {
- return;
- }
final ProtoOutputStream outputStream = new ProtoOutputStream();
- dumpTransitionStateToProto(outputStream, transition);
- mTraceBuffer.pushTransitionState(outputStream);
- }
+ final long protoToken = outputStream
+ .start(com.android.server.wm.shell.TransitionTraceProto.TRANSITIONS);
+ outputStream.write(com.android.server.wm.shell.Transition.ID, transition.getSyncId());
+ outputStream.write(com.android.server.wm.shell.Transition.ABORT_TIME_NS,
+ transition.mLogger.mAbortTimeNs);
+ outputStream.end(protoToken);
- /**
- * Records the transition info that is being sent over to Shell.
- * @param transition The transition the info is associated with.
- * @param info The transition info we want to log.
- */
- private void logTransitionInfo(Transition transition, TransitionInfo info) {
- if (!mActiveTracingEnabled) {
- return;
- }
- final ProtoOutputStream outputStream = new ProtoOutputStream();
- dumpTransitionInfoToProto(outputStream, transition, info);
- mTraceBuffer.pushTransitionInfo(outputStream);
+ mTraceBuffer.add(outputStream);
}
private void dumpTransitionTargetsToProto(ProtoOutputStream outputStream,
@@ -189,139 +169,6 @@
Trace.endSection();
}
- private void dumpFinishedTransitionToProto(
- ProtoOutputStream outputStream,
- Transition transition
- ) {
- Trace.beginSection("TransitionTracer#dumpFinishedTransitionToProto");
-
- outputStream.write(com.android.server.wm.shell.Transition.CREATE_TIME_NS,
- transition.mLogger.mCreateTimeNs);
- outputStream.write(com.android.server.wm.shell.Transition.SEND_TIME_NS,
- transition.mLogger.mSendTimeNs);
- outputStream.write(com.android.server.wm.shell.Transition.FINISH_TIME_NS,
- transition.mLogger.mFinishTimeNs);
-
- Trace.endSection();
- }
-
- private void dumpTransitionStateToProto(ProtoOutputStream outputStream, Transition transition) {
- Trace.beginSection("TransitionTracer#dumpTransitionStateToProto");
-
- final long stateToken = outputStream
- .start(com.android.server.wm.shell.TransitionTraceProto.TRANSITION_STATES);
-
- outputStream.write(com.android.server.wm.shell.TransitionState.TIME_NS,
- SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.server.wm.shell.TransitionState.TRANSITION_ID,
- transition.getSyncId());
- outputStream.write(com.android.server.wm.shell.TransitionState.TRANSITION_TYPE,
- transition.mType);
- outputStream.write(com.android.server.wm.shell.TransitionState.STATE,
- transition.getState());
- outputStream.write(com.android.server.wm.shell.TransitionState.FLAGS,
- transition.getFlags());
-
- for (int i = 0; i < transition.mChanges.size(); ++i) {
- final WindowContainer window = transition.mChanges.keyAt(i);
- final ChangeInfo changeInfo = transition.mChanges.valueAt(i);
- dumpChangeInfoToProto(outputStream, window, changeInfo);
- }
-
- for (int i = 0; i < transition.mParticipants.size(); ++i) {
- final WindowContainer window = transition.mParticipants.valueAt(i);
- window.writeIdentifierToProto(outputStream,
- com.android.server.wm.shell.TransitionState.PARTICIPANTS);
- }
-
- outputStream.end(stateToken);
- Trace.endSection();
- }
-
- private void dumpChangeInfoToProto(ProtoOutputStream outputStream, WindowContainer window,
- ChangeInfo changeInfo) {
- Trace.beginSection("TransitionTraceBuffer#writeChange");
- final long changeEntryToken =
- outputStream.start(com.android.server.wm.shell.TransitionState.CHANGE);
-
- final int transitMode = changeInfo.getTransitMode(window);
- final boolean hasChanged = changeInfo.hasChanged();
- final int changeFlags = changeInfo.getChangeFlags(window);
- final int windowingMode = changeInfo.mWindowingMode;
-
- outputStream.write(com.android.server.wm.shell.ChangeInfo.TRANSIT_MODE, transitMode);
- outputStream.write(com.android.server.wm.shell.ChangeInfo.HAS_CHANGED, hasChanged);
- outputStream.write(com.android.server.wm.shell.ChangeInfo.CHANGE_FLAGS, changeFlags);
- outputStream.write(com.android.server.wm.shell.ChangeInfo.WINDOWING_MODE, windowingMode);
- window.writeIdentifierToProto(
- outputStream, com.android.server.wm.shell.ChangeInfo.WINDOW_IDENTIFIER);
-
- outputStream.end(changeEntryToken);
- Trace.endSection();
- }
-
- private void dumpTransitionInfoToProto(ProtoOutputStream outputStream,
- Transition transition, TransitionInfo info) {
- Trace.beginSection("TransitionTracer#dumpTransitionInfoToProto");
- final long transitionInfoToken = outputStream
- .start(com.android.server.wm.shell.TransitionTraceProto.TRANSITION_INFO);
-
- outputStream.write(com.android.server.wm.shell.TransitionInfo.TRANSITION_ID,
- transition.getSyncId());
- for (int i = 0; i < info.getChanges().size(); ++i) {
- TransitionInfo.Change change = info.getChanges().get(i);
- dumpTransitionInfoChangeToProto(outputStream, change);
- }
-
- outputStream.end(transitionInfoToken);
- Trace.endSection();
- }
-
- private void dumpTransitionInfoChangeToProto(
- ProtoOutputStream outputStream,
- TransitionInfo.Change change
- ) {
- Trace.beginSection("TransitionTracer#dumpTransitionInfoChangeToProto");
- final long changeEntryToken = outputStream
- .start(com.android.server.wm.shell.TransitionInfo.CHANGE);
-
- outputStream.write(com.android.server.wm.shell.TransitionInfoChange.LAYER_ID,
- change.getLeash().getLayerId());
- outputStream.write(com.android.server.wm.shell.TransitionInfoChange.MODE, change.getMode());
-
- outputStream.end(changeEntryToken);
- Trace.endSection();
- }
-
- private class TransitionTraceBuffer {
- private final TraceBuffer mTransitionBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY);
- private final TraceBuffer mStateBuffer = new TraceBuffer(ACTIVE_TRACING_BUFFER_CAPACITY);
- private final TraceBuffer mTransitionInfoBuffer =
- new TraceBuffer(ACTIVE_TRACING_BUFFER_CAPACITY);
-
- private void pushTransitionProto(ProtoOutputStream outputStream) {
- mTransitionBuffer.add(outputStream);
- }
-
- private void pushTransitionState(ProtoOutputStream outputStream) {
- mStateBuffer.add(outputStream);
- }
-
- private void pushTransitionInfo(ProtoOutputStream outputStream) {
- mTransitionInfoBuffer.add(outputStream);
- }
-
- public void writeToFile(File file, ProtoOutputStream proto) throws IOException {
- mTransitionBuffer.writeTraceToFile(file, proto);
- }
-
- public void reset() {
- mTransitionBuffer.resetBuffer();
- mStateBuffer.resetBuffer();
- mTransitionInfoBuffer.resetBuffer();
- }
- }
-
/**
* Starts collecting transitions for the trace.
* If called while a trace is already running, this will reset the trace.
@@ -335,8 +182,8 @@
LogAndPrintln.i(pw, "Starting shell transition trace.");
synchronized (mEnabledLock) {
mActiveTracingEnabled = true;
- mTraceBuffer.mTransitionBuffer.setCapacity(ACTIVE_TRACING_BUFFER_CAPACITY);
- mTraceBuffer.reset();
+ mTraceBuffer.resetBuffer();
+ mTraceBuffer.setCapacity(ACTIVE_TRACING_BUFFER_CAPACITY);
}
Trace.endSection();
}
@@ -364,8 +211,8 @@
synchronized (mEnabledLock) {
mActiveTracingEnabled = false;
writeTraceToFileLocked(pw, outputFile);
- mTraceBuffer.reset();
- mTraceBuffer.mTransitionBuffer.setCapacity(ALWAYS_ON_TRACING_CAPACITY);
+ mTraceBuffer.resetBuffer();
+ mTraceBuffer.setCapacity(ALWAYS_ON_TRACING_CAPACITY);
}
Trace.endSection();
}
@@ -404,7 +251,7 @@
int pid = android.os.Process.myPid();
LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
+ " from process " + pid);
- mTraceBuffer.writeToFile(file, proto);
+ mTraceBuffer.writeTraceToFile(file, proto);
} catch (IOException e) {
LogAndPrintln.e(pw, "Unable to write buffer to file", e);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 3ccf183..829a33d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3592,11 +3592,11 @@
&& !mTransitionController.useShellTransitionsRotation()) {
if (deltaRotation != Surface.ROTATION_0) {
updateSurfaceRotation(t, deltaRotation, null /* positionLeash */);
- t.setFixedTransformHint(mSurfaceControl,
+ getPendingTransaction().setFixedTransformHint(mSurfaceControl,
getWindowConfiguration().getDisplayRotation());
} else if (deltaRotation != mLastDeltaRotation) {
t.setMatrix(mSurfaceControl, 1, 0, 0, 1);
- t.unsetFixedTransformHint(mSurfaceControl);
+ getPendingTransaction().unsetFixedTransformHint(mSurfaceControl);
}
}
mLastDeltaRotation = deltaRotation;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 4c5efef..31afcbf 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -596,7 +596,8 @@
.build();
t.setPosition(leash, mLastSurfacePosition.x, mLastSurfacePosition.y);
t.reparent(getSurfaceControl(), leash);
- t.setFixedTransformHint(leash, getWindowConfiguration().getDisplayRotation());
+ getPendingTransaction().setFixedTransformHint(leash,
+ getWindowConfiguration().getDisplayRotation());
mFixedRotationTransformLeash = leash;
updateSurfaceRotation(t, rotation, mFixedRotationTransformLeash);
return mFixedRotationTransformLeash;
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 8728c3c..86dbe11 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -482,7 +482,7 @@
callback,
request,
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
- getEnabledProviders(),
+ getEnabledProvidersForUser(userId),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
addSessionLocked(userId, session);
@@ -537,7 +537,7 @@
getCredentialCallback,
request,
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
- getEnabledProviders(),
+ getEnabledProvidersForUser(userId),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan,
prepareGetCredentialCallback);
@@ -655,7 +655,7 @@
request,
callback,
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
- getEnabledProviders(),
+ getEnabledProvidersForUser(userId),
getPrimaryProvidersForUserId(getContext(), userId),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
@@ -726,10 +726,13 @@
"setEnabledProviders",
null);
+ Set<String> enableProvider = new HashSet<>(providers);
+ enableProvider.addAll(primaryProviders);
+
boolean writeEnabledStatus =
Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.CREDENTIAL_SERVICE,
- String.join(":", providers),
+ String.join(":", enableProvider),
userId);
boolean writePrimaryStatus =
@@ -804,7 +807,7 @@
verifyGetProvidersPermission();
return CredentialProviderInfoFactory.getCredentialProviderServices(
- mContext, userId, providerFilter, getEnabledProviders(),
+ mContext, userId, providerFilter, getEnabledProvidersForUser(userId),
getPrimaryProvidersForUserId(mContext, userId));
}
@@ -815,7 +818,7 @@
final int userId = UserHandle.getCallingUserId();
return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting(
- mContext, userId, providerFilter, getEnabledProviders(),
+ mContext, userId, providerFilter, getEnabledProvidersForUser(userId),
getPrimaryProvidersForUserId(mContext, userId));
}
@@ -832,24 +835,26 @@
}
}
- @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
- // this.mLock
- private Set<ComponentName> getEnabledProviders() {
+ private Set<ComponentName> getEnabledProvidersForUser(int userId) {
+ final int resolvedUserId = ActivityManager.handleIncomingUser(
+ Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, false,
+ "getEnabledProvidersForUser", null);
+
Set<ComponentName> enabledProviders = new HashSet<>();
- synchronized (mLock) {
- runForUser(
- (service) -> {
- try {
- enabledProviders.add(
- service.getCredentialProviderInfo()
- .getServiceInfo().getComponentName());
- } catch (NullPointerException e) {
- // Safe check
- Slog.e(TAG, "Skipping provider as either the providerInfo"
- + " or serviceInfo is null - weird");
- }
- });
+ String directValue = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(), Settings.Secure.CREDENTIAL_SERVICE, resolvedUserId);
+
+ if (!TextUtils.isEmpty(directValue)) {
+ String[] components = directValue.split(":");
+ for (String componentString : components) {
+ ComponentName component = ComponentName.unflattenFromString(componentString);
+ if (component != null) {
+ enabledProviders.add(component);
+ }
+ }
}
+
return enabledProviders;
}
@@ -879,7 +884,7 @@
callback,
request,
constructCallingAppInfo(callingPackage, userId, null),
- getEnabledProviders(),
+ getEnabledProvidersForUser(userId),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
addSessionLocked(userId, session);
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 1503410..e9fa883 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest;
@@ -52,11 +53,22 @@
CancellationSignal cancellationSignal,
long startedTimestamp) {
super(context, sessionCallback, lock, userId, callingUid, request, callback,
- RequestInfo.TYPE_GET, callingAppInfo, enabledProviders, cancellationSignal,
- startedTimestamp);
+ getRequestInfoFromRequest(request), callingAppInfo, enabledProviders,
+ cancellationSignal, startedTimestamp);
mRequestSessionMetric.collectGetFlowInitialMetricInfo(request);
}
+ private static String getRequestInfoFromRequest(GetCredentialRequest request) {
+ for (CredentialOption option : request.getCredentialOptions()) {
+ if (option.getCredentialRetrievalData().getStringArrayList(
+ CredentialOption
+ .SUPPORTED_ELEMENT_KEYS) != null) {
+ return RequestInfo.TYPE_GET_VIA_REGISTRY;
+ }
+ }
+ return RequestInfo.TYPE_GET;
+ }
+
/**
* Creates a new provider session, and adds it list of providers that are contributing to
* this session.
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index f5e3b86..83e7e93 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -59,7 +59,7 @@
private static final String TAG = "RemoteCredentialService";
/** Timeout for a single request. */
- private static final long TIMEOUT_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
+ private static final long TIMEOUT_REQUEST_MILLIS = 3 * DateUtils.SECOND_IN_MILLIS;
/** Timeout to unbind after the task queue is empty. */
private static final long TIMEOUT_IDLE_SERVICE_CONNECTION_MILLIS =
5 * DateUtils.SECOND_IN_MILLIS;
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
index 1930a48..fd49796 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
@@ -18,11 +18,13 @@
import static android.credentials.ui.RequestInfo.TYPE_CREATE;
import static android.credentials.ui.RequestInfo.TYPE_GET;
+import static android.credentials.ui.RequestInfo.TYPE_GET_VIA_REGISTRY;
import static android.credentials.ui.RequestInfo.TYPE_UNDEFINED;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CREATE_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL_VIA_REGISTRY;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN;
@@ -35,6 +37,8 @@
public enum ApiName {
UNKNOWN(CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN),
GET_CREDENTIAL(CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL),
+ GET_CREDENTIAL_VIA_REGISTRY(
+CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_GET_CREDENTIAL_VIA_REGISTRY),
CREATE_CREDENTIAL(
CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CREATE_CREDENTIAL),
CLEAR_CREDENTIAL(
@@ -52,6 +56,8 @@
CREATE_CREDENTIAL.mInnerMetricCode),
new AbstractMap.SimpleEntry<>(TYPE_GET,
GET_CREDENTIAL.mInnerMetricCode),
+ new AbstractMap.SimpleEntry<>(TYPE_GET_VIA_REGISTRY,
+ GET_CREDENTIAL_VIA_REGISTRY.mInnerMetricCode),
new AbstractMap.SimpleEntry<>(TYPE_UNDEFINED,
CLEAR_CREDENTIAL.mInnerMetricCode)
);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index debfedc..bb3b438 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -23200,6 +23200,8 @@
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEFAULT_SMS,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_INPUT_METHODS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MICROPHONE,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 8030bb7..bac39e0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -265,7 +265,7 @@
// never used, but might need some refactoring to not always assume a non-null
// mechanism.
TRUE_MORE_RESTRICTIVE,
- POLICY_FLAG_LOCAL_ONLY_POLICY,
+ POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
PolicyEnforcerCallbacks::setApplicationHidden,
new BooleanPolicySerializer());
@@ -290,7 +290,7 @@
new AccountTypePolicyKey(
DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY),
TRUE_MORE_RESTRICTIVE,
- POLICY_FLAG_LOCAL_ONLY_POLICY,
+ POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
// Nothing is enforced, we just need to store it
(Boolean value, Context context, Integer userId, PolicyKey policyKey) -> true,
new BooleanPolicySerializer());
@@ -311,7 +311,7 @@
static PolicyDefinition<Set<String>> PERMITTED_INPUT_METHODS = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY),
new MostRecent<>(),
- POLICY_FLAG_LOCAL_ONLY_POLICY,
+ POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
(Set<String> value, Context context, Integer userId, PolicyKey policyKey) -> true,
new StringSetPolicySerializer());
@@ -319,14 +319,14 @@
static PolicyDefinition<Boolean> SCREEN_CAPTURE_DISABLED = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY),
TRUE_MORE_RESTRICTIVE,
- /* flags= */ 0,
+ POLICY_FLAG_INHERITABLE,
PolicyEnforcerCallbacks::setScreenCaptureDisabled,
new BooleanPolicySerializer());
static PolicyDefinition<Boolean> PERSONAL_APPS_SUSPENDED = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY),
new MostRecent<>(),
- POLICY_FLAG_LOCAL_ONLY_POLICY,
+ POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
PolicyEnforcerCallbacks::setPersonalAppsSuspended,
new BooleanPolicySerializer());
@@ -547,7 +547,7 @@
String restriction, int flags) {
String identifier = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
UserRestrictionPolicyKey key = new UserRestrictionPolicyKey(identifier, restriction);
- flags |= POLICY_FLAG_USER_RESTRICTION_POLICY;
+ flags |= (POLICY_FLAG_USER_RESTRICTION_POLICY | POLICY_FLAG_INHERITABLE);
PolicyDefinition<Boolean> definition = new PolicyDefinition<>(
key,
TRUE_MORE_RESTRICTIVE,
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 906cc83..9e37164 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -93,6 +93,9 @@
private static final int PLATFORM_VERSION = 20;
private static final int NEWER_VERSION = 30;
+ private static final int DISALLOW_PRERELEASE = -1;
+ private static final int DISALLOW_RELEASED = -1;
+
@Rule public final Expect expect = Expect.create();
private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename,
@@ -149,8 +152,10 @@
// Don't allow newer pre-release minSdkVersion on pre-release platform.
// APP: Pre-release API 30
// DEV: Pre-release API 20
- verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
- verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
+ DISALLOW_PRERELEASE);
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
+ DISALLOW_PRERELEASE);
}
@Test
@@ -173,21 +178,27 @@
// Don't allow older pre-release minSdkVersion on released platform.
// APP: Pre-release API 10
// DEV: Released API 20
- verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
- verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
+ verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true,
+ DISALLOW_RELEASED);
+ verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true,
+ DISALLOW_RELEASED);
// Don't allow same pre-release minSdkVersion on released platform.
// APP: Pre-release API 20
// DEV: Released API 20
- verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
- verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1);
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true,
+ DISALLOW_RELEASED);
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true,
+ DISALLOW_RELEASED);
// Don't allow newer pre-release minSdkVersion on released platform.
// APP: Pre-release API 30
// DEV: Released API 20
- verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
- verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true,
+ DISALLOW_RELEASED);
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true,
+ DISALLOW_RELEASED);
}
private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
@@ -254,10 +265,10 @@
// Don't allow newer pre-release targetSdkVersion on pre-release platform.
// APP: Pre-release API 30
// DEV: Pre-release API 20
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, false, -1);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, false,
+ DISALLOW_PRERELEASE);
verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
- false, -1
- );
+ false, DISALLOW_PRERELEASE);
// Do allow newer pre-release targetSdkVersion on pre-release platform when
// allowUnknownCodenames is true.
@@ -290,35 +301,35 @@
// Don't allow older pre-release targetSdkVersion on released platform.
// APP: Pre-release API 10
// DEV: Released API 20
- verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, false, -1);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, false,
+ DISALLOW_RELEASED);
verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true,
- false, -1
- );
+ false, DISALLOW_RELEASED);
// Don't allow same pre-release targetSdkVersion on released platform.
// APP: Pre-release API 20
// DEV: Released API 20
- verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, false, -1);
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, false,
+ DISALLOW_RELEASED);
verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, false,
- -1
- );
+ DISALLOW_RELEASED);
// Don't allow same pre-release targetSdkVersion on released platform when
// allowUnknownCodenames is true.
// APP: Pre-release API 20
// DEV: Released API 20
verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, true,
- -1);
+ DISALLOW_RELEASED);
verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, true,
- -1);
+ DISALLOW_RELEASED);
// Don't allow newer pre-release targetSdkVersion on released platform.
// APP: Pre-release API 30
// DEV: Released API 20
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, false, -1);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, false,
+ DISALLOW_RELEASED);
verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true,
- false, -1
- );
+ false, DISALLOW_RELEASED);
// Do allow newer pre-release targetSdkVersion on released platform when
// allowUnknownCodenames is true.
// APP: Pre-release API 30
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 3d963ed..56bd192 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -164,7 +164,7 @@
public void testAttachDetach() throws Exception {
// Normal attachment / detachment.
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
assertNotNull(module);
module.detach();
}
@@ -172,7 +172,7 @@
@Test
public void testLoadUnloadModel() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
final int hwHandle = 7;
int handle = loadGenericModel(module, hwHandle).first;
@@ -183,7 +183,7 @@
@Test
public void testLoadPreemptModel() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
final int hwHandle = 7;
Pair<Integer, SoundTriggerHwCallback> loadResult = loadGenericModel(module, hwHandle);
@@ -202,7 +202,7 @@
@Test
public void testLoadUnloadPhraseModel() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
final int hwHandle = 73;
int handle = loadPhraseModel(module, hwHandle).first;
@@ -213,7 +213,7 @@
@Test
public void testStartStopRecognition() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 7;
@@ -233,7 +233,7 @@
@Test
public void testStartRecognitionBusy() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 7;
@@ -257,7 +257,7 @@
@Test
public void testStartStopPhraseRecognition() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 67;
@@ -277,7 +277,7 @@
@Test
public void testRecognition() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 7;
@@ -322,7 +322,7 @@
@Test
public void testPhraseRecognition() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 7;
@@ -352,7 +352,7 @@
@Test
public void testForceRecognition() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 17;
@@ -389,7 +389,7 @@
@Test
public void testForceRecognitionNotSupported() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 17;
@@ -420,7 +420,7 @@
@Test
public void testForcePhraseRecognition() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 17;
@@ -457,7 +457,7 @@
@Test
public void testForcePhraseRecognitionNotSupported() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 17;
@@ -489,7 +489,7 @@
public void testAbortRecognition() throws Exception {
// Make sure the HAL doesn't support concurrent capture.
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 11;
@@ -521,7 +521,7 @@
public void testAbortPhraseRecognition() throws Exception {
// Make sure the HAL doesn't support concurrent capture.
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
// Load the model.
final int hwHandle = 11;
@@ -552,7 +552,7 @@
@Test
public void testParameterSupported() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
final int hwHandle = 12;
int modelHandle = loadGenericModel(module, hwHandle).first;
@@ -574,7 +574,7 @@
@Test
public void testParameterNotSupported() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
final int hwHandle = 13;
int modelHandle = loadGenericModel(module, hwHandle).first;
@@ -592,7 +592,7 @@
@Test
public void testGetParameter() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
final int hwHandle = 14;
int modelHandle = loadGenericModel(module, hwHandle).first;
@@ -609,7 +609,7 @@
@Test
public void testSetParameter() throws Exception {
ISoundTriggerCallback callback = createCallbackMock();
- ISoundTriggerModule module = mService.attach(0, callback);
+ ISoundTriggerModule module = mService.attach(0, callback, false);
final int hwHandle = 17;
int modelHandle = loadGenericModel(module, hwHandle).first;
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index cc357d7..385c28a 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -20,6 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
@@ -101,8 +102,9 @@
throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback, false);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture(),
+ anyBoolean());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
@@ -116,8 +118,9 @@
public void testOnPhraseRecognitionRestartsActiveSession() throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback, false);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture(),
+ anyBoolean());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
@@ -137,8 +140,9 @@
throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback, false);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture(),
+ anyBoolean());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
RecognitionStatus.ABORTED, 100 /* keyphraseId */);
@@ -154,8 +158,9 @@
throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
ISoundTriggerCallback.class);
- mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback);
- verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
+ mSoundTriggerMiddlewareLogging.attach(0, mISoundTriggerCallback, false);
+ verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture(),
+ anyBoolean());
triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
RecognitionStatus.SUCCESS);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 8e80485..04e1d9c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -940,8 +940,6 @@
@Test
public void testIgnoresDeskDockRotation_whenNoSensorAndLockedRespected() throws Exception {
mBuilder.setDeskDockRotation(Surface.ROTATION_270).build();
- when(mMockDisplayPolicy.isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer())
- .thenReturn(true);
configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_DESK);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 67320009..a675248 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -303,6 +303,10 @@
private SoundTriggerHelper newSoundTriggerHelper(
ModuleProperties moduleProperties, EventLogger eventLogger) {
+ return newSoundTriggerHelper(moduleProperties, eventLogger, false);
+ }
+ private SoundTriggerHelper newSoundTriggerHelper(
+ ModuleProperties moduleProperties, EventLogger eventLogger, boolean isTrusted) {
Identity middlemanIdentity = new Identity();
middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
@@ -325,7 +329,7 @@
eventLogger,
(SoundTrigger.StatusListener statusListener) -> new SoundTriggerModule(
mMiddlewareService, moduleId, statusListener,
- Looper.getMainLooper(), middlemanIdentity, originatorIdentity),
+ Looper.getMainLooper(), middlemanIdentity, originatorIdentity, isTrusted),
moduleId,
() -> listUnderlyingModuleProperties(originatorIdentity)
);
@@ -1724,7 +1728,8 @@
}
@Override
- public Session attach(@NonNull IBinder client, ModuleProperties underlyingModule) {
+ public Session attach(@NonNull IBinder client, ModuleProperties underlyingModule,
+ boolean isTrusted) {
var identity = IdentityContext.getNonNull();
int sessionId = mSessionIdCounter.getAndIncrement();
mServiceEventLogger.enqueue(new ServiceEvent(
@@ -1733,7 +1738,7 @@
"LocalSoundTriggerEventLogger for package: " +
identity.packageName + "#" + sessionId);
- return new SessionImpl(newSoundTriggerHelper(underlyingModule, eventLogger),
+ return new SessionImpl(newSoundTriggerHelper(underlyingModule, eventLogger, isTrusted),
client, eventLogger, identity);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
index 60f89da..ca35b51 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
@@ -38,7 +38,10 @@
*
* listModules() must be called prior to calling this method and the provided handle must be
* one of the handles from the returned list.
+ * @param isTrusted - {@code true} if this service should not note AppOps for recognitions,
+ * and should delegate these checks to the **trusted** client.
*/
public ISoundTriggerModule attach(int handle,
- ISoundTriggerCallback callback);
+ ISoundTriggerCallback callback,
+ boolean isTrusted);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
index c8c0f3d..3b800de 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
@@ -116,7 +116,8 @@
@Override
public @NonNull
- ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback) {
+ ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback,
+ boolean isTrusted) {
return mModules[handle].attach(callback);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index ecd65ae..e3366f8 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -149,22 +149,22 @@
@Override
public @NonNull
- ISoundTriggerModule attach(int handle, ISoundTriggerCallback callback) {
+ ISoundTriggerModule attach(int handle, ISoundTriggerCallback callback, boolean isTrusted) {
try {
var originatorIdentity = IdentityContext.getNonNull();
String packageIdentification = originatorIdentity.packageName
- + mSessionCount.getAndIncrement();
+ + mSessionCount.getAndIncrement() + (isTrusted ? "trusted" : "");
ModuleLogging result = new ModuleLogging();
var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
"Session logger for: " + packageIdentification);
var callbackWrapper = new CallbackLogging(callback, eventLogger, originatorIdentity);
- result.attach(mDelegate.attach(handle, callbackWrapper), eventLogger);
+ result.attach(mDelegate.attach(handle, callbackWrapper, isTrusted), eventLogger);
mServiceEventLogger.enqueue(ServiceEvent.createForReturn(
ServiceEvent.Type.ATTACH,
- packageIdentification, result, handle, callback)
+ packageIdentification, result, handle, callback, isTrusted)
.printLog(ALOGI, TAG));
mSessionEventLoggers.add(eventLogger);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 6b724de..2e641a2 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -85,11 +85,11 @@
@Override
public @NonNull
ISoundTriggerModule attach(int handle,
- @NonNull ISoundTriggerCallback callback) {
+ @NonNull ISoundTriggerCallback callback, boolean isTrusted) {
Identity identity = getIdentity();
enforcePermissionsForPreflight(identity);
- ModuleWrapper wrapper = new ModuleWrapper(identity, callback);
- return wrapper.attach(mDelegate.attach(handle, wrapper.getCallbackWrapper()));
+ ModuleWrapper wrapper = new ModuleWrapper(identity, callback, isTrusted);
+ return wrapper.attach(mDelegate.attach(handle, wrapper.getCallbackWrapper(), isTrusted));
}
// Override toString() in order to have the delegate's ID in it.
@@ -204,11 +204,14 @@
private ISoundTriggerModule mDelegate;
private final @NonNull Identity mOriginatorIdentity;
private final @NonNull CallbackWrapper mCallbackWrapper;
+ private final boolean mIsTrusted;
ModuleWrapper(@NonNull Identity originatorIdentity,
- @NonNull ISoundTriggerCallback callback) {
+ @NonNull ISoundTriggerCallback callback,
+ boolean isTrusted) {
mOriginatorIdentity = originatorIdentity;
mCallbackWrapper = new CallbackWrapper(callback);
+ mIsTrusted = isTrusted;
}
ModuleWrapper attach(@NonNull ISoundTriggerModule delegate) {
@@ -347,7 +350,11 @@
}
private void enforcePermissions(String reason) {
- enforcePermissionsForDataDelivery(mOriginatorIdentity, reason);
+ if (mIsTrusted) {
+ enforcePermissionsForPreflight(mOriginatorIdentity);
+ } else {
+ enforcePermissionsForDataDelivery(mOriginatorIdentity, reason);
+ }
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
index 1558acf..9de2438 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
@@ -105,17 +105,17 @@
public ISoundTriggerModule attachAsOriginator(int handle, Identity identity,
ISoundTriggerCallback callback) {
try (SafeCloseable ignored = establishIdentityDirect(Objects.requireNonNull(identity))) {
- return new ModuleService(mDelegate.attach(handle, callback));
+ return new ModuleService(mDelegate.attach(handle, callback, /* isTrusted= */ false));
}
}
@Override
public ISoundTriggerModule attachAsMiddleman(int handle, Identity middlemanIdentity,
- Identity originatorIdentity, ISoundTriggerCallback callback) {
+ Identity originatorIdentity, ISoundTriggerCallback callback, boolean isTrusted) {
try (SafeCloseable ignored = establishIdentityIndirect(
Objects.requireNonNull(middlemanIdentity),
Objects.requireNonNull(originatorIdentity))) {
- return new ModuleService(mDelegate.attach(handle, callback));
+ return new ModuleService(mDelegate.attach(handle, callback, isTrusted));
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 2924c12..31fab89 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -191,7 +191,7 @@
@Override
public @NonNull ISoundTriggerModule attach(int handle,
- @NonNull ISoundTriggerCallback callback) {
+ @NonNull ISoundTriggerCallback callback, boolean isTrusted) {
// Input validation.
Objects.requireNonNull(callback);
Objects.requireNonNull(callback.asBinder());
@@ -209,7 +209,7 @@
// From here on, every exception isn't client's fault.
try {
Session session = new Session(handle, callback);
- session.attach(mDelegate.attach(handle, session.getCallbackWrapper()));
+ session.attach(mDelegate.attach(handle, session.getCallbackWrapper(), isTrusted));
return session;
} catch (Exception e) {
throw handleException(e);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 27f3fb3..423a81a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -381,51 +381,21 @@
@NonNull Identity originatorIdentity, IBinder client,
ModuleProperties moduleProperties) {
Objects.requireNonNull(originatorIdentity);
- boolean forHotwordDetectionService;
+ boolean forHotwordDetectionService = false;
synchronized (VoiceInteractionManagerServiceStub.this) {
enforceIsCurrentVoiceInteractionService();
forHotwordDetectionService =
mImpl != null && mImpl.mHotwordDetectionConnection != null;
}
- IVoiceInteractionSoundTriggerSession session;
- if (forHotwordDetectionService) {
- // Use our own identity and handle the permission checks ourselves. This allows
- // properly checking/noting against the voice interactor or hotword detection
- // service as needed.
- if (HotwordDetectionConnection.DEBUG) {
- Slog.d(TAG, "Creating a SoundTriggerSession for a HotwordDetectionService");
- }
- originatorIdentity.uid = Binder.getCallingUid();
- originatorIdentity.pid = Binder.getCallingPid();
- session = new SoundTriggerSessionPermissionsDecorator(
- createSoundTriggerSessionForSelfIdentity(client, moduleProperties),
- mContext,
- originatorIdentity);
- } else {
- if (HotwordDetectionConnection.DEBUG) {
- Slog.d(TAG, "Creating a SoundTriggerSession");
- }
- try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
- originatorIdentity)) {
- session = new SoundTriggerSession(mSoundTriggerInternal.attach(client,
- moduleProperties));
- }
+ if (HotwordDetectionConnection.DEBUG) {
+ Slog.d(TAG, "Creating a SoundTriggerSession, for HDS: "
+ + forHotwordDetectionService);
}
- return new SoundTriggerSessionBinderProxy(session);
- }
-
- private IVoiceInteractionSoundTriggerSession createSoundTriggerSessionForSelfIdentity(
- IBinder client, ModuleProperties moduleProperties) {
- Identity identity = new Identity();
- identity.uid = Process.myUid();
- identity.pid = Process.myPid();
- identity.packageName = ActivityThread.currentOpPackageName();
- return Binder.withCleanCallingIdentity(() -> {
- try (SafeCloseable ignored = IdentityContext.create(identity)) {
- return new SoundTriggerSession(
- mSoundTriggerInternal.attach(client, moduleProperties));
- }
- });
+ try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
+ originatorIdentity)) {
+ return new SoundTriggerSession(mSoundTriggerInternal.attach(client,
+ moduleProperties, forHotwordDetectionService));
+ }
}
@Override
@@ -1700,11 +1670,7 @@
return null;
}
- /**
- * Implementation of SoundTriggerSession. Does not implement {@link #asBinder()} as it's
- * intended to be wrapped by an {@link IVoiceInteractionSoundTriggerSession.Stub} object.
- */
- private class SoundTriggerSession implements IVoiceInteractionSoundTriggerSession {
+ private class SoundTriggerSession extends IVoiceInteractionSoundTriggerSession.Stub {
final SoundTriggerInternal.Session mSession;
private IHotwordRecognitionStatusCallback mSessionExternalCallback;
private IRecognitionStatusCallback mSessionInternalCallback;
@@ -1851,12 +1817,6 @@
}
@Override
- public IBinder asBinder() {
- throw new UnsupportedOperationException(
- "This object isn't intended to be used as a Binder.");
- }
-
- @Override
public void detach() {
mSession.detach();
}
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index b003f59..331caa1 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -43,8 +43,8 @@
/** Disconnected because of a local user-initiated action, such as hanging up. */
public static final int LOCAL = TelecomProtoEnums.LOCAL; // = 2
/**
- * Disconnected because of a remote user-initiated action, such as the other party hanging up
- * up.
+ * Disconnected because the remote party hung up an ongoing call, or because an outgoing call
+ * was not answered by the remote party.
*/
public static final int REMOTE = TelecomProtoEnums.REMOTE; // = 3
/** Disconnected because it has been canceled. */
diff --git a/tests/SilkFX/res/layout/gainmap_metadata.xml b/tests/SilkFX/res/layout/gainmap_metadata.xml
index 0dabaca..4cc3e0c 100644
--- a/tests/SilkFX/res/layout/gainmap_metadata.xml
+++ b/tests/SilkFX/res/layout/gainmap_metadata.xml
@@ -21,8 +21,8 @@
android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="350dp"
- android:layout_height="300dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="8dp"
android:orientation="vertical"
diff --git a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
index 6a8752a..501b9d3 100644
--- a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
+++ b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
@@ -79,6 +79,16 @@
.isEqualTo(oldCount + 1)
}
+ @Test
+ fun reportUserMayRequestUnlock_differentUserId_doesNotPropagateToAgent() {
+ val oldCount = trustAgentRule.agent.onUserMayRequestUnlockCallCount
+ trustManager.reportUserMayRequestUnlock(userId + 1)
+ await()
+
+ assertThat(trustAgentRule.agent.onUserMayRequestUnlockCallCount)
+ .isEqualTo(oldCount)
+ }
+
companion object {
private const val TAG = "UserUnlockRequestTest"
private fun await() = Thread.sleep(250)
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 2ce2167..1b1e93bd 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -209,6 +209,11 @@
AddOptionalFlag("--compile-sdk-version-name",
"Version name to inject into the AndroidManifest.xml if none is present.",
&options_.manifest_fixer_options.compile_sdk_version_codename);
+ AddOptionalSwitch(
+ "--no-compile-sdk-metadata",
+ "Suppresses output of compile SDK-related attributes in AndroidManifest.xml,\n"
+ "including android:compileSdkVersion and platformBuildVersion.",
+ &options_.manifest_fixer_options.no_compile_sdk_metadata);
AddOptionalFlagList("--fingerprint-prefix", "Fingerprint prefix to add to install constraints.",
&options_.manifest_fixer_options.fingerprint_prefixes);
AddOptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 53f0abe..c4f6e70 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -719,7 +719,7 @@
root->InsertChild(0, std::move(uses_sdk));
}
- if (options_.compile_sdk_version) {
+ if (!options_.no_compile_sdk_metadata && options_.compile_sdk_version) {
xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
// Make sure we un-compile the value if it was set to something else.
@@ -731,10 +731,9 @@
// Make sure we un-compile the value if it was set to something else.
attr->compiled_value = {};
attr->value = options_.compile_sdk_version.value();
-
}
- if (options_.compile_sdk_version_codename) {
+ if (!options_.no_compile_sdk_metadata && options_.compile_sdk_version_codename) {
xml::Attribute* attr =
root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index 175ab6f..42938a4 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -67,11 +67,12 @@
std::optional<std::string> revision_code_default;
// The version of the framework being compiled against to set for 'android:compileSdkVersion' in
- // the <manifest> tag.
+ // the <manifest> tag. Not used if no_compile_sdk_metadata is set.
std::optional<std::string> compile_sdk_version;
// The version codename of the framework being compiled against to set for
- // 'android:compileSdkVersionCodename' in the <manifest> tag.
+ // 'android:compileSdkVersionCodename' in the <manifest> tag. Not used if no_compile_sdk_metadata
+ // is set.
std::optional<std::string> compile_sdk_version_codename;
// The fingerprint prefixes to be added to the <install-constraints> tag.
@@ -87,6 +88,9 @@
// Whether to replace the manifest version with the the command line version
bool replace_version = false;
+
+ // Whether to suppress `android:compileSdkVersion*` and `platformBuildVersion*` attributes.
+ bool no_compile_sdk_metadata = false;
};
// Verifies that the manifest is correctly formed and inserts defaults where specified with
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 1b8f05b..6151a8e 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -892,6 +892,35 @@
EXPECT_THAT(attr->value, StrEq("P"));
}
+TEST_F(ManifestFixerTest, DoNotInsertCompileSdkVersions) {
+ std::string input = R"(<manifest package="com.pkg" />)";
+ ManifestFixerOptions options;
+ options.no_compile_sdk_metadata = true;
+ options.compile_sdk_version = {"28"};
+ options.compile_sdk_version_codename = {"P"};
+
+ std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+ ASSERT_THAT(manifest, NotNull());
+
+ // There should be a declaration of kSchemaAndroid, even when the input
+ // didn't have one.
+ EXPECT_EQ(manifest->root->namespace_decls.size(), 1);
+ EXPECT_EQ(manifest->root->namespace_decls[0].prefix, "android");
+ EXPECT_EQ(manifest->root->namespace_decls[0].uri, xml::kSchemaAndroid);
+
+ xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion");
+ ASSERT_THAT(attr, IsNull());
+
+ attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
+ ASSERT_THAT(attr, IsNull());
+
+ attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+ ASSERT_THAT(attr, IsNull());
+
+ attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+ ASSERT_THAT(attr, IsNull());
+}
+
TEST_F(ManifestFixerTest, OverrideCompileSdkVersions) {
std::string input = R"(
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"