diff options
93 files changed, 973 insertions, 596 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java index ce381b6699ea..e08200b055d8 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.ActivityManagerInternal.AppBackgroundRestrictionListener; 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.IAppOpsCallback; 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 @@ import java.util.Set; 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 @@ public class AppStateTrackerImpl implements AppStateTracker { } 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 c5405171edd0..0a7bffc786cc 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.GuardedBy; 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 @@ public final class JobStore { /** 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 @@ public final class JobStore { 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 @@ public final class JobStore { 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 @@ public final class JobStore { * @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 @@ public final class JobStore { */ @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 @@ public final class JobStore { } return false; } + mCurrentJobSetSize--; if (removeFromPersisted && jobStatus.isPersisted()) { mPendingJobWriteUids.put(jobStatus.getUid(), true); maybeWriteStatusToDiskAsync(); @@ -315,7 +352,9 @@ public final class JobStore { */ @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 final class JobStore { */ 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 final class JobStore { public void clear() { mJobSet.clear(); mPendingJobWriteUids.put(ALL_UIDS, true); + mCurrentJobSetSize = 0; maybeWriteStatusToDiskAsync(); } @@ -352,6 +393,7 @@ public final class JobStore { public void clearForTesting() { mJobSet.clear(); mPendingJobWriteUids.put(ALL_UIDS, true); + mCurrentJobSetSize = 0; } void setUseSplitFiles(boolean useSplitFiles) { @@ -442,6 +484,12 @@ public final class JobStore { 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 @@ public final class JobStore { 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/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 9e59ee496de1..0e5cbe228c1b 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -60,13 +60,16 @@ import android.os.RemoteCallback; 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 @@ import java.util.function.Supplier; */ @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 @@ public class AppOpsManager { */ @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 @@ public class AppOpsManager { @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 @@ public class AppOpsManager { } } + 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 @@ public class AppOpsManager { @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/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java index 069c264313e7..dcf1a47c3f70 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -1136,7 +1136,10 @@ public final class SQLiteConnectionPool implements Closeable { 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/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index 301b412e6ce2..bfff4dbdd627 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -2306,7 +2306,7 @@ public class SoundTrigger { 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 48d4ea40fecd..8813a17c504b 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -83,7 +83,8 @@ public class SoundTriggerModule { */ 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 @@ public class SoundTriggerModule { 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 2c31e32f2ef8..94971b8654ee 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -107,42 +107,22 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { } 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 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { * 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 @@ public class GraphicsEnvironment { String packageName) { if (!shouldUseAngle(context, bundle, packageName)) { - setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver); return false; } @@ -655,13 +566,13 @@ public class GraphicsEnvironment { // 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 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { 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 @@ public class GraphicsEnvironment { + 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 @@ public class GraphicsEnvironment { 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/provider/CallLog.java b/core/java/android/provider/CallLog.java index 77c00676878c..ac6b2b23cdf5 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -1293,7 +1293,8 @@ public class CallLog { 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 class CallLog { 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/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index 617519b1b540..fdcb87ff5e3f 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -1468,6 +1468,11 @@ public class BatteryStatsHistory { 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 @@ public class BatteryStatsHistory { 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 @@ public class BatteryStatsHistory { 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 d9152d61ed8a..01dbceb38d3a 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -50,7 +50,7 @@ void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName, } 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 @@ void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appNa } 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 @@ const JNINativeMethod g_methods[] = { {"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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index fefa79f65201..7e0a36d30771 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 7de36a7113ae..6f7bc53e891c 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/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index e8014af463bd..adc0c9c4322a 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 @@ public class BubbleExpandedView extends LinearLayout { 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 e7dede757578..2832c553c20c 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange /** 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 838e37a905db..2bbd870f024d 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.ShellController; 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.Set; 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 @@ public class CompatUIController implements OnDisplaysChangedListener, 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 @@ public class CompatUIController implements OnDisplaysChangedListener, 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 659229228a57..d4778fa7a58a 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_APPLIED; 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 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { 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 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { 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 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { @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 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { /** 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 9c4e79cd631b..180498c50c78 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.PACK 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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana 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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana 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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana } /** + * @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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana @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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana 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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana 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 959c50d5c640..9a67258ded2e 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 @@ package com.android.wm.shell.compatui; 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 @@ class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { @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 @@ class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { 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 @@ class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { mLayout.setDismissOnClickListener(null); mAnimationController.startExitAnimation(mLayout, () -> { release(); - mOnDismissCallback.accept(Pair.create(mTaskInfo, getTaskListener())); + mOnDismissCallback.accept(Pair.create(getLastTaskInfo(), getTaskListener())); }); } @@ -210,7 +205,6 @@ class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { @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 a18ab9154e01..95bb1fe1c986 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_FOCUSABLE; 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 @@ class ReachabilityEduWindowManager extends CompatUIWindowManagerAbstract { private final ShellExecutor mMainExecutor; - @NonNull - private TaskInfo mTaskInfo; - private boolean mIsActivityLetterboxed; private int mLetterboxVerticalPosition; @@ -86,7 +82,6 @@ class ReachabilityEduWindowManager extends CompatUIWindowManagerAbstract { 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 @@ class ReachabilityEduWindowManager extends CompatUIWindowManagerAbstract { @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 @@ class ReachabilityEduWindowManager extends CompatUIWindowManagerAbstract { 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 @@ class ReachabilityEduWindowManager extends CompatUIWindowManagerAbstract { 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 51e5141a28af..a770da28fbd1 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 @@ package com.android.wm.shell.compatui; 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 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { */ private final int mDialogVerticalMargin; - @NonNull - private TaskInfo mTaskInfo; - @Nullable @VisibleForTesting RestartDialogLayout mLayout; @@ -95,7 +91,6 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { DialogAnimationController<RestartDialogLayout> animationController, CompatUIConfiguration compatUIConfiguration) { super(context, taskInfo, syncQueue, taskListener, displayLayout); - mTaskInfo = taskInfo; mTransitions = transitions; mOnDismissCallback = onDismissCallback; mOnRestartCallback = onRestartCallback; @@ -125,7 +120,7 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { 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 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { 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 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { // Dialog has already been released. return; } + final TaskInfo lastTaskInfo = getLastTaskInfo(); mLayout.setDismissOnClickListener(this::onDismiss); mLayout.setRestartOnClickListener(dontShowAgain -> { if (mLayout != null) { @@ -200,9 +184,9 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { }); } 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 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { 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/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index b3109388da2c..9de9855720bc 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.TransitionRequestInfo 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.ShellController 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 @@ class DesktopTasksController( } 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 @@ class DesktopTasksController( /** 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, "showDesktopApps") val wct = WindowContainerTransaction() // TODO(b/278084491): pass in display id bringDesktopAppsToFront(displayId, wct) @@ -130,7 +130,7 @@ class DesktopTasksController( /** 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, "moveToDesktop: %d", task.taskId) val wct = WindowContainerTransaction() // Bring other apps to front first @@ -190,7 +190,7 @@ class DesktopTasksController( /** 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, "moveToFullscreen: %d", task.taskId) val wct = WindowContainerTransaction() addMoveToFullscreenChanges(wct, task.token) @@ -255,10 +255,10 @@ class DesktopTasksController( 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 +269,7 @@ class DesktopTasksController( 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 +281,17 @@ class DesktopTasksController( * 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 +316,7 @@ class DesktopTasksController( } private fun bringDesktopAppsToFront(displayId: Int, wct: WindowContainerTransaction) { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront") + KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront") val activeTasks = desktopModeTaskRepository.getActiveTasks(displayId) // First move home to front and then other tasks on top of it @@ -397,7 +397,7 @@ class DesktopTasksController( 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," + " taskId=%d", @@ -414,7 +414,7 @@ class DesktopTasksController( // 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," + " taskId=%d", 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 24d0b996a3cb..f51eb5299dd9 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 @@ public class PipBoundsAlgorithm { 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 6cedcf534f3b..363d6759f8d0 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 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, "%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 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } /** - * 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 98db707d1105..6b8108a50589 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 @@ public class PipTransition extends PipTransitionController { 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 5c2f1438c08e..b8373f3548ca 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } 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/util/KtProtoLog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt new file mode 100644 index 000000000000..9b48a542720c --- /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/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java index 4de529885565..55781f1b4d6f 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 static org.mockito.Mockito.verify; 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 @@ public class CompatUIWindowManagerTest extends ShellTestCase { 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 5bcc72e73cb9..973a99c269ea 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 static org.junit.Assert.assertNull; 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.TestShellExecutor; 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 @@ import org.mockito.MockitoAnnotations; @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(windowManager.createLayout(/* canShow= */ true)); + assertFalse(mWindowManager.createLayout(/* canShow= */ true)); - assertNull(windowManager.mLayout); + assertNull(mWindowManager.mLayout); } - private ReachabilityEduWindowManager createReachabilityEduWindowManager(TaskInfo taskInfo) { - return new ReachabilityEduWindowManager(mContext, taskInfo, mSyncTransactionQueue, - mTaskListener, mDisplayLayout, mCompatUIConfiguration, mExecutor); + @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)); } - private static TaskInfo createTaskInfo(int userId, boolean isLetterboxDoubleTapEnabled) { - return createTaskInfo(userId, /* isLetterboxDoubleTapEnabled */ isLetterboxDoubleTapEnabled, - /* topActivityLetterboxVerticalPosition */ -1, - /* topActivityLetterboxHorizontalPosition */ -1, - /* topActivityLetterboxWidth */ -1, - /* topActivityLetterboxHeight */ -1); + @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 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; + private ReachabilityEduWindowManager createReachabilityEduWindowManager(TaskInfo taskInfo) { + return new ReachabilityEduWindowManager(mContext, taskInfo, mSyncTransactionQueue, + mTaskListener, mDisplayLayout, mCompatUIConfiguration, mExecutor); } } 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 000000000000..9f109a1d0f50 --- /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/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl index 531b3ae0c230..bc6a2591f386 100644 --- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl +++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl @@ -80,14 +80,16 @@ interface ISoundTriggerMiddlewareService { * 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 0289aa3b203d..3394dd05ef8c 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategy.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java @@ -203,10 +203,16 @@ public final class AudioProductStrategy implements Parcelable { 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 @@ public final class AudioProductStrategy implements Parcelable { && 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/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java index b66545a6558e..266faae489dd 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.AudioManager; 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 @@ public class AudioProductStrategyTest { } } } + + @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/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp index e9000a8e4b0f..df43863fdd84 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp @@ -27,6 +27,7 @@ android_library { "//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 d26ad1c77f1b..e6fb720ba27f 100644 --- a/packages/SettingsLib/SettingsTheme/Android.bp +++ b/packages/SettingsLib/SettingsTheme/Android.bp @@ -16,6 +16,7 @@ android_library { 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 0f9f7816d1dd..48cc75d41285 100644 --- a/packages/SettingsLib/SettingsTransition/Android.bp +++ b/packages/SettingsLib/SettingsTransition/Android.bp @@ -22,6 +22,7 @@ android_library { "//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/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp index eca116586fbe..5d09a1a926d8 100644 --- a/packages/SettingsLib/TopIntroPreference/Android.bp +++ b/packages/SettingsLib/TopIntroPreference/Android.bp @@ -23,6 +23,7 @@ android_library { 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 33ba64ac2cb7..dc2b52d24462 100644 --- a/packages/SettingsLib/Utils/Android.bp +++ b/packages/SettingsLib/Utils/Android.bp @@ -25,6 +25,7 @@ android_library { "//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 e9aded0838d9..2372c802168c 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/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index adaf4a1d3ab5..c45d77471932 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 @@ public class WifiStatusTracker { } @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 @@ public class WifiStatusTracker { } @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 @@ public class WifiStatusTracker { 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 6e975cf9d8f3..5a9a9d154070 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 @@ public class WifiStatusTrackerTest { 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 29832a081612..f050a1ef0f39 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 745470f4c61a..9492472a2be1 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 36083f1f0408..2ee27107d900 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 index 3fa12ddca70a..4fef0d69c78c 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 c1accdc7063a..a59f9239dfca 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 c045048802f7..4e5b8fba136d 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 000000000000..4d91503f77b0 --- /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 5adfaa134c3c..d39d71ec7967 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 a1185a2d5479..07e5aff3954d 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 0dd9f5a39f91..2dd12ca4e21a 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/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml index cb7f40f6d87d..ae243130e537 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 297cf2b94a19..250076950907 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 2927d6ba7f3c..8a19c2ebdcd6 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/overlay_action_chip.xml b/packages/SystemUI/res/layout/overlay_action_chip.xml index e0c20ff4269c..e7c382f9833b 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 7e9202c9f89b..3b728a9ebc02 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 392d84537e92..78cd7184b485 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 aff0e8052739..bf0b8a660432 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/styles.xml b/packages/SystemUI/res/values/styles.xml index 9d0cc11c93c2..cee21353bd68 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/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 693268d730a4..1cbcb9d56566 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -264,8 +264,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard */ @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/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index b446724e6da6..a4d4a9a9bf56 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 @@ object Flags { "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 b5ddc2ea91b7..552e5ea967cf 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 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, 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/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index 2312c705cd6e..4bc7ec844794 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 @@ public class LongScreenshotActivity extends Activity { } 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 860bfe37aee2..13678b0e7187 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 @@ public class OverlayActionChip extends FrameLayout { 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 560ea8aae594..313410ac45df 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 @@ public class NotificationIconAreaController implements } updateAodIconsVisibility(animate, false /* force */); updateAodNotificationIcons(); + updateAodIconColors(); } @Override 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 eec91a0bca82..e1ffae01be03 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 @@ constructor( */ override val isDefaultConnectionFailed: StateFlow<Boolean> = combine( - mobileConnectionsRepo.mobileIsDefault, + mobileIsDefault, mobileConnectionsRepo.defaultConnectionIsValidated, forcingCellularValidation, ) { mobileIsDefault, defaultConnectionIsValidated, forcingCellularValidation -> diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index 8a05a37ad0dd..65ddb53f748b 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.biometrics.SideFpsUiRequestSource; 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 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { } @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 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @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/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index 6e1ab58db56d..1c219da09e27 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 @@ class MobileIconsInteractorTest : SysuiTestCase() { 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/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 7463061256b7..a324b2ff88e8 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 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ @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 e894f1c2879e..2d1290caf32d 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub 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/core/java/com/android/server/SoundTriggerInternal.java b/services/core/java/com/android/server/SoundTriggerInternal.java index f184574c9a36..f8830ea705c6 100644 --- a/services/core/java/com/android/server/SoundTriggerInternal.java +++ b/services/core/java/com/android/server/SoundTriggerInternal.java @@ -47,7 +47,14 @@ public interface SoundTriggerInternal { 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 a888a0b5d7d9..8ce1829a4b16 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 6360e2a0d089..36da888dbc2a 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a110169ac8c2..1f3795a12b76 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_RECEIVE_AMBIENT_TRIGGER_AUDIO; 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 @@ public class AppOpsService extends IAppOpsService.Stub { @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 @@ public class AppOpsService extends IAppOpsService.Stub { @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 773df3720ed3..1d8bef1c6732 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 @@ public class AudioDeviceInventory { 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 aece17e7a6e6..4aa256d3ce74 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 @@ public class SoundDoseHelper { /*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 @@ public class SoundDoseHelper { } 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); - - // 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; - } + updateSafeMediaVolume_l(caller); + 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 @@ public class SoundDoseHelper { 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/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 1c89ec445426..3c5ad2acc8a0 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 @@ public class TrustManagerService extends SystemService { @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/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index c40d72c3746e..6b90181cff0b 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 @@ class ActivityClientController extends IActivityClientController.Stub { } 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 0b572dfea3e3..f35343c98711 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 8728c3c64715..57b3c0d431a2 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.provider.Settings; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; @@ -482,7 +483,7 @@ public final class CredentialManagerService callback, request, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), - getEnabledProviders(), + getEnabledProvidersForUser(userId), CancellationSignal.fromTransport(cancelTransport), timestampBegan); addSessionLocked(userId, session); @@ -537,7 +538,7 @@ public final class CredentialManagerService getCredentialCallback, request, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), - getEnabledProviders(), + getEnabledProvidersForUser(userId), CancellationSignal.fromTransport(cancelTransport), timestampBegan, prepareGetCredentialCallback); @@ -655,7 +656,7 @@ public final class CredentialManagerService request, callback, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), - getEnabledProviders(), + getEnabledProvidersForUser(userId), getPrimaryProvidersForUserId(getContext(), userId), CancellationSignal.fromTransport(cancelTransport), timestampBegan); @@ -804,7 +805,7 @@ public final class CredentialManagerService verifyGetProvidersPermission(); return CredentialProviderInfoFactory.getCredentialProviderServices( - mContext, userId, providerFilter, getEnabledProviders(), + mContext, userId, providerFilter, getEnabledProvidersForUser(userId), getPrimaryProvidersForUserId(mContext, userId)); } @@ -815,7 +816,7 @@ public final class CredentialManagerService final int userId = UserHandle.getCallingUserId(); return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting( - mContext, userId, providerFilter, getEnabledProviders(), + mContext, userId, providerFilter, getEnabledProvidersForUser(userId), getPrimaryProvidersForUserId(mContext, userId)); } @@ -832,24 +833,26 @@ public final class CredentialManagerService } } - @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 +882,7 @@ public final class CredentialManagerService 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/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java index f5e3b86213a1..83e7e939e064 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 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr 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/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java index 3d963ed4fe37..56bd1929b1d4 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 class SoundTriggerMiddlewareImplTest { 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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 class SoundTriggerMiddlewareImplTest { 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 class SoundTriggerMiddlewareImplTest { 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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 @@ public class SoundTriggerMiddlewareImplTest { @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 cc357d76cb4a..385c28ae7152 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.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERAC 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 @@ public class SoundTriggerMiddlewareLoggingLatencyTest { 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 class SoundTriggerMiddlewareLoggingLatencyTest { 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 @@ public class SoundTriggerMiddlewareLoggingLatencyTest { 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 @@ public class SoundTriggerMiddlewareLoggingLatencyTest { 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/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java index 67320009e9aa..a67524887086 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 @@ public class SoundTriggerService extends SystemService { 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 @@ public class SoundTriggerService extends SystemService { 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 @@ public class SoundTriggerService extends SystemService { } @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 @@ public class SoundTriggerService extends SystemService { "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 60f89da8e4d3..ca35b5188515 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 @@ public interface ISoundTriggerMiddlewareInternal { * * 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 c8c0f3d00cbf..3b800de2f30b 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 @@ public class SoundTriggerMiddlewareImpl implements ISoundTriggerMiddlewareIntern @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 ecd65ae9fa2f..e3366f8e994b 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 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt @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 6b724de73488..2e641a26e9b4 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 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware @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 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware 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 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware } 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 1558acf547d1..9de24383ba75 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 class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic 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 2924c124f22e..31fab89d1d4e 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 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware @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 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware // 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 27f3fb3898ee..423a81ac0523 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 @@ public class VoiceInteractionManagerService extends SystemService { @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); + } + try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect( + originatorIdentity)) { + return new SoundTriggerSession(mSoundTriggerInternal.attach(client, + moduleProperties, 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)); - } - }); } @Override @@ -1700,11 +1670,7 @@ public class VoiceInteractionManagerService extends SystemService { 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 @@ public class VoiceInteractionManagerService extends SystemService { } @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 b003f59d5e81..331caa1bad7a 100644 --- a/telecomm/java/android/telecom/DisconnectCause.java +++ b/telecomm/java/android/telecom/DisconnectCause.java @@ -43,8 +43,8 @@ public final class DisconnectCause implements Parcelable { /** 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 0dabaca457f0..4cc3e0cbdb83 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 6a8752abfde7..501b9d33871a 100644 --- a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt +++ b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt @@ -79,6 +79,16 @@ class UserUnlockRequestTest { .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) |