diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-09-15 21:23:16 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-09-15 21:23:16 +0000 |
commit | 6e47c7075b91983ae501114425ea25e6df7690c8 (patch) | |
tree | 3e61d657c3073b6647dc0502abadeea224cf5ed3 | |
parent | 299fe6f5d6fc6f1af7c3411dcf4e5efdf7217368 (diff) | |
parent | 17fc586c25143984f6642ea8f25dd2e2d86a5e05 (diff) | |
download | base-android-14.0.0_r14.tar.gz |
Merge cherrypicks of ['googleplex-android-review.googlesource.com/24308899', 'googleplex-android-review.googlesource.com/24310240', 'googleplex-android-review.googlesource.com/23727470', 'googleplex-android-review.googlesource.com/24444452', 'googleplex-android-review.googlesource.com/24424817', 'googleplex-android-review.googlesource.com/24248274', 'googleplex-android-review.googlesource.com/24484185', 'googleplex-android-review.googlesource.com/24499883', 'googleplex-android-review.googlesource.com/24681253', 'googleplex-android-review.googlesource.com/24499331', 'googleplex-android-review.googlesource.com/24485253', 'googleplex-android-review.googlesource.com/24026633', 'googleplex-android-review.googlesource.com/24499047', 'googleplex-android-review.googlesource.com/24422641', 'googleplex-android-review.googlesource.com/24733945', 'googleplex-android-review.googlesource.com/24677183', 'googleplex-android-review.googlesource.com/24708071', 'googleplex-android-review.googlesource.com/24758914'] into udc-release.android-14.0.0_r15android-14.0.0_r14android-14.0.0_r13android14-s2-releaseandroid14-release
Change-Id: I8023576b9abf5d7976ab4ded6a1c803001da870b
29 files changed, 333 insertions, 94 deletions
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 411d157fa927..0ffe44219788 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -454,12 +454,11 @@ public class Dialog implements DialogInterface, Window.Callback, */ protected void onStart() { if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true); - if (mContext != null + if (allowsRegisterDefaultOnBackInvokedCallback() && mContext != null && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) { // Add onBackPressed as default back behavior. mDefaultBackCallback = this::onBackPressed; getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback); - mDefaultBackCallback = null; } } @@ -470,9 +469,18 @@ public class Dialog implements DialogInterface, Window.Callback, if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); if (mDefaultBackCallback != null) { getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback); + mDefaultBackCallback = null; } } + /** + * Whether this dialog allows to register the default onBackInvokedCallback. + * @hide + */ + protected boolean allowsRegisterDefaultOnBackInvokedCallback() { + return true; + } + private static final String DIALOG_SHOWING_TAG = "android:dialogShowing"; private static final String DIALOG_HIERARCHY_TAG = "android:dialogHierarchy"; @@ -697,7 +705,8 @@ public class Dialog implements DialogInterface, Window.Callback, if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) && event.isTracking() && !event.isCanceled() - && !WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) { + && (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext) + || !allowsRegisterDefaultOnBackInvokedCallback())) { onBackPressed(); return true; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 11dd30b82e78..54c8cb09d7ea 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3485,8 +3485,11 @@ public class Notification implements Parcelable * * @hide */ - public void setAllowlistToken(@Nullable IBinder token) { - mAllowlistToken = token; + public void clearAllowlistToken() { + mAllowlistToken = null; + if (publicVersion != null) { + publicVersion.clearAllowlistToken(); + } } /** diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index cd45f4df3d50..b4f4a7efad98 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -212,6 +212,11 @@ public final class AttributionSource implements Parcelable { } /** @hide */ + public AttributionSource withDefaultToken() { + return withToken(sDefaultToken); + } + + /** @hide */ public AttributionSource withPid(int pid) { return new AttributionSource(getUid(), pid, getPackageName(), getAttributionTag(), getToken(), mAttributionSourceState.renouncedPermissions, getNext()); @@ -520,16 +525,28 @@ public final class AttributionSource implements Parcelable { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AttributionSource that = (AttributionSource) o; - return mAttributionSourceState.uid == that.mAttributionSourceState.uid + return equalsExceptToken(that) && Objects.equals( + mAttributionSourceState.token, that.mAttributionSourceState.token); + } + + /** + * We store trusted attribution sources without their token (the token is the key to the map) + * to avoid having a strong reference to the token. This means, when checking the equality of a + * supplied AttributionSource in PermissionManagerService.isTrustedAttributionSource, we want to + * compare everything except the token. + * + * @hide + */ + public boolean equalsExceptToken(@Nullable AttributionSource o) { + if (o == null) return false; + return mAttributionSourceState.uid == o.mAttributionSourceState.uid && Objects.equals(mAttributionSourceState.packageName, - that.mAttributionSourceState.packageName) + o.mAttributionSourceState.packageName) && Objects.equals(mAttributionSourceState.attributionTag, - that.mAttributionSourceState.attributionTag) - && Objects.equals(mAttributionSourceState.token, - that.mAttributionSourceState.token) + o.mAttributionSourceState.attributionTag) && Arrays.equals(mAttributionSourceState.renouncedPermissions, - that.mAttributionSourceState.renouncedPermissions) - && Objects.equals(getNext(), that.getNext()); + o.mAttributionSourceState.renouncedPermissions) + && Objects.equals(getNext(), o.getNext()); } @Override diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java index 66269cb772f8..b25f47b11532 100644 --- a/core/java/android/hardware/usb/UsbConfiguration.java +++ b/core/java/android/hardware/usb/UsbConfiguration.java @@ -172,7 +172,8 @@ public class UsbConfiguration implements Parcelable { String name = in.readString(); int attributes = in.readInt(); int maxPower = in.readInt(); - Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader()); + Parcelable[] interfaces = in.readParcelableArray( + UsbInterface.class.getClassLoader(), UsbInterface.class); UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower); configuration.setInterfaces(interfaces); return configuration; diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java index 5704dac7a327..e4a09a651ae1 100644 --- a/core/java/android/inputmethodservice/SoftInputWindow.java +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -79,6 +79,13 @@ final class SoftInputWindow extends Dialog { @WindowState private int mWindowState = WindowState.TOKEN_PENDING; + @Override + protected boolean allowsRegisterDefaultOnBackInvokedCallback() { + // Do not register OnBackInvokedCallback from Dialog#onStart, InputMethodService will + // register CompatOnBackInvokedCallback for input method window. + return false; + } + /** * Set {@link IBinder} window token to the window. * diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java index f2ae973500af..611da3cec5c6 100644 --- a/core/java/android/window/WindowProviderService.java +++ b/core/java/android/window/WindowProviderService.java @@ -34,6 +34,7 @@ import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.IBinder; +import android.util.Log; import android.view.Display; import android.view.WindowManager; import android.view.WindowManager.LayoutParams.WindowType; @@ -52,6 +53,8 @@ import android.view.WindowManagerImpl; @UiContext public abstract class WindowProviderService extends Service implements WindowProvider { + private static final String TAG = WindowProviderService.class.getSimpleName(); + private final Bundle mOptions; private final WindowTokenClient mWindowToken = new WindowTokenClient(); private final WindowContextController mController = new WindowContextController(mWindowToken); @@ -194,8 +197,16 @@ public abstract class WindowProviderService extends Service implements WindowPro public final Context createServiceBaseContext(ActivityThread mainThread, LoadedApk packageInfo) { final Context context = super.createServiceBaseContext(mainThread, packageInfo); - final Display display = context.getSystemService(DisplayManager.class) - .getDisplay(getInitialDisplayId()); + final DisplayManager displayManager = context.getSystemService(DisplayManager.class); + final int initialDisplayId = getInitialDisplayId(); + Display display = displayManager.getDisplay(initialDisplayId); + // Fallback to use the default display if the initial display to start WindowProviderService + // is detached. + if (display == null) { + Log.e(TAG, "Display with id " + initialDisplayId + " not found, falling back to " + + "DEFAULT_DISPLAY"); + display = displayManager.getDisplay(DEFAULT_DISPLAY); + } return context.createTokenContext(mWindowToken, display); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 2f9f6ae3f3c4..4dbc54fa2481 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -7752,8 +7752,9 @@ android:process=":ui"> </activity> <activity android:name="com.android.internal.app.PlatLogoActivity" - android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen" + android:theme="@style/Theme.NoTitleBar.Fullscreen" android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" + android:enableOnBackInvokedCallback="true" android:icon="@drawable/platlogo" android:process=":ui"> </activity> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 6f7bc53e891c..fb27df15048d 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3537,11 +3537,11 @@ <attr name="preferKeepClear" format="boolean" /> <!-- <p>Whether or not the auto handwriting initiation is enabled in this View. - <p>For a view with active {@link android.view.inputmethod.InputConnection}, - if auto handwriting initiation is enabled stylus movement within its view boundary + <p>For a view with an active {@link android.view.inputmethod.InputConnection}, + if auto handwriting initiation is enabled, stylus movement within its view boundary will automatically trigger the handwriting mode. - <p>This is true by default. - See {@link android.view.View#setAutoHandwritingEnabled}. --> + See {@link android.view.View#setAutoHandwritingEnabled}. + <p>The default value of this flag is configurable by the device manufacturer. --> <attr name="autoHandwritingEnabled" format="boolean" /> <!-- <p>The amount of offset that is applied to the left edge of the view's stylus diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bd0fe40e758d..70013911904e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -6459,4 +6459,7 @@ <!-- Whether the AOSP support for app cloning building blocks is to be enabled for the device. --> <bool name="config_enableAppCloningBuildingBlocks">true</bool> + + <!-- Whether unlocking and waking a device are sequenced --> + <bool name="config_orderUnlockAndWake">false</bool> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2d040bb66d83..2425d367e1db 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -5132,4 +5132,7 @@ <java-symbol type="drawable" name="focus_event_pressed_key_background" /> <java-symbol type="string" name="lockscreen_too_many_failed_attempts_countdown" /> + + <!-- Whether we order unlocking and waking --> + <java-symbol type="bool" name="config_orderUnlockAndWake" /> </resources> diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 29e8716f08ac..6121b8837f4f 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -267,17 +267,22 @@ public final class MediaSession { } /** - * Set a pending intent for your media button receiver to allow restarting - * playback after the session has been stopped. If your app is started in - * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via - * the pending intent. - * <p> - * The pending intent is recommended to be explicit to follow the security recommendation of - * {@link PendingIntent#getActivity}. + * Set a pending intent for your media button receiver to allow restarting playback after the + * session has been stopped. + * + * <p>If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be + * sent via the pending intent. + * + * <p>The provided {@link PendingIntent} must not target an activity. Passing an activity + * pending intent will cause the call to be ignored. Refer to this <a + * href="https://developer.android.com/guide/components/activities/background-starts">guide</a> + * for more information. + * + * <p>The pending intent is recommended to be explicit to follow the security recommendation of + * {@link PendingIntent#getService}. * * @param mbr The {@link PendingIntent} to send the media button event to. * @see PendingIntent#getActivity - * * @deprecated Use {@link #setMediaButtonBroadcastReceiver(ComponentName)} instead. */ @Deprecated @@ -285,7 +290,7 @@ public final class MediaSession { try { mBinder.setMediaButtonReceiver(mbr); } catch (RemoteException e) { - Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e); + e.rethrowFromSystemServer(); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index f60f8db5e773..765edd72cfbd 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -1948,6 +1948,9 @@ public class SettingsProvider extends ContentProvider { cacheName = Settings.System.ALARM_ALERT_CACHE; } if (cacheName != null) { + if (!isValidAudioUri(name, value)) { + return false; + } final File cacheFile = new File( getRingtoneCacheDir(owningUserId), cacheName); cacheFile.delete(); @@ -1980,6 +1983,34 @@ public class SettingsProvider extends ContentProvider { } } + private boolean isValidAudioUri(String name, String uri) { + if (uri != null) { + Uri audioUri = Uri.parse(uri); + if (Settings.AUTHORITY.equals( + ContentProvider.getAuthorityWithoutUserId(audioUri.getAuthority()))) { + // Don't accept setting the default uri to self-referential URIs like + // Settings.System.DEFAULT_RINGTONE_URI, which is an alias to the value of this + // setting. + return false; + } + final String mimeType = getContext().getContentResolver().getType(audioUri); + if (mimeType == null) { + Slog.e(LOG_TAG, + "mutateSystemSetting for setting: " + name + " URI: " + audioUri + + " ignored: failure to find mimeType (no access from this context?)"); + return false; + } + if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg") + || mimeType.equals("application/x-flac"))) { + Slog.e(LOG_TAG, + "mutateSystemSetting for setting: " + name + " URI: " + audioUri + + " ignored: associated mimeType: " + mimeType + " is not an audio type"); + return false; + } + } + return true; + } + private boolean hasWriteSecureSettingsPermission() { // Write secure settings is a more protected permission. If caller has it we are good. return getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index 702cc05f7f5f..43290a31ea5f 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -401,6 +401,18 @@ open class ClockRegistry( scope.launch(bgDispatcher) { mutateSetting { it.copy(seedColor = value) } } } + // Returns currentClockId if clock is connected, otherwise DEFAULT_CLOCK_ID. Since this + // is dependent on which clocks are connected, it may change when a clock is installed or + // removed from the device (unlike currentClockId). + // TODO: Merge w/ CurrentClockId when we convert to a flow. We shouldn't need both behaviors. + val activeClockId: String + get() { + if (!availableClocks.containsKey(currentClockId)) { + return DEFAULT_CLOCK_ID + } + return currentClockId + } + init { // Register default clock designs for (clock in defaultClockProvider.getClocks()) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index a0261309d61a..70849b7e2acf 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -266,6 +266,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS setClock(null); mSecureSettings.unregisterContentObserver(mDoubleLineClockObserver); + mSecureSettings.unregisterContentObserver(mShowWeatherObserver); mKeyguardUnlockAnimationController.removeKeyguardUnlockAnimationListener( mKeyguardUnlockAnimationListener); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 1a06b0184bc5..18474e0af5b8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -470,6 +470,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private final int mDreamOpenAnimationDuration; /** + * Whether unlock and wake should be sequenced. + */ + private final boolean mOrderUnlockAndWake; + + /** * The animation used for hiding keyguard. This is used to fetch the animation timings if * WindowManager is not providing us with them. */ @@ -1434,6 +1439,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mMainDispatcher = mainDispatcher; mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel; + + mOrderUnlockAndWake = context.getResources().getBoolean( + com.android.internal.R.bool.config_orderUnlockAndWake); } public void userActivity() { @@ -2781,6 +2789,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private void setUnlockAndWakeFromDream(boolean updatedValue, @WakeAndUnlockUpdateReason int reason) { + if (!mOrderUnlockAndWake) { + return; + } + if (updatedValue == mUnlockingAndWakingFromDream) { return; } @@ -2863,6 +2875,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, null /* nonApps */, null /* finishedCallback */); }); } + + // It's possible that the device was unlocked (via BOUNCER or Fingerprint) while + // dreaming. It's time to wake up. + if (mDreamOverlayShowing && !mOrderUnlockAndWake) { + mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, + "com.android.systemui:UNLOCK_DREAMING"); + } } Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt index 1978b3d048b7..039460d8fdae 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt @@ -61,28 +61,23 @@ constructor( override fun start() { Log.d(LOG_TAG, "Resource trimmer registered.") - if ( - !(featureFlags.isEnabled(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK) || - featureFlags.isEnabled(Flags.TRIM_FONT_CACHES_AT_UNLOCK)) - ) { - return - } - - applicationScope.launch(bgDispatcher) { - // We need to wait for the AoD transition (and animation) to complete. - // This means we're waiting for isDreaming (== implies isDoze) and dozeAmount == 1f - // signal. This is to make sure we don't clear font caches during animation which - // would jank and leave stale data in memory. - val isDozingFully = - keyguardInteractor.dozeAmount.map { it == 1f }.distinctUntilChanged() - combine( - keyguardInteractor.wakefulnessModel.map { it.state }, - keyguardInteractor.isDreaming, - isDozingFully, - ::Triple - ) - .distinctUntilChanged() - .collect { onWakefulnessUpdated(it.first, it.second, it.third) } + if (featureFlags.isEnabled(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK)) { + applicationScope.launch(bgDispatcher) { + // We need to wait for the AoD transition (and animation) to complete. + // This means we're waiting for isDreaming (== implies isDoze) and dozeAmount == 1f + // signal. This is to make sure we don't clear font caches during animation which + // would jank and leave stale data in memory. + val isDozingFully = + keyguardInteractor.dozeAmount.map { it == 1f }.distinctUntilChanged() + combine( + keyguardInteractor.wakefulnessModel.map { it.state }, + keyguardInteractor.isDreaming, + isDozingFully, + ::Triple + ) + .distinctUntilChanged() + .collect { onWakefulnessUpdated(it.first, it.second, it.third) } + } } applicationScope.launch(bgDispatcher) { @@ -97,17 +92,16 @@ constructor( @WorkerThread private fun onKeyguardGone() { - if (!featureFlags.isEnabled(Flags.TRIM_FONT_CACHES_AT_UNLOCK)) { - return - } - - if (DEBUG) { - Log.d(LOG_TAG, "Trimming font caches since keyguard went away.") - } // We want to clear temporary caches we've created while rendering and animating // lockscreen elements, especially clocks. + Log.d(LOG_TAG, "Sending TRIM_MEMORY_UI_HIDDEN.") globalWindowManager.trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) - globalWindowManager.trimCaches(HardwareRenderer.CACHE_TRIM_FONT) + if (featureFlags.isEnabled(Flags.TRIM_FONT_CACHES_AT_UNLOCK)) { + if (DEBUG) { + Log.d(LOG_TAG, "Trimming font caches since keyguard went away.") + } + globalWindowManager.trimCaches(HardwareRenderer.CACHE_TRIM_FONT) + } } @WorkerThread diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index ed11711f66c6..a0b72fa208e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -173,6 +173,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private final VibratorHelper mVibratorHelper; private final BiometricUnlockLogger mLogger; private final SystemClock mSystemClock; + private final boolean mOrderUnlockAndWake; private long mLastFpFailureUptimeMillis; private int mNumConsecutiveFpFailures; @@ -308,6 +309,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mVibratorHelper = vibrator; mLogger = biometricUnlockLogger; mSystemClock = systemClock; + mOrderUnlockAndWake = resources.getBoolean( + com.android.internal.R.bool.config_orderUnlockAndWake); dumpManager.registerDumpable(getClass().getName(), this); } @@ -462,10 +465,11 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp Trace.endSection(); }; - final boolean wakingFromDream = mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM - && mPowerManager.isInteractive(); + final boolean wakeInKeyguard = mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM + && mPowerManager.isInteractive() && mOrderUnlockAndWake + && mOrderUnlockAndWake; - if (mMode != MODE_NONE && !wakingFromDream) { + if (mMode != MODE_NONE && !wakeInKeyguard) { wakeUp.run(); } switch (mMode) { @@ -501,7 +505,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp // later to awaken. } mNotificationShadeWindowController.setNotificationShadeFocusable(false); - mKeyguardViewMediator.onWakeAndUnlocking(wakingFromDream); + mKeyguardViewMediator.onWakeAndUnlocking(wakeInKeyguard); Trace.endSection(); break; case MODE_ONLY_WAKE: diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 34ea91b94414..1c8241433172 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -602,6 +602,9 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { @Test public void testWakeAndUnlockingOverDream() { + // Ensure ordering unlock and wake is enabled. + createAndStartViewMediator(true); + // Send signal to wake mViewMediator.onWakeAndUnlocking(true); @@ -631,6 +634,9 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { @Test public void testWakeAndUnlockingOverDream_signalAuthenticateIfStillShowing() { + // Ensure ordering unlock and wake is enabled. + createAndStartViewMediator(true); + // Send signal to wake mViewMediator.onWakeAndUnlocking(true); @@ -787,6 +793,15 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { } private void createAndStartViewMediator() { + createAndStartViewMediator(false); + } + + private void createAndStartViewMediator(boolean orderUnlockAndWake) { + if (orderUnlockAndWake) { + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_orderUnlockAndWake, orderUnlockAndWake); + } + mViewMediator = new KeyguardViewMediator( mContext, mUiEventLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt index 644736899b6c..c175ec3a96ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt @@ -18,6 +18,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.shared.model.WakeSleepReason import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState +import com.android.systemui.util.mockito.any import com.android.systemui.utils.GlobalWindowManager import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -227,6 +228,9 @@ class ResourceTrimmerTest : SysuiTestCase() { keyguardTransitionRepository.sendTransitionStep( TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE) ) - verifyNoMoreInteractions(globalWindowManager) + // Memory hidden should still be called. + verify(globalWindowManager, times(1)) + .trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) + verify(globalWindowManager, times(0)).trimCaches(any()) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index 04c93cb71e42..0c6926849c4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -224,6 +224,25 @@ class ClockRegistryTest : SysuiTestCase() { } @Test + fun activeClockId_changeAfterPluginConnected() { + val plugin1 = FakeClockPlugin() + .addClock("clock_1", "clock 1") + .addClock("clock_2", "clock 2") + + val plugin2 = FakeClockPlugin() + .addClock("clock_3", "clock 3", { mockClock }) + .addClock("clock_4", "clock 4") + + registry.applySettings(ClockSettings("clock_3", null)) + + pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle) + assertEquals(DEFAULT_CLOCK_ID, registry.activeClockId) + + pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle) + assertEquals("clock_3", registry.activeClockId) + } + + @Test fun createDefaultClock_pluginDisconnected() { val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1") diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index 7acf398955fb..2131f9d55ca8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -124,7 +124,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - TestableResources res = getContext().getOrCreateTestableResources(); + when(mKeyguardStateController.isShowing()).thenReturn(true); when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true); when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true); @@ -134,7 +134,15 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { when(mAuthController.isUdfpsFingerDown()).thenReturn(false); when(mVibratorHelper.hasVibrator()).thenReturn(true); mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager); - mBiometricUnlockController = new BiometricUnlockController(mDozeScrimController, + mBiometricUnlockController = createController(false); + when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(mStrongAuthTracker); + } + + BiometricUnlockController createController(boolean orderUnlockAndWake) { + TestableResources res = getContext().getOrCreateTestableResources(); + res.addOverride(com.android.internal.R.bool.config_orderUnlockAndWake, orderUnlockAndWake); + BiometricUnlockController biometricUnlockController = new BiometricUnlockController( + mDozeScrimController, mKeyguardViewMediator, mNotificationShadeWindowController, mKeyguardStateController, mHandler, mUpdateMonitor, res.getResources(), mKeyguardBypassController, @@ -144,9 +152,10 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper, mSystemClock ); - mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); - mBiometricUnlockController.addListener(mBiometricUnlockEventsListener); - when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(mStrongAuthTracker); + biometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); + biometricUnlockController.addListener(mBiometricUnlockEventsListener); + + return biometricUnlockController; } @Test @@ -549,6 +558,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test public void onSideFingerprintSuccess_dreaming_unlockNoWake() { + mBiometricUnlockController = createController(true); when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); when(mWakefulnessLifecycle.getLastWakeReason()) .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 476e1b4ef11e..8089dcfe7ebc 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3074,6 +3074,22 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** + * Enforces that the uid of the caller matches the uid of the package. + * + * @param packageName the name of the package to match uid against. + * @param callingUid the uid of the caller. + * @throws SecurityException if the calling uid doesn't match uid of the package. + */ + private void enforceCallingPackage(String packageName, int callingUid) { + final int userId = UserHandle.getUserId(callingUid); + final int packageUid = getPackageManagerInternal().getPackageUid(packageName, + /*flags=*/ 0, userId); + if (packageUid != callingUid) { + throw new SecurityException(packageName + " does not belong to uid " + callingUid); + } + } + @Override public void setPackageScreenCompatMode(String packageName, int mode) { mActivityTaskManager.setPackageScreenCompatMode(packageName, mode); @@ -13618,13 +13634,16 @@ public class ActivityManagerService extends IActivityManager.Stub // A backup agent has just come up @Override public void backupAgentCreated(String agentPackageName, IBinder agent, int userId) { + final int callingUid = Binder.getCallingUid(); + enforceCallingPackage(agentPackageName, callingUid); + // Resolve the target user id and enforce permissions. - userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), + userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, /* allowAll */ false, ALLOW_FULL_ONLY, "backupAgentCreated", null); if (DEBUG_BACKUP) { Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent + " callingUserId = " + UserHandle.getCallingUserId() + " userId = " + userId - + " callingUid = " + Binder.getCallingUid() + " uid = " + Process.myUid()); + + " callingUid = " + callingUid + " uid = " + Process.myUid()); } synchronized(this) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 29a19417b8fd..32c033230a16 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -2305,7 +2305,11 @@ import java.util.concurrent.atomic.AtomicBoolean; } @GuardedBy("mDeviceStateLock") - private boolean communnicationDeviceCompatOn() { + // LE Audio: For system server (Telecom) and APKs targeting S and above, we let the audio + // policy routing rules select the default communication device. + // For older APKs, we force LE Audio headset when connected as those APKs cannot select a LE + // Audiodevice explicitly. + private boolean communnicationDeviceLeAudioCompatOn() { return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION && !(CompatChanges.isChangeEnabled( USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid) @@ -2313,19 +2317,25 @@ import java.util.concurrent.atomic.AtomicBoolean; } @GuardedBy("mDeviceStateLock") + // Hearing Aid: For system server (Telecom) and IN_CALL mode we let the audio + // policy routing rules select the default communication device. + // For 3p apps and IN_COMMUNICATION mode we force Hearing aid when connected to maintain + // backwards compatibility + private boolean communnicationDeviceHaCompatOn() { + return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION + && !(mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID); + } + + @GuardedBy("mDeviceStateLock") AudioDeviceAttributes getDefaultCommunicationDevice() { - // For system server (Telecom) and APKs targeting S and above, we let the audio - // policy routing rules select the default communication device. - // For older APKs, we force Hearing Aid or LE Audio headset when connected as - // those APKs cannot select a LE Audio or Hearing Aid device explicitly. AudioDeviceAttributes device = null; - if (communnicationDeviceCompatOn()) { - // If both LE and Hearing Aid are active (thie should not happen), - // priority to Hearing Aid. + // If both LE and Hearing Aid are active (thie should not happen), + // priority to Hearing Aid. + if (communnicationDeviceHaCompatOn()) { device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID); - if (device == null) { - device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET); - } + } + if (device == null && communnicationDeviceLeAudioCompatOn()) { + device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET); } return device; } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 9185a00da570..4084462d3f28 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -1062,6 +1062,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR != 0) { return; } + + if (pi != null && pi.isActivity()) { + Log.w( + TAG, + "Ignoring invalid media button receiver targeting an activity: " + pi); + return; + } + mMediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mUserId, pi, mPackageName); mService.onMediaButtonReceiverChanged(MediaSessionRecord.this); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 79559fdc34d6..647087de1c04 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4444,7 +4444,7 @@ public class NotificationManagerService extends SystemService { // Remove background token before returning notification to untrusted app, this // ensures the app isn't able to perform background operations that are // associated with notification interactions. - notification.setAllowlistToken(null); + notification.clearAllowlistToken(); return new StatusBarNotification( sbn.getPackageName(), sbn.getOpPkg(), diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index f0e38955f050..d662aaedb774 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -67,6 +67,7 @@ import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.compat.annotation.EnabledSince; import android.content.ComponentName; import android.content.Context; @@ -311,6 +312,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final long SILENT_INSTALL_ALLOWED = 265131695L; /** + * The system supports pre-approval and update ownership features from + * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE API 34}. The change id is used to make sure + * the system includes the fix of pre-approval with update ownership case. When checking the + * change id, if it is disabled, it means the build includes the fix. The more detail is on + * b/293644536. + * See {@link PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean)} and + * {@link #requestUserPreapproval(PreapprovalDetails, IntentSender)} for more details. + */ + @Disabled + @ChangeId + private static final long PRE_APPROVAL_WITH_UPDATE_OWNERSHIP_FIX = 293644536L; + + /** * The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#S} before getting the * target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared @@ -893,16 +907,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (mPermissionsManuallyAccepted) { return USER_ACTION_NOT_NEEDED; } - packageName = mPackageName; + // For pre-pappvoal case, the mPackageName would be null. + if (mPackageName != null) { + packageName = mPackageName; + } else if (mPreapprovalRequested.get() && mPreapprovalDetails != null) { + packageName = mPreapprovalDetails.getPackageName(); + } else { + packageName = null; + } hasDeviceAdminReceiver = mHasDeviceAdminReceiver; } - final boolean forcePermissionPrompt = + // For the below cases, force user action prompt + // 1. installFlags includes INSTALL_FORCE_PERMISSION_PROMPT + // 2. params.requireUserAction is USER_ACTION_REQUIRED + final boolean forceUserActionPrompt = (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0 || params.requireUserAction == SessionParams.USER_ACTION_REQUIRED; - if (forcePermissionPrompt) { - return USER_ACTION_REQUIRED; - } + final int userActionNotTypicallyNeededResponse = forceUserActionPrompt + ? USER_ACTION_REQUIRED + : USER_ACTION_NOT_NEEDED; + // It is safe to access mInstallerUid and mInstallSource without lock // because they are immutable after sealing. final Computer snapshot = mPm.snapshotComputer(); @@ -956,7 +981,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { || isInstallerDeviceOwnerOrAffiliatedProfileOwner(); if (noUserActionNecessary) { - return USER_ACTION_NOT_NEEDED; + return userActionNotTypicallyNeededResponse; } if (isUpdateOwnershipEnforcementEnabled @@ -969,7 +994,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (isPermissionGranted) { - return USER_ACTION_NOT_NEEDED; + return userActionNotTypicallyNeededResponse; } if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid, diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 5b3514c01f9f..01bceb190c2e 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -3587,8 +3587,8 @@ public class ShortcutService extends IShortcutService.Stub { // Otherwise check persisted shortcuts getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> { - cb.complete(getShortcutIconUriInternal(launcherUserId, launcherPackage, - packageName, si, userId)); + cb.complete(si == null ? null : getShortcutIconUriInternal(launcherUserId, + launcherPackage, packageName, si, userId)); }); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 297ad73e054b..c24d5236f4f7 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1001,7 +1001,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { - mAttributions.put(source.getToken(), source); + // Change the token for the AttributionSource we're storing, so that we don't store + // a strong reference to the original token inside the map itself. + mAttributions.put(source.getToken(), source.withDefaultToken()); } } @@ -1009,7 +1011,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { synchronized (mLock) { final AttributionSource cachedSource = mAttributions.get(source.getToken()); if (cachedSource != null) { - return cachedSource.equals(source); + return cachedSource.equalsExceptToken(source); } return false; } diff --git a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java index 9015563f439e..24114988d6ba 100644 --- a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java +++ b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerService.java @@ -63,6 +63,12 @@ public final class TextToSpeechManagerService extends public void createSession(String engine, ITextToSpeechSessionCallback sessionCallback) { synchronized (mLock) { + if (engine == null) { + runSessionCallbackMethod( + () -> sessionCallback.onError("Engine cannot be null")); + return; + } + TextToSpeechManagerPerUserService perUserService = getServiceForUserLocked( UserHandle.getCallingUserId()); if (perUserService != null) { |