diff options
126 files changed, 3261 insertions, 1167 deletions
diff --git a/Android.bp b/Android.bp index 21054ddd89c6..6a85f62a5ae6 100644 --- a/Android.bp +++ b/Android.bp @@ -161,6 +161,7 @@ java_defaults { ":libcamera_client_framework_aidl", "core/java/android/hardware/IConsumerIrService.aidl", "core/java/android/hardware/ISerialManager.aidl", + "core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl", "core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl", "core/java/android/hardware/biometrics/IBiometricService.aidl", "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl", diff --git a/api/current.txt b/api/current.txt index 5997043cdd4a..b6249467fc62 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10307,6 +10307,7 @@ package android.content { field public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR"; field public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS"; field public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL"; + field public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES"; field public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY"; field public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS"; field public static final String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET"; @@ -38536,6 +38537,7 @@ package android.provider { field public static final String ALBUM_ID = "album_id"; field public static final String ALBUM_KEY = "album_key"; field public static final String ARTIST = "artist"; + field public static final String ARTIST_ID = "artist_id"; field public static final String FIRST_YEAR = "minyear"; field public static final String LAST_YEAR = "maxyear"; field public static final String NUMBER_OF_SONGS = "numsongs"; @@ -44380,9 +44382,9 @@ package android.telephony { method public int getCid(); method public int getLac(); method @Deprecated public int getMcc(); - method public String getMccString(); + method @Nullable public String getMccString(); method @Deprecated public int getMnc(); - method public String getMncString(); + method @Nullable public String getMncString(); method @Nullable public String getMobileNetworkOperator(); method @Deprecated public int getPsc(); method public void writeToParcel(android.os.Parcel, int); @@ -44394,9 +44396,9 @@ package android.telephony { method public int getCi(); method public int getEarfcn(); method @Deprecated public int getMcc(); - method public String getMccString(); + method @Nullable public String getMccString(); method @Deprecated public int getMnc(); - method public String getMncString(); + method @Nullable public String getMncString(); method @Nullable public String getMobileNetworkOperator(); method public int getPci(); method public int getTac(); @@ -44419,8 +44421,8 @@ package android.telephony { method public int getCid(); method public int getCpid(); method public int getLac(); - method public String getMccString(); - method public String getMncString(); + method @Nullable public String getMccString(); + method @Nullable public String getMncString(); method @Nullable public String getMobileNetworkOperator(); method public int getUarfcn(); method public void writeToParcel(android.os.Parcel, int); @@ -44431,9 +44433,9 @@ package android.telephony { method public int getCid(); method public int getLac(); method @Deprecated public int getMcc(); - method public String getMccString(); + method @Nullable public String getMccString(); method @Deprecated public int getMnc(); - method public String getMncString(); + method @Nullable public String getMncString(); method @Nullable public String getMobileNetworkOperator(); method public int getPsc(); method public int getUarfcn(); @@ -44456,22 +44458,22 @@ package android.telephony { } public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable { - method public android.telephony.CellIdentityCdma getCellIdentity(); - method public android.telephony.CellSignalStrengthCdma getCellSignalStrength(); + method @NonNull public android.telephony.CellIdentityCdma getCellIdentity(); + method @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoCdma> CREATOR; } public final class CellInfoGsm extends android.telephony.CellInfo implements android.os.Parcelable { - method public android.telephony.CellIdentityGsm getCellIdentity(); - method public android.telephony.CellSignalStrengthGsm getCellSignalStrength(); + method @NonNull public android.telephony.CellIdentityGsm getCellIdentity(); + method @NonNull public android.telephony.CellSignalStrengthGsm getCellSignalStrength(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoGsm> CREATOR; } public final class CellInfoLte extends android.telephony.CellInfo implements android.os.Parcelable { - method public android.telephony.CellIdentityLte getCellIdentity(); - method public android.telephony.CellSignalStrengthLte getCellSignalStrength(); + method @NonNull public android.telephony.CellIdentityLte getCellIdentity(); + method @NonNull public android.telephony.CellSignalStrengthLte getCellSignalStrength(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR; } @@ -44507,7 +44509,7 @@ package android.telephony { method public abstract boolean equals(Object); method public abstract int getAsuLevel(); method public abstract int getDbm(); - method public abstract int getLevel(); + method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public abstract int getLevel(); method public abstract int hashCode(); field public static final int SIGNAL_STRENGTH_GOOD = 3; // 0x3 field public static final int SIGNAL_STRENGTH_GREAT = 4; // 0x4 @@ -44527,7 +44529,7 @@ package android.telephony { method public int getEvdoEcio(); method public int getEvdoLevel(); method public int getEvdoSnr(); - method public int getLevel(); + method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthCdma> CREATOR; } @@ -44537,7 +44539,7 @@ package android.telephony { method public int getAsuLevel(); method public int getBitErrorRate(); method public int getDbm(); - method public int getLevel(); + method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); method public int getTimingAdvance(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR; @@ -44548,7 +44550,7 @@ package android.telephony { method public int getAsuLevel(); method public int getCqi(); method public int getDbm(); - method public int getLevel(); + method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); method public int getRsrp(); method public int getRsrq(); method public int getRssi(); @@ -44565,7 +44567,7 @@ package android.telephony { method public int getCsiRsrq(); method public int getCsiSinr(); method public int getDbm(); - method public int getLevel(); + method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); method public int getSsRsrp(); method public int getSsRsrq(); method public int getSsSinr(); @@ -44577,7 +44579,7 @@ package android.telephony { method public int describeContents(); method public int getAsuLevel(); method public int getDbm(); - method public int getLevel(); + method @IntRange(from=0, to=4) public int getLevel(); method public int getRscp(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthTdscdma> CREATOR; @@ -44587,7 +44589,7 @@ package android.telephony { method public int describeContents(); method public int getAsuLevel(); method public int getDbm(); - method public int getLevel(); + method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR; } diff --git a/api/test-current.txt b/api/test-current.txt index f76881d19e93..7121a549176a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -328,8 +328,14 @@ package android.app { } public class NotificationManager { + method public void allowAssistantCapability(String); + method public void disallowAssistantCapability(String); + method @NonNull public java.util.List<java.lang.String> getAllowedAssistantCapabilities(); + method @Nullable public android.content.ComponentName getAllowedNotificationAssistant(); method public android.content.ComponentName getEffectsSuppressor(); + method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName); method public boolean matchesCallFilter(android.os.Bundle); + method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean); } public final class PictureInPictureParams implements android.os.Parcelable { @@ -2454,10 +2460,49 @@ package android.service.contentcapture { package android.service.notification { + public final class Adjustment implements android.os.Parcelable { + ctor public Adjustment(String, String, android.os.Bundle, CharSequence, int); + ctor public Adjustment(@NonNull String, @NonNull String, @NonNull android.os.Bundle, @NonNull CharSequence, @NonNull android.os.UserHandle); + method public int describeContents(); + method @NonNull public CharSequence getExplanation(); + method @NonNull public String getKey(); + method @NonNull public String getPackage(); + method @NonNull public android.os.Bundle getSignals(); + method public int getUser(); + method @NonNull public android.os.UserHandle getUserHandle(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR; + field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions"; + field public static final String KEY_IMPORTANCE = "key_importance"; + field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria"; + field public static final String KEY_TEXT_REPLIES = "key_text_replies"; + field public static final String KEY_USER_SENTIMENT = "key_user_sentiment"; + } + @Deprecated public abstract class ConditionProviderService extends android.app.Service { method @Deprecated public boolean isBound(); } + public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { + ctor public NotificationAssistantService(); + method public final void adjustNotification(@NonNull android.service.notification.Adjustment); + method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>); + method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int); + method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent); + method public void onCapabilitiesChanged(); + method public void onNotificationDirectReplied(@NonNull String); + method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification); + method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel); + method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean); + method public abstract void onNotificationSnoozedUntilContext(@NonNull android.service.notification.StatusBarNotification, @NonNull String); + method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>); + method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int); + method public final void unsnoozeNotification(@NonNull String); + field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; + field public static final int SOURCE_FROM_APP = 0; // 0x0 + field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1 + } + public abstract class NotificationListenerService extends android.app.Service { method public void onNotificationRemoved(@NonNull android.service.notification.StatusBarNotification, @NonNull android.service.notification.NotificationListenerService.RankingMap, @NonNull android.service.notification.NotificationStats, int); } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index e3c2f422a94d..f7608f5320e8 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -4919,6 +4919,8 @@ message AppCompacted { UNKNOWN = 0; SOME = 1; FULL = 2; + PERSISTENT = 3; + BFGS = 4; } optional Action action = 3; diff --git a/config/preloaded-classes b/config/preloaded-classes index abdbab2a29eb..5910c284608d 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -756,7 +756,6 @@ android.content.ActivityNotFoundException android.content.AsyncQueryHandler$WorkerArgs android.content.AsyncQueryHandler$WorkerHandler android.content.AsyncQueryHandler -android.content.AsyncTaskLoader$LoadTask android.content.AsyncTaskLoader android.content.BroadcastReceiver$PendingResult$1 android.content.BroadcastReceiver$PendingResult @@ -3186,7 +3185,6 @@ android.speech.tts.ITextToSpeechCallback android.speech.tts.ITextToSpeechService$Stub$Proxy android.speech.tts.ITextToSpeechService android.speech.tts.TextToSpeech$Action -android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask android.speech.tts.TextToSpeech$Connection android.speech.tts.TextToSpeech$OnInitListener android.speech.tts.TextToSpeech diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist index 59f605d8e490..cd5a1205d122 100644 --- a/config/preloaded-classes-blacklist +++ b/config/preloaded-classes-blacklist @@ -1,6 +1,8 @@ +android.content.AsyncTaskLoader$LoadTask android.net.ConnectivityThread$Singleton android.os.AsyncTask android.os.FileObserver +android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask android.widget.Magnifier sun.nio.fs.UnixChannelFactory com.android.server.SystemConfig$PermissionEntry diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java index 26377642f2f9..c822d20445ec 100644 --- a/core/java/android/accounts/Account.java +++ b/core/java/android/accounts/Account.java @@ -93,6 +93,12 @@ public class Account implements Parcelable { public Account(Parcel in) { this.name = in.readString(); this.type = in.readString(); + if (TextUtils.isEmpty(name)) { + throw new android.os.BadParcelableException("the name must not be empty: " + name); + } + if (TextUtils.isEmpty(type)) { + throw new android.os.BadParcelableException("the type must not be empty: " + type); + } this.accessId = in.readString(); if (accessId != null) { synchronized (sAccessedAccounts) { diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 0bec21fcda90..d54aca89c50d 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -1169,6 +1169,7 @@ public class NotificationManager { * @hide */ @SystemApi + @TestApi public boolean isNotificationAssistantAccessGranted(@NonNull ComponentName assistant) { INotificationManager service = getService(); try { @@ -1204,6 +1205,7 @@ public class NotificationManager { * @hide */ @SystemApi + @TestApi public @NonNull @Adjustment.Keys List<String> getAllowedAssistantCapabilities() { INotificationManager service = getService(); try { @@ -1213,6 +1215,32 @@ public class NotificationManager { } } + /** + * @hide + */ + @TestApi + public void allowAssistantCapability(String capability) { + INotificationManager service = getService(); + try { + service.allowAssistantCapability(capability); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + @TestApi + public void disallowAssistantCapability(String capability) { + INotificationManager service = getService(); + try { + service.disallowAssistantCapability(capability); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { INotificationManager service = getService(); @@ -1310,6 +1338,7 @@ public class NotificationManager { * @hide */ @SystemApi + @TestApi public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant, boolean granted) { INotificationManager service = getService(); @@ -1332,6 +1361,7 @@ public class NotificationManager { /** @hide */ @SystemApi + @TestApi public @Nullable ComponentName getAllowedNotificationAssistant() { INotificationManager service = getService(); try { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index d87171e39595..8628d32123bc 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4731,6 +4731,18 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC"; + /** + * Used with {@link #ACTION_MAIN} to launch the files application. + * The activity should be able to browse and manage files stored on the device. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String)} to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard extra data keys. diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index fc79a425e861..639335e53ae5 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -451,7 +451,7 @@ public final class OverlayInfo implements Parcelable { public String toString() { return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName + ((targetOverlayableName == null) ? "" - : ", targetOverlyabale=" + targetOverlayableName) + : ", targetOverlayable=" + targetOverlayableName) + ", state=" + state + " (" + stateToString(state) + "), userId=" + userId + " }"; } } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 2b23e7a2a633..270aea851791 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -591,8 +591,6 @@ public class PackageParser { */ public interface Callback { boolean hasFeature(String feature); - String[] getOverlayPaths(String targetPackageName, String targetPath); - String[] getOverlayApks(String targetPackageName); } /** @@ -609,14 +607,6 @@ public class PackageParser { @Override public boolean hasFeature(String feature) { return mPm.hasSystemFeature(feature); } - - @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) { - return null; - } - - @Override public String[] getOverlayApks(String targetPackageName) { - return null; - } } /** @@ -1168,19 +1158,7 @@ public class PackageParser { } final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath()); - Package p = fromCacheEntry(bytes); - if (mCallback != null) { - String[] overlayApks = mCallback.getOverlayApks(p.packageName); - if (overlayApks != null && overlayApks.length > 0) { - for (String overlayApk : overlayApks) { - // If a static RRO is updated, return null. - if (!isCacheUpToDate(new File(overlayApk), cacheFile)) { - return null; - } - } - } - } - return p; + return fromCacheEntry(bytes); } catch (Throwable e) { Slog.w(TAG, "Error reading package cache: ", e); @@ -1354,7 +1332,7 @@ public class PackageParser { final Resources res = new Resources(assets, mMetrics, null); final String[] outError = new String[1]; - final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError); + final Package pkg = parseBaseApk(res, parser, flags, outError); if (pkg == null) { throw new PackageParserException(mParseError, apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); @@ -1911,7 +1889,6 @@ public class PackageParser { * need to consider whether they should be supported by split APKs and child * packages. * - * @param apkPath The package apk file path * @param res The resources from which to resolve values * @param parser The manifest parser * @param flags Flags how to parse @@ -1921,8 +1898,7 @@ public class PackageParser { * @throws XmlPullParserException * @throws IOException */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags, + private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { final String splitName; final String pkgName; @@ -1942,15 +1918,6 @@ public class PackageParser { return null; } - if (mCallback != null) { - String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath); - if (overlayPaths != null && overlayPaths.length > 0) { - for (String overlayPath : overlayPaths) { - res.getAssets().addOverlayPath(overlayPath); - } - } - } - final Package pkg = new Package(pkgName); TypedArray sa = res.obtainAttributes(parser, diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index a696eeb6bcc7..6c497d47c645 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -207,5 +207,22 @@ public class BiometricManager { Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected"); } } + + /** + * TODO(b/123378871): Remove when moved. + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback) { + if (mService != null) { + try { + mService.registerCancellationCallback(callback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + Slog.w(TAG, "registerCancellationCallback(): Service not connected"); + } + } } diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 08035972a0db..1142a07bc66c 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -82,6 +82,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @hide */ public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential"; + /** + * @hide + */ + public static final String KEY_FROM_CONFIRM_DEVICE_CREDENTIAL + = "from_confirm_device_credential"; /** * Error/help message will show for this amount of time. @@ -271,6 +276,17 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } /** + * TODO(123378871): Remove when moved. + * @return + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + @NonNull public Builder setFromConfirmDeviceCredential() { + mBundle.putBoolean(KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, true); + return this; + } + + /** * Creates a {@link BiometricPrompt}. * @return a {@link BiometricPrompt} * @throws IllegalArgumentException if any of the required fields are not set. @@ -494,7 +510,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan public void authenticateUser(@NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @NonNull AuthenticationCallback callback, - int userId) { + int userId, + IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) { if (cancel == null) { throw new IllegalArgumentException("Must supply a cancellation signal"); } @@ -504,7 +521,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (callback == null) { throw new IllegalArgumentException("Must supply a callback"); } - authenticateInternal(null /* crypto */, cancel, executor, callback, userId); + authenticateInternal(null /* crypto */, cancel, executor, callback, userId, + confirmDeviceCredentialCallback); } /** @@ -555,7 +573,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL)) { throw new IllegalArgumentException("Device credential not supported with crypto"); } - authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId()); + authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId(), + null /* confirmDeviceCredentialCallback */); } /** @@ -597,7 +616,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (callback == null) { throw new IllegalArgumentException("Must supply a callback"); } - authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId()); + authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId(), + null /* confirmDeviceCredentialCallback */); } private void cancelAuthentication() { @@ -614,7 +634,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @NonNull AuthenticationCallback callback, - int userId) { + int userId, + IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) { try { if (cancel.isCanceled()) { Log.w(TAG, "Authentication already canceled"); @@ -629,7 +650,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan final long sessionId = crypto != null ? crypto.getOpId() : 0; if (BiometricManager.hasBiometrics(mContext)) { mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver, - mContext.getOpPackageName(), mBundle); + mContext.getOpPackageName(), mBundle, confirmDeviceCredentialCallback); } else { mExecutor.execute(() -> { callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT, diff --git a/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl b/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl new file mode 100644 index 000000000000..8b35852efd31 --- /dev/null +++ b/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.biometrics; + +/** + * Communication channel between ConfirmDeviceCredential / ConfirmLock* and BiometricService. + * @hide + */ +interface IBiometricConfirmDeviceCredentialCallback { + // Invoked when authentication should be canceled. + oneway void cancel(); +}
\ No newline at end of file diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl index 4971911eb87c..90d4921c3c18 100644 --- a/core/java/android/hardware/biometrics/IBiometricService.aidl +++ b/core/java/android/hardware/biometrics/IBiometricService.aidl @@ -17,6 +17,7 @@ package android.hardware.biometrics; import android.os.Bundle; +import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; @@ -30,8 +31,10 @@ import android.hardware.biometrics.IBiometricServiceReceiver; interface IBiometricService { // Requests authentication. The service choose the appropriate biometric to use, and show // the corresponding BiometricDialog. + // TODO(b/123378871): Remove callback when moved. void authenticate(IBinder token, long sessionId, int userId, - IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle); + IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle, + IBiometricConfirmDeviceCredentialCallback callback); // Cancel authentication for the given sessionId void cancelAuthentication(IBinder token, String opPackageName); @@ -59,4 +62,8 @@ interface IBiometricService { void onConfirmDeviceCredentialSuccess(); // TODO(b/123378871): Remove when moved. void onConfirmDeviceCredentialError(int error, String message); + // TODO(b/123378871): Remove when moved. + // When ConfirmLock* is invoked from BiometricPrompt, it needs to register a callback so that + // it can receive the cancellation signal. + void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback); } diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 9e9e68dbf3fe..ed5c1b1e2277 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -1148,9 +1148,9 @@ public class Environment { final Context context = AppGlobals.getInitialApplication(); final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); - final boolean hasLegacy = appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, + final boolean hasLegacy = appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, context.getApplicationInfo().uid, - context.getPackageName()) == AppOpsManager.MODE_ALLOWED; + context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED; // STOPSHIP: only use app-op once permission model has fully landed final boolean requestedLegacy = !AppGlobals.getInitialApplication().getApplicationInfo() diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index c57bf9141248..075b650ed8f4 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1652,6 +1652,26 @@ public class StorageManager { */ public static boolean checkPermissionAndAppOp(Context context, boolean enforce, int pid, int uid, String packageName, String permission, int op) { + return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, permission, op, + true); + } + + /** + * Check that given app holds both permission and appop but do not noteOp. + * @hide + */ + public static boolean checkPermissionAndCheckOp(Context context, boolean enforce, + int pid, int uid, String packageName, String permission, int op) { + return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, permission, op, + false); + } + + /** + * Check that given app holds both permission and appop. + * @hide + */ + private static boolean checkPermissionAndAppOp(Context context, boolean enforce, + int pid, int uid, String packageName, String permission, int op, boolean note) { if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) { if (enforce) { throw new SecurityException( @@ -1662,7 +1682,21 @@ public class StorageManager { } AppOpsManager appOps = context.getSystemService(AppOpsManager.class); - final int mode = appOps.noteOpNoThrow(op, uid, packageName); + final int mode; + if (note) { + mode = appOps.noteOpNoThrow(op, uid, packageName); + } else { + try { + appOps.checkPackage(uid, packageName); + } catch (SecurityException e) { + if (enforce) { + throw e; + } else { + return false; + } + } + mode = appOps.checkOpNoThrow(op, uid, packageName); + } switch (mode) { case AppOpsManager.MODE_ALLOWED: return true; diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index bda6ed19d3c1..0b1647d05ef4 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -2676,7 +2676,13 @@ public final class MediaStore { public static final String ALBUM = "album"; /** - * The artist whose songs appear on this album + * The ID of the artist whose songs appear on this album. + */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + public static final String ARTIST_ID = "artist_id"; + + /** + * The name of the artist whose songs appear on this album. */ @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ARTIST = "artist"; diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index 2b7e8b859f28..5a918023fdc3 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -674,6 +674,8 @@ public abstract class AutofillService extends Service { * Called when the Android system disconnects from the service. * * <p> At this point this service may no longer be an active {@link AutofillService}. + * It should not make calls on {@link AutofillManager} that requires the caller to be + * the current service. */ public void onDisconnected() { } diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index 96b861b46dd4..b00eb8a0a2e1 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -41,6 +41,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.view.autofill.IAugmentedAutofillManagerClient; import android.view.autofill.IAutofillWindowPresenter; @@ -183,6 +184,8 @@ public abstract class AugmentedAutofillService extends Service { * Called when the Android system disconnects from the service. * * <p> At this point this service may no longer be an active {@link AugmentedAutofillService}. + * It should not make calls on {@link AutofillManager} that requires the caller to be + * the current service. */ public void onDisconnected() { } diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index dc57a1591913..5be73b92fbc0 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -37,7 +37,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; -import android.service.autofill.AutofillService; import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; @@ -350,7 +349,9 @@ public abstract class ContentCaptureService extends Service { /** * Called when the Android system disconnects from the service. * - * <p> At this point this service may no longer be an active {@link AutofillService}. + * <p> At this point this service may no longer be an active {@link ContentCaptureService}. + * It should not make calls on {@link ContentCaptureManager} that requires the caller to be + * the current service. */ public void onDisconnected() { Slog.i(TAG, "unbinding from " + getClass().getName()); diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java index 8ba9a8357c65..e81ce7f85ac1 100644 --- a/core/java/android/service/notification/Adjustment.java +++ b/core/java/android/service/notification/Adjustment.java @@ -18,6 +18,7 @@ package android.service.notification; import android.annotation.NonNull; import android.annotation.StringDef; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.Notification; import android.os.Bundle; import android.os.Parcel; @@ -40,6 +41,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi +@TestApi public final class Adjustment implements Parcelable { private final String mPackage; private final String mKey; @@ -130,6 +132,7 @@ public final class Adjustment implements Parcelable { * @hide */ @SystemApi + @TestApi public Adjustment(String pkg, String key, Bundle signals, CharSequence explanation, int user) { mPackage = pkg; mKey = key; @@ -212,6 +215,7 @@ public final class Adjustment implements Parcelable { /** @hide */ @SystemApi + @TestApi public int getUser() { return mUser; } diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index 22104b5089cf..8bb5f97ca878 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -53,4 +53,5 @@ oneway interface INotificationListener void onNotificationDirectReply(String key); void onSuggestedReplySent(String key, in CharSequence reply, int source); void onActionClicked(String key, in Notification.Action action, int source); + void onCapabilitiesChanged(); } diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index b81725d99d2b..b4fd39701233 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -65,6 +66,7 @@ import java.util.List; * @hide */ @SystemApi +@TestApi public abstract class NotificationAssistantService extends NotificationListenerService { private static final String TAG = "NotificationAssistants"; @@ -357,6 +359,11 @@ public abstract class NotificationAssistantService extends NotificationListenerS args.argi2 = source; mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_INVOKED, args).sendToTarget(); } + + @Override + public void onCapabilitiesChanged() { + mHandler.obtainMessage(MyHandler.MSG_ON_CAPABILITIES_CHANGED).sendToTarget(); + } } private final class MyHandler extends Handler { @@ -367,6 +374,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5; public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6; public static final int MSG_ON_ACTION_INVOKED = 7; + public static final int MSG_ON_CAPABILITIES_CHANGED = 8; public MyHandler(Looper looper) { super(looper, null, false); @@ -448,6 +456,10 @@ public abstract class NotificationAssistantService extends NotificationListenerS onActionInvoked(key, action, source); break; } + case MSG_ON_CAPABILITIES_CHANGED: { + onCapabilitiesChanged(); + break; + } } } } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 333868a2f08a..016f4aacef2a 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -1399,6 +1399,11 @@ public abstract class NotificationListenerService extends Service { } @Override + public void onCapabilitiesChanged() { + // no-op in the listener + } + + @Override public void onNotificationChannelModification(String pkgName, UserHandle user, NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index 597b34bf8554..956161acd762 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -41,9 +41,11 @@ interface IRecentsAnimationController { * with remote animation targets should be relinquished. If {@param moveHomeToTop} is true, then * the home activity should be moved to the top. Otherwise, the home activity is hidden and the * user is returned to the app. + * @param sendUserLeaveHint If set to true, {@link Activity#onUserLeaving} will be sent to the + * top resumed app, false otherwise. */ @UnsupportedAppUsage - void finish(boolean moveHomeToTop); + void finish(boolean moveHomeToTop, boolean sendUserLeaveHint); /** * Called by the handler to indicate that the recents animation input consumer should be diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 988fad2fb28e..51303f70f878 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -3055,6 +3055,7 @@ public class ChooserActivity extends ResolverActivity { private int mRadius = 0; private Path mPath = new Path(); private Paint mOverlayPaint = new Paint(0); + private Paint mRoundRectPaint = new Paint(0); private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private String mExtraImageCount = null; @@ -3078,6 +3079,11 @@ public class ChooserActivity extends ResolverActivity { mOverlayPaint.setColor(0x99000000); mOverlayPaint.setStyle(Paint.Style.FILL); + mRoundRectPaint.setColor(context.getResources().getColor(R.color.chooser_row_divider)); + mRoundRectPaint.setStyle(Paint.Style.STROKE); + mRoundRectPaint.setStrokeWidth(context.getResources() + .getDimensionPixelSize(R.dimen.chooser_preview_image_border)); + mTextPaint.setColor(Color.WHITE); mTextPaint.setTextSize(context.getResources() .getDimensionPixelSize(R.dimen.chooser_preview_image_font_size)); @@ -3087,8 +3093,8 @@ public class ChooserActivity extends ResolverActivity { private void updatePath(int width, int height) { mPath.reset(); - int imageWidth = width - getPaddingRight(); - int imageHeight = height - getPaddingBottom(); + int imageWidth = width - getPaddingRight() - getPaddingLeft(); + int imageHeight = height - getPaddingBottom() - getPaddingTop(); mPath.addRoundRect(getPaddingLeft(), getPaddingTop(), imageWidth, imageHeight, mRadius, mRadius, Path.Direction.CW); } @@ -3120,7 +3126,6 @@ public class ChooserActivity extends ResolverActivity { updatePath(width, height); } - @Override protected void onDraw(Canvas canvas) { if (mRadius != 0) { @@ -3129,8 +3134,12 @@ public class ChooserActivity extends ResolverActivity { super.onDraw(canvas); + int x = getPaddingLeft(); + int y = getPaddingRight(); + int width = getWidth() - getPaddingRight() - getPaddingLeft(); + int height = getHeight() - getPaddingBottom() - getPaddingTop(); if (mExtraImageCount != null) { - canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mOverlayPaint); + canvas.drawRect(x, y, width, height, mOverlayPaint); int xPos = canvas.getWidth() / 2; int yPos = (int) ((canvas.getHeight() / 2.0f) @@ -3138,6 +3147,8 @@ public class ChooserActivity extends ResolverActivity { canvas.drawText(mExtraImageCount, xPos, yPos, mTextPaint); } + + canvas.drawRoundRect(x, y, width, height, mRadius, mRadius, mRoundRectPaint); } } } diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java index b26efc0dbd10..2f9136a2577e 100644 --- a/core/java/com/android/internal/app/procstats/ProcessState.java +++ b/core/java/com/android/internal/app/procstats/ProcessState.java @@ -78,8 +78,8 @@ public final class ProcessState { STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI STATE_TOP, // ActivityManager.PROCESS_STATE_TOP STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION - STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_TOP + STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 13bcbf6625e2..3135c62c9c61 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -317,7 +317,8 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandl buffer->getPixelFormat(), (jint)buffer->getUsage(), (jlong)buffer.get(), - namedColorSpace); + namedColorSpace, + false /* capturedSecureLayers */); } static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) { diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 099635246f05..77ebd0290d33 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -462,7 +462,6 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ } if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) { - LOG(INFO) << "Ignoring open file descriptor " << fd; continue; } @@ -496,7 +495,6 @@ void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_ } if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) { - LOG(INFO) << "Ignoring open file descriptor " << fd; continue; } diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index c646fefad9d6..02cbc2e578cf 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -724,6 +724,7 @@ <dimen name="chooser_edge_margin_thin">16dp</dimen> <dimen name="chooser_edge_margin_normal">24dp</dimen> <dimen name="chooser_preview_image_font_size">20sp</dimen> + <dimen name="chooser_preview_image_border">1dp</dimen> <dimen name="chooser_preview_width">-1px</dimen> <dimen name="resolver_icon_size">42dp</dimen> <dimen name="resolver_badge_size">18dp</dimen> diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml index a43f7529c283..5c446d667015 100644 --- a/core/res/res/values/dimens_car.xml +++ b/core/res/res/values/dimens_car.xml @@ -121,6 +121,9 @@ <!-- Dialog button end margin --> <dimen name="button_end_margin">@*android:dimen/car_padding_4</dimen> + <!-- Dialog top padding when there is no title --> + <dimen name="dialog_no_title_padding_top">@*android:dimen/car_padding_4</dimen> + <!-- Dialog start margin for text view --> <dimen name="text_view_start_margin">@*android:dimen/car_keyline_1</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b87381364b1a..fb72da519f53 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2777,6 +2777,7 @@ <java-symbol type="dimen" name="chooser_edge_margin_normal" /> <java-symbol type="dimen" name="chooser_preview_image_font_size"/> <java-symbol type="dimen" name="chooser_preview_width" /> + <java-symbol type="dimen" name="chooser_preview_image_border"/> <java-symbol type="dimen" name="chooser_max_collapsed_height" /> <java-symbol type="layout" name="chooser_grid" /> <java-symbol type="layout" name="chooser_grid_preview_text" /> @@ -2790,6 +2791,7 @@ <java-symbol type="drawable" name="scroll_indicator_material" /> <java-symbol type="layout" name="chooser_row" /> + <java-symbol type="color" name="chooser_row_divider" /> <java-symbol type="layout" name="chooser_row_direct_share" /> <java-symbol type="bool" name="config_supportDoubleTapWake" /> <java-symbol type="drawable" name="ic_perm_device_info" /> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index ed198e60902b..e4a93e740c4c 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -309,6 +309,7 @@ applications that come with the platform <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/> <permission name="android.permission.SET_WALLPAPER" /> <permission name="android.permission.SET_WALLPAPER_COMPONENT" /> + <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 325e227e6f93..790e189e9109 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -25,7 +25,6 @@ import android.annotation.Nullable; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.os.Binder; -import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -1662,7 +1661,7 @@ public class AudioTrack extends PlayerBase * a better solution. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 112561552) + @UnsupportedAppUsage(trackingBug = 130237544) public int getLatency() { return native_get_latency(); } diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml index a5286364dc26..355bdd8dfc98 100644 --- a/packages/CaptivePortalLogin/AndroidManifest.xml +++ b/packages/CaptivePortalLogin/AndroidManifest.xml @@ -18,7 +18,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.captiveportallogin" - android:versionCode="200000000" + android:versionCode="210000000" android:versionName="Q-initial"> <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" /> diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml index 45a59a32ec17..73bfd3010983 100644 --- a/packages/ExtServices/AndroidManifest.xml +++ b/packages/ExtServices/AndroidManifest.xml @@ -17,7 +17,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" package="android.ext.services" - android:versionCode="200000000" + android:versionCode="210000000" android:versionName="1" coreApp="true"> diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml index b4588e01dc79..ac05c44c1803 100644 --- a/packages/NetworkStack/AndroidManifest.xml +++ b/packages/NetworkStack/AndroidManifest.xml @@ -19,7 +19,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.networkstack" android:sharedUserId="android.uid.networkstack" - android:versionCode="200000000" + android:versionCode="210000000" android:versionName="29 system image" > diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index bde1b25b914f..55ff591e3a1f 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -43,7 +43,6 @@ import android.content.pm.PackageUserState; import android.net.Uri; import android.os.Bundle; import android.os.Process; -import android.os.RemoteException; import android.os.UserManager; import android.provider.Settings; import android.util.Log; @@ -472,16 +471,6 @@ public class PackageInstallerActivity extends AlertActivity { mOriginatingUid, mOriginatingPackage); switch (appOpMode) { case AppOpsManager.MODE_DEFAULT: - try { - int result = mIpm.checkUidPermission( - Manifest.permission.REQUEST_INSTALL_PACKAGES, mOriginatingUid); - if (result == PackageManager.PERMISSION_GRANTED) { - initiateInstall(); - break; - } - } catch (RemoteException exc) { - Log.e(TAG, "Unable to talk to package manager"); - } mAppOpsManager.setMode(appOpCode, mOriginatingUid, mOriginatingPackage, AppOpsManager.MODE_ERRORED); // fall through diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index d4d0519fcc5f..e02709e10e83 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -83,17 +83,18 @@ import java.util.regex.Pattern; * as needed. */ public class ApplicationsState { - static final String TAG = "ApplicationsState"; - static final boolean DEBUG = false; - static final boolean DEBUG_LOCKING = false; + private static final String TAG = "ApplicationsState"; public static final int SIZE_UNKNOWN = -1; public static final int SIZE_INVALID = -2; - static final Pattern REMOVE_DIACRITICALS_PATTERN + private static final boolean DEBUG = false; + private static final boolean DEBUG_LOCKING = false; + private static final Object sLock = new Object(); + private static final Pattern REMOVE_DIACRITICALS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); - static final Object sLock = new Object(); + @VisibleForTesting static ApplicationsState sInstance; public static ApplicationsState getInstance(Application app) { @@ -126,13 +127,12 @@ public class ApplicationsState { // Information about all applications. Synchronize on mEntriesMap // to protect access to these. - final ArrayList<Session> mSessions = new ArrayList<Session>(); - final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>(); + final ArrayList<Session> mSessions = new ArrayList<>(); + final ArrayList<Session> mRebuildingSessions = new ArrayList<>(); private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges(); // Map: userid => (Map: package name => AppEntry) - final SparseArray<HashMap<String, AppEntry>> mEntriesMap = - new SparseArray<HashMap<String, AppEntry>>(); - final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>(); + final SparseArray<HashMap<String, AppEntry>> mEntriesMap = new SparseArray<>(); + final ArrayList<AppEntry> mAppEntries = new ArrayList<>(); List<ApplicationInfo> mApplications = new ArrayList<>(); long mCurId = 1; UUID mCurComputingSizeUuid; @@ -182,9 +182,10 @@ public class ApplicationsState { mInterestingConfigChanges = interestingConfigChanges; } - public static final @SessionFlags int DEFAULT_SESSION_FLAGS = + @SessionFlags + public static final int DEFAULT_SESSION_FLAGS = FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS | - FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER; + FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER; private ApplicationsState(Application app, IPackageManager iPackageManager) { mContext = app; @@ -194,7 +195,7 @@ public class ApplicationsState { mUm = mContext.getSystemService(UserManager.class); mStats = mContext.getSystemService(StorageStatsManager.class); for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) { - mEntriesMap.put(userId, new HashMap<String, AppEntry>()); + mEntriesMap.put(userId, new HashMap<>()); } mThread = new HandlerThread("ApplicationsState.Loader", @@ -683,9 +684,16 @@ public class ApplicationsState { private AppEntry getEntryLocked(ApplicationInfo info) { int userId = UserHandle.getUserId(info.uid); AppEntry entry = mEntriesMap.get(userId).get(info.packageName); - if (DEBUG) Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry); + if (DEBUG) { + Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry); + } if (entry == null) { - if (DEBUG) Log.i(TAG, "Creating AppEntry for " + info.packageName); + if (mHiddenModules.contains(info.packageName)) { + return null; + } + if (DEBUG) { + Log.i(TAG, "Creating AppEntry for " + info.packageName); + } entry = new AppEntry(mContext, info, mCurId++); mEntriesMap.get(userId).put(info.packageName, entry); mAppEntries.add(entry); @@ -759,7 +767,8 @@ public class ApplicationsState { boolean mRebuildForeground; private final boolean mHasLifecycle; - @SessionFlags private int mFlags = DEFAULT_SESSION_FLAGS; + @SessionFlags + private int mFlags = DEFAULT_SESSION_FLAGS; Session(Callbacks callbacks, Lifecycle lifecycle) { mCallbacks = callbacks; @@ -771,7 +780,8 @@ public class ApplicationsState { } } - public @SessionFlags int getSessionFlags() { + @SessionFlags + public int getSessionFlags() { return mFlags; } @@ -863,25 +873,32 @@ public class ApplicationsState { filter.init(mContext); } - List<AppEntry> apps; + final List<AppEntry> apps; synchronized (mEntriesMap) { apps = new ArrayList<>(mAppEntries); } - ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>(); - if (DEBUG) Log.i(TAG, "Rebuilding..."); - for (int i = 0; i < apps.size(); i++) { - AppEntry entry = apps.get(i); + ArrayList<AppEntry> filteredApps = new ArrayList<>(); + if (DEBUG) { + Log.i(TAG, "Rebuilding..."); + } + for (AppEntry entry : apps) { if (entry != null && (filter == null || filter.filterApp(entry))) { synchronized (mEntriesMap) { - if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock"); + if (DEBUG_LOCKING) { + Log.v(TAG, "rebuild acquired lock"); + } if (comparator != null) { // Only need the label if we are going to be sorting. entry.ensureLabel(mContext); } - if (DEBUG) Log.i(TAG, "Using " + entry.info.packageName + ": " + entry); + if (DEBUG) { + Log.i(TAG, "Using " + entry.info.packageName + ": " + entry); + } filteredApps.add(entry); - if (DEBUG_LOCKING) Log.v(TAG, "rebuild releasing lock"); + if (DEBUG_LOCKING) { + Log.v(TAG, "rebuild releasing lock"); + } } } } @@ -1290,7 +1307,8 @@ public class ApplicationsState { } } - private @SessionFlags int getCombinedSessionFlags(List<Session> sessions) { + @SessionFlags + private int getCombinedSessionFlags(List<Session> sessions) { synchronized (mEntriesMap) { int flags = 0; for (Session session : sessions) { @@ -1601,7 +1619,7 @@ public class ApplicationsState { } if (object1.info != null && object2.info != null) { compareResult = - sCollator.compare(object1.info.packageName, object2.info.packageName); + sCollator.compare(object1.info.packageName, object2.info.packageName); if (compareResult != 0) { return compareResult; } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java index 2711e3175957..3a53d29f7618 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.util.Log; import android.util.Pair; +import com.android.settingslib.R; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -47,7 +48,9 @@ public class BluetoothMediaDevice extends MediaDevice { @Override public String getSummary() { - return mCachedDevice.getConnectionSummary(); + return isConnected() || mCachedDevice.isBusy() + ? mCachedDevice.getConnectionSummary() + : mContext.getString(R.string.bluetooth_disconnected); } @Override diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 3a9a99385c28..314b74a69147 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -154,6 +154,7 @@ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) --> <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> + <uses-permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" /> <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- Permission needed to enable/disable overlays --> diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java index 42600c157387..834f4fc75dce 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java @@ -117,6 +117,7 @@ public interface QSTile { public String expandedAccessibilityClassName; public SlashState slash; public boolean handlesLongClick = true; + public boolean showRippleEffect = true; public boolean copyTo(State other) { if (other == null) throw new IllegalArgumentException(); @@ -135,7 +136,8 @@ public interface QSTile { || !Objects.equals(other.isTransient, isTransient) || !Objects.equals(other.dualTarget, dualTarget) || !Objects.equals(other.slash, slash) - || !Objects.equals(other.handlesLongClick, handlesLongClick); + || !Objects.equals(other.handlesLongClick, handlesLongClick) + || !Objects.equals(other.showRippleEffect, showRippleEffect); other.icon = icon; other.iconSupplier = iconSupplier; other.label = label; @@ -149,6 +151,7 @@ public interface QSTile { other.isTransient = isTransient; other.slash = slash != null ? slash.copy() : null; other.handlesLongClick = handlesLongClick; + other.showRippleEffect = showRippleEffect; return changed; } diff --git a/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml new file mode 100644 index 000000000000..fe1bb265880c --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml @@ -0,0 +1,31 @@ +<!-- + Copyright (C) 2019 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:viewportWidth="22" + android:viewportHeight="17" + android:width="22dp" + android:height="17dp"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M1.22,8.49l0.43-4.96h4.33v1.17H2.67L2.44,7.41c0.41-0.29,0.85-0.43,1.33-0.43c0.77,0,1.38,0.3,1.83,0.9 s0.66,1.41,0.66,2.43c0,1.03-0.24,1.84-0.72,2.43s-1.14,0.88-1.98,0.88c-0.75,0-1.36-0.24-1.83-0.73s-0.74-1.16-0.81-2.02h1.13 c0.07,0.57,0.23,1,0.49,1.29c0.26,0.29,0.59,0.43,1.01,0.43c0.47,0,0.84-0.2,1.1-0.61c0.26-0.41,0.4-0.96,0.4-1.65 c0-0.65-0.14-1.18-0.43-1.59S3.96,8.11,3.47,8.11c-0.4,0-0.72,0.1-0.96,0.31L2.19,8.75L1.22,8.49z" /> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M14.14,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13c0.56-0.7,1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79c0.54,0.53,0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45c-0.29-0.35-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7C9.14,5.63,8.96,6.37,8.95,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" /> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M20.96,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" /> + +</vector> diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back.xml b/packages/SystemUI/res/drawable/ic_sysbar_back.xml index 144884349c52..ee402622d52b 100644 --- a/packages/SystemUI/res/drawable/ic_sysbar_back.xml +++ b/packages/SystemUI/res/drawable/ic_sysbar_back.xml @@ -17,6 +17,7 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="28dp" android:height="28dp" + android:autoMirrored="true" android:viewportWidth="28" android:viewportHeight="28"> diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml index 93b2f9c85bd1..442fafcebb84 100644 --- a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml +++ b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml @@ -17,6 +17,7 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="28dp" android:height="28dp" + android:autoMirrored="true" android:viewportWidth="28" android:viewportHeight="28"> <path diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index f47d4b5aac6d..e098bc5acd5c 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -424,6 +424,9 @@ <!-- Content description of the data connection type LTE+. [CHAR LIMIT=NONE] --> <string name="data_connection_lte_plus">LTE+</string> + <!-- Content description of the data connection type 5Ge. [CHAR LIMIT=NONE] --> + <string name="data_connection_5ge" translate="false">5Ge</string> + <!-- Content description of the data connection type 5G. [CHAR LIMIT=NONE] --> <string name="data_connection_5g" translate="false">5G</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 1d9105c35ac5..d2fe5cd9ef64 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -77,9 +77,15 @@ public class RecentsAnimationControllerCompat { } } - public void finish(boolean toHome) { + /** + * Finish the current recents animation. + * @param toHome Going to home or back to the previous app. + * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous + * app. + */ + public void finish(boolean toHome, boolean sendUserLeaveHint) { try { - mAnimationController.finish(toHome); + mAnimationController.finish(toHome, sendUserLeaveHint); } catch (RemoteException e) { Log.e(TAG, "Failed to finish recents animation", e); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java index d40973bfdad7..a732a253f5a3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java @@ -40,7 +40,6 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.ImageView.ScaleType; import android.widget.Switch; import com.android.settingslib.Utils; @@ -63,6 +62,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { private boolean mTileState; private boolean mCollapsedView; private boolean mClicked; + private boolean mShowRippleEffect = true; private final ImageView mBg; private final int mColorActive; @@ -209,6 +209,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { mCircleColor = circleColor; } + mShowRippleEffect = state.showRippleEffect; setClickable(state.state != Tile.STATE_UNAVAILABLE); setLongClickable(state.handlesLongClick); mIcon.setIcon(state, allowAnimations); @@ -254,7 +255,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { @Override public void setClickable(boolean clickable) { super.setClickable(clickable); - setBackground(clickable ? mRipple : null); + setBackground(clickable && mShowRippleEffect ? mRipple : null); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java index c664a2090c04..d62f10d312d7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java @@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles; import android.content.Intent; +import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.widget.Switch; @@ -23,6 +24,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.SecureSetting; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; @@ -32,6 +34,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements BatteryController.BatteryStateChangeCallback { private final BatteryController mBatteryController; + private final SecureSetting mSetting; private int mLevel; private boolean mPowerSave; @@ -45,6 +48,12 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements super(host); mBatteryController = batteryController; mBatteryController.observe(getLifecycle(), this); + mSetting = new SecureSetting(mContext, mHandler, Secure.LOW_POWER_WARNING_ACKNOWLEDGED) { + @Override + protected void handleValueChanged(int value, boolean observedChange) { + handleRefreshState(null); + } + }; } @Override @@ -53,12 +62,19 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements } @Override + protected void handleDestroy() { + super.handleDestroy(); + mSetting.setListening(false); + } + + @Override public int getMetricsCategory() { return MetricsEvent.QS_BATTERY_TILE; } @Override public void handleSetListening(boolean listening) { + mSetting.setListening(listening); } @Override @@ -88,6 +104,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements state.contentDescription = state.label; state.value = mPowerSave; state.expandedAccessibilityClassName = Switch.class.getName(); + state.showRippleEffect = mSetting.getValue() == 0; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index 34f3c606be62..33a2acfe9521 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -64,6 +64,7 @@ import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.TaskStackChangeListener; import java.io.PrintWriter; @@ -339,7 +340,7 @@ public class RecentsOnboarding { } public void onConnectedToLauncher() { - if (!ONBOARDING_ENABLED) { + if (!ONBOARDING_ENABLED || QuickStepContract.isGesturalMode(mContext)) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index a87e50c50f51..15848d832c83 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -539,7 +539,6 @@ public class KeyguardIndicationController implements StateListener { protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback { public static final int HIDE_DELAY_MS = 5000; - private int mLastSuccessiveErrorMessage = -1; @Override public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { @@ -577,20 +576,14 @@ public class KeyguardIndicationController implements StateListener { if (!updateMonitor.isUnlockingWithBiometricAllowed()) { return; } + animatePadlockError(); if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.showBouncerMessage(helpString, mInitialTextColorState); } else if (updateMonitor.isScreenOn()) { - mLockIcon.setTransientBiometricsError(true); showTransientIndication(helpString); hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); - mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG), - TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); } - // Help messages indicate that there was actually a try since the last error, so those - // are not two successive error messages anymore. - mLastSuccessiveErrorMessage = -1; } @Override @@ -600,15 +593,9 @@ public class KeyguardIndicationController implements StateListener { if (shouldSuppressBiometricError(msgId, biometricSourceType, updateMonitor)) { return; } + animatePadlockError(); if (mStatusBarKeyguardViewManager.isBouncerShowing()) { - // When swiping up right after receiving a biometric error, the bouncer calls - // authenticate leading to the same message being shown again on the bouncer. - // We want to avoid this, as it may confuse the user when the message is too - // generic. - if (mLastSuccessiveErrorMessage != msgId) { - mStatusBarKeyguardViewManager.showBouncerMessage(errString, - mInitialTextColorState); - } + mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState); } else if (updateMonitor.isScreenOn()) { showTransientIndication(errString); // We want to keep this message around in case the screen was off @@ -616,7 +603,13 @@ public class KeyguardIndicationController implements StateListener { } else { mMessageToShowOnScreenOn = errString; } - mLastSuccessiveErrorMessage = msgId; + } + + private void animatePadlockError() { + mLockIcon.setTransientBiometricsError(true); + mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG), + TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); } private boolean shouldSuppressBiometricError(int msgId, @@ -670,17 +663,10 @@ public class KeyguardIndicationController implements StateListener { @Override public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) { super.onBiometricAuthenticated(userId, biometricSourceType); - mLastSuccessiveErrorMessage = -1; mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT); } @Override - public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) { - super.onBiometricAuthFailed(biometricSourceType); - mLastSuccessiveErrorMessage = -1; - } - - @Override public void onUserUnlocked() { if (mVisible) { updateIndication(false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index d11eab7bb895..562e535eb42a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -401,7 +401,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override public void getOutline(View view, Outline outline) { if (mAmbientState.isDarkAtAll() || !mShowDarkShelf) { - outline.setRoundRect(mBackgroundAnimationRect, mCornerRadius); + float xProgress = mDarkXInterpolator.getInterpolation( + (1 - mLinearDarkAmount) * mBackgroundXFactor); + outline.setRoundRect(mBackgroundAnimationRect, + MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius, + xProgress)); } else { ViewOutlineProvider.BACKGROUND.getOutline(view, outline); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index 1d87a8b439e8..443cc4397bd3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -98,8 +98,10 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener // Short-circuiting from UserManager. Needs to be extracted because of SystemUI boolean flag // qs_show_user_switcher_for_single_user + // The default in UserManager is to show the switcher. We want to not show it unless the + // user explicitly requests it in Settings final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.USER_SWITCHER_ENABLED, 1) != 0; + Settings.Global.USER_SWITCHER_ENABLED, 0) != 0; if (!UserManager.supportsMultipleUsers() || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index e2a63cc00d9e..835db6f532db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -34,7 +34,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Point; @@ -48,8 +47,6 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.view.Display; -import android.view.IPinnedStackController; -import android.view.IPinnedStackListener; import android.view.MotionEvent; import android.view.Surface; import android.view.View; @@ -237,45 +234,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav } }; - private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() { - @Override - public void onListenerRegistered(IPinnedStackController controller) { - } - - @Override - public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { - post(() -> { - // TODO remove this and do below when mNavigationIconHints changes - if (imeVisible) { - getBackButton().setVisibility(VISIBLE); - reloadNavIcons(); - } else { - getImeSwitchButton().setVisibility(GONE); - } - mImeVisible = imeVisible; - updateWindowTouchable(); - }); - } - - @Override - public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) { - } - - @Override - public void onMinimizedStateChanged(boolean isMinimized) { - } - - @Override - public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, - int displayRotation) { - } - - @Override - public void onActionsChanged(ParceledListSlice actions) { - } - }; - private BroadcastReceiver mOverlaysChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -507,9 +465,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav final boolean useAltBack = (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - float degrees = useAltBack - ? (isRtl ? 270 : -90) - : (isRtl ? 180 : 0); + float degrees = useAltBack ? (isRtl ? 90 : -90) : 0; if (drawable.getRotation() == degrees) { return; } @@ -559,10 +515,13 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav public void setNavigationIconHints(int hints) { if (hints == mNavigationIconHints) return; - final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; - if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) { - mTransitionListener.onBackAltCleared(); + final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; + final boolean oldBackAlt = + (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; + if (newBackAlt != oldBackAlt) { + onImeVisibilityChanged(newBackAlt); } + if (DEBUG) { android.widget.Toast.makeText(getContext(), "Navigation icon hints = " + hints, @@ -572,6 +531,14 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav updateNavButtonIcons(); } + private void onImeVisibilityChanged(boolean visible) { + if (!visible) { + mTransitionListener.onBackAltCleared(); + } + mImeVisible = visible; + updateWindowTouchable(); + } + public void setDisabledFlags(int disabledFlags) { if (mDisabledFlags == disabledFlags) return; @@ -1114,14 +1081,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav filter.addDataScheme("package"); getContext().registerReceiver(mOverlaysChangedReceiver, filter); mEdgeBackGestureHandler.onNavBarAttached(); - - if (QuickStepContract.isGesturalMode(getContext())) { - try { - WindowManagerWrapper.getInstance().addPinnedStackListener(mImeChangedListener); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register pinned stack listener", e); - } - } updateWindowTouchable(); } @@ -1139,8 +1098,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav getContext().unregisterReceiver(mOverlaysChangedReceiver); mEdgeBackGestureHandler.onNavBarDetached(); - - WindowManagerWrapper.getInstance().removePinnedStackListener(mImeChangedListener); } private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java index 03c89c60360f..dd0c3443f2ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java @@ -37,6 +37,7 @@ import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.util.FloatProperty; import android.view.ContextThemeWrapper; +import android.view.View; import com.android.settingslib.Utils; import com.android.systemui.R; @@ -79,9 +80,10 @@ public class KeyButtonDrawable extends Drawable { private final ShadowDrawableState mState; private AnimatedVectorDrawable mAnimatedDrawable; - public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor) { + public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor, + boolean horizontalFlip) { this(d, new ShadowDrawableState(lightColor, darkColor, - d instanceof AnimatedVectorDrawable)); + d instanceof AnimatedVectorDrawable, horizontalFlip)); } private KeyButtonDrawable(Drawable d, ShadowDrawableState state) { @@ -282,7 +284,12 @@ public class KeyButtonDrawable extends Drawable { // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared. final Drawable d = mState.mChildState.newDrawable().mutate(); setDrawableBounds(d); + canvas.save(); + if (mState.mHorizontalFlip) { + canvas.scale(-1f, 1f, width * 0.5f, height * 0.5f); + } d.draw(canvas); + canvas.restore(); if (mState.mIsHardwareBitmap) { bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false); @@ -305,7 +312,12 @@ public class KeyButtonDrawable extends Drawable { // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared. final Drawable d = mState.mChildState.newDrawable().mutate(); setDrawableBounds(d); + canvas.save(); + if (mState.mHorizontalFlip) { + canvas.scale(-1f, 1f, width * 0.5f, height * 0.5f); + } d.draw(canvas); + canvas.restore(); // Draws the shadow from original drawable Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); @@ -357,6 +369,7 @@ public class KeyButtonDrawable extends Drawable { int mShadowColor; float mDarkIntensity; int mAlpha; + boolean mHorizontalFlip; boolean mIsHardwareBitmap; Bitmap mLastDrawnIcon; @@ -368,11 +381,12 @@ public class KeyButtonDrawable extends Drawable { final boolean mSupportsAnimation; public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor, - boolean animated) { + boolean animated, boolean horizontalFlip) { mLightColor = lightColor; mDarkColor = darkColor; mSupportsAnimation = animated; mAlpha = 255; + mHorizontalFlip = horizontalFlip; } @Override @@ -400,7 +414,7 @@ public class KeyButtonDrawable extends Drawable { * @return KeyButtonDrawable */ public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon, - boolean hasShadow) { + boolean hasShadow) { final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme); final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme); Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme); @@ -409,7 +423,7 @@ public class KeyButtonDrawable extends Drawable { } public static KeyButtonDrawable create(Context lightContext, Context darkContext, - @DrawableRes int iconResId, boolean hasShadow) { + @DrawableRes int iconResId, boolean hasShadow) { return create(lightContext, Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor), Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor), @@ -418,10 +432,12 @@ public class KeyButtonDrawable extends Drawable { public static KeyButtonDrawable create(Context context, @ColorInt int lightColor, @ColorInt int darkColor, @DrawableRes int iconResId, boolean hasShadow) { - final KeyButtonDrawable drawable = new KeyButtonDrawable(context.getDrawable(iconResId), - lightColor, darkColor); + final Resources res = context.getResources(); + boolean isRtl = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + Drawable d = context.getDrawable(iconResId); + final KeyButtonDrawable drawable = new KeyButtonDrawable(d, lightColor, darkColor, + isRtl && d.isAutoMirrored()); if (hasShadow) { - final Resources res = context.getResources(); int offsetX = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_x); int offsetY = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_y); int radius = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_radius); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index c5996a1e1b00..15854e66bc5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -47,6 +47,8 @@ import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionD import java.io.PrintWriter; import java.util.BitSet; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class MobileSignalController extends SignalController< @@ -73,6 +75,8 @@ public class MobileSignalController extends SignalController< private SignalStrength mSignalStrength; private MobileIconGroup mDefaultIcons; private Config mConfig; + // Some specific carriers have 5GE network which is special LTE CA network. + private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1; // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't // need listener lists anymore. @@ -236,6 +240,8 @@ public class MobileSignalController extends SignalController< TelephonyIcons.LTE_PLUS); } } + mNetworkToIconLookup.put(NETWORK_TYPE_LTE_CA_5GE, + TelephonyIcons.LTE_CA_5G_E); mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC); } @@ -381,6 +387,26 @@ public class MobileSignalController extends SignalController< } } + private boolean isCarrierSpecificDataIcon() { + if (mConfig.patternOfCarrierSpecificDataIcon == null + || mConfig.patternOfCarrierSpecificDataIcon.length() == 0) { + return false; + } + + Pattern stringPattern = Pattern.compile(mConfig.patternOfCarrierSpecificDataIcon); + String[] operatorNames = new String[]{mServiceState.getOperatorAlphaLongRaw(), + mServiceState.getOperatorAlphaShortRaw()}; + for (String opName : operatorNames) { + if (!TextUtils.isEmpty(opName)) { + Matcher matcher = stringPattern.matcher(opName); + if (matcher.find()) { + return true; + } + } + } + return false; + } + /** * Updates the network's name based on incoming spn and plmn. */ @@ -559,12 +585,8 @@ public class MobileSignalController extends SignalController< + " dataState=" + state.getDataRegState()); } mServiceState = state; - if (state != null) { - mDataNetType = state.getDataNetworkType(); - if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null && - mServiceState.isUsingCarrierAggregation()) { - mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA; - } + if (mServiceState != null) { + updateDataNetType(mServiceState.getDataNetworkType()); } updateTelephony(); } @@ -576,12 +598,19 @@ public class MobileSignalController extends SignalController< + " type=" + networkType); } mDataState = state; + updateDataNetType(networkType); + updateTelephony(); + } + + private void updateDataNetType(int networkType) { mDataNetType = networkType; - if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null && - mServiceState.isUsingCarrierAggregation()) { - mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA; + if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) { + if (isCarrierSpecificDataIcon()) { + mDataNetType = NETWORK_TYPE_LTE_CA_5GE; + } else if (mServiceState != null && mServiceState.isUsingCarrierAggregation()) { + mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA; + } } - updateTelephony(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index d01430a97783..ea0dd33ae694 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -1102,6 +1102,7 @@ public class NetworkControllerImpl extends BroadcastReceiver boolean hspaDataDistinguishable; boolean inflateSignalStrengths = false; boolean alwaysShowDataRatIcon = false; + public String patternOfCarrierSpecificDataIcon = ""; /** * Mapping from NR 5G status string to an integer. The NR 5G status string should match @@ -1140,6 +1141,8 @@ public class NetworkControllerImpl extends BroadcastReceiver CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL); config.hideLtePlus = b.getBoolean( CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL); + config.patternOfCarrierSpecificDataIcon = b.getString( + CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING); String nr5GIconConfiguration = b.getString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING); if (!TextUtils.isEmpty(nr5GIconConfiguration)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java index e151ca3e23f3..c22ff8ba594b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -35,6 +35,7 @@ class TelephonyIcons { static final int ICON_3G = R.drawable.ic_3g_mobiledata; static final int ICON_4G = R.drawable.ic_4g_mobiledata; static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata; + static final int ICON_5G_E = R.drawable.ic_5g_e_mobiledata; static final int ICON_1X = R.drawable.ic_1x_mobiledata; static final int ICON_5G = R.drawable.ic_5g_mobiledata; static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata; @@ -204,6 +205,19 @@ class TelephonyIcons { TelephonyIcons.ICON_LTE_PLUS, true); + static final MobileIconGroup LTE_CA_5G_E = new MobileIconGroup( + "5Ge", + null, + null, + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, + 0, 0, + 0, + 0, + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], + R.string.data_connection_5ge, + TelephonyIcons.ICON_5G_E, + true); + static final MobileIconGroup NR_5G = new MobileIconGroup( "5G", null, @@ -276,6 +290,7 @@ class TelephonyIcons { ICON_NAME_TO_ICON.put("h+", H_PLUS); ICON_NAME_TO_ICON.put("4g", FOUR_G); ICON_NAME_TO_ICON.put("4g+", FOUR_G_PLUS); + ICON_NAME_TO_ICON.put("5ge", LTE_CA_5G_E); ICON_NAME_TO_ICON.put("lte", LTE); ICON_NAME_TO_ICON.put("lte+", LTE_PLUS); ICON_NAME_TO_ICON.put("5g", NR_5G); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java index e3c081ea2a67..c837c9ccea95 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java @@ -179,8 +179,10 @@ public class NavigationBarContextTest extends SysuiTestCase { final int unusedColor = 0; final Drawable d = mock(Drawable.class); final ContextualButton button = spy(mBtn0); - final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor)); - final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor)); + final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor, + false /* horizontalFlip */)); + final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor, + false /* horizontalFlip */)); kbd1.setDarkIntensity(TEST_DARK_INTENSITY); kbd2.setDarkIntensity(0f); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 0786b1819b71..da9cffa73585 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3836,9 +3836,9 @@ class StorageManagerService extends IStorageManager.Stub } // Determine if caller is holding runtime permission - final boolean hasRead = StorageManager.checkPermissionAndAppOp(mContext, false, 0, + final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0, uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE); - final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0, + final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0, uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE); // STOPSHIP: remove this temporary hack once we have dynamic runtime // permissions fully enabled again diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java index 5cc9bfd52b13..6bb3200f7cc1 100644 --- a/services/core/java/com/android/server/SystemServerInitThreadPool.java +++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java @@ -22,9 +22,10 @@ import android.util.Slog; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.Preconditions; +import com.android.server.am.ActivityManagerService; +import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -47,6 +48,8 @@ public class SystemServerInitThreadPool { private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(4, "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND); + private List<String> mPendingTasks = new ArrayList<>(); + public static synchronized SystemServerInitThreadPool get() { if (sInstance == null) { sInstance = new SystemServerInitThreadPool(); @@ -57,19 +60,26 @@ public class SystemServerInitThreadPool { } public Future<?> submit(Runnable runnable, String description) { - if (IS_DEBUGGABLE) { - return mService.submit(() -> { - Slog.d(TAG, "Started executing " + description); - try { - runnable.run(); - } catch (RuntimeException e) { - Slog.e(TAG, "Failure in " + description + ": " + e, e); - throw e; - } - Slog.d(TAG, "Finished executing " + description); - }); + synchronized (mPendingTasks) { + mPendingTasks.add(description); } - return mService.submit(runnable); + return mService.submit(() -> { + if (IS_DEBUGGABLE) { + Slog.d(TAG, "Started executing " + description); + } + try { + runnable.run(); + } catch (RuntimeException e) { + Slog.e(TAG, "Failure in " + description + ": " + e, e); + throw e; + } + synchronized (mPendingTasks) { + mPendingTasks.remove(description); + } + if (IS_DEBUGGABLE) { + Slog.d(TAG, "Finished executing " + description); + } + }); } static synchronized void shutdown() { @@ -81,16 +91,36 @@ public class SystemServerInitThreadPool { TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); + dumpStackTraces(); throw new IllegalStateException(TAG + " init interrupted"); } + if (!terminated) { + // dump stack must be called before shutdownNow() to collect stacktrace of threads + // in the thread pool. + dumpStackTraces(); + } List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow(); if (!terminated) { + final List<String> copy = new ArrayList<>(); + synchronized (sInstance.mPendingTasks) { + copy.addAll(sInstance.mPendingTasks); + } throw new IllegalStateException("Cannot shutdown. Unstarted tasks " - + unstartedRunnables); + + unstartedRunnables + " Unfinished tasks " + copy); } sInstance.mService = null; // Make mService eligible for GC + sInstance.mPendingTasks = null; Slog.d(TAG, "Shutdown successful"); } } + /** + * A helper function to call ActivityManagerService.dumpStackTraces(). + */ + private static void dumpStackTraces() { + final ArrayList<Integer> pids = new ArrayList<>(); + pids.add(Process.myPid()); + ActivityManagerService.dumpStackTraces( + pids, null, null, null); + } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index c647e2ed824f..ac584e9571fc 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -1304,12 +1304,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } if (VDBG) { - log("notifyUserMobileDataStateChangedForSubscriberPhoneID: subId=" + phoneId - + " state=" + state); + log("notifyUserMobileDataStateChangedForSubscriberPhoneID: PhoneId=" + phoneId + + " subId=" + subId + " state=" + state); } synchronized (mRecords) { if (validatePhoneId(phoneId)) { - mMessageWaiting[phoneId] = state; + mUserMobileDataState[phoneId] = state; for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) && diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 5d47c9dfdddd..44d435f2b539 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1262,15 +1262,16 @@ public final class OomAdjuster { // processes). These should not bring the current process // into the top state, since they are not on top. Instead // give them the best bound state after that. + final int bestState = cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES) + ? PROCESS_STATE_FOREGROUND_SERVICE_LOCATION + : PROCESS_STATE_BOUND_FOREGROUND_SERVICE; if ((cr.flags & Context.BIND_FOREGROUND_SERVICE) != 0) { - clientProcState = - PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + clientProcState = bestState; } else if (mService.mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE) != 0) { - clientProcState = - PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + clientProcState = bestState; } else { clientProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index d073bc60c766..4c3bb8c07728 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1840,11 +1840,14 @@ public class AppOpsService extends IAppOpsService.Stub { } private boolean isPackageSuspendedForUser(String pkg, int uid) { + final long identity = Binder.clearCallingIdentity(); try { return AppGlobals.getPackageManager().isPackageSuspendedForUser( pkg, UserHandle.getUserId(uid)); } catch (RemoteException re) { throw new SecurityException("Could not talk to package manager service"); + } finally { + Binder.restoreCallingIdentity(identity); } } diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index bc78d1ad751f..3dbea0d1978e 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -22,7 +22,6 @@ import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCE import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; import android.Manifest; -import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.annotation.UserIdInt; @@ -51,6 +50,7 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.service.attention.AttentionService; import android.service.attention.AttentionService.AttentionFailureCodes; +import android.service.attention.AttentionService.AttentionSuccessCodes; import android.service.attention.IAttentionCallback; import android.service.attention.IAttentionService; import android.text.TextUtils; @@ -75,6 +75,7 @@ import java.io.PrintWriter; */ public class AttentionManagerService extends SystemService { private static final String LOG_TAG = "AttentionManagerService"; + private static final boolean DEBUG = false; /** * DeviceConfig flag name, allows a CTS to inject a fake implementation. @@ -156,7 +157,11 @@ public class AttentionManagerService extends SystemService { /** * Checks whether user attention is at the screen and calls in the provided callback. * - * @return {@code true} if the framework was able to send the provided callback to the service + * Calling this multiple times quickly in a row will result in either a) returning a cached + * value, if present, or b) returning {@code false} because only one active request at a time is + * allowed. + * + * @return {@code true} if the framework was able to dispatch the request */ private boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) { Preconditions.checkNotNull(callbackInternal); @@ -182,54 +187,30 @@ public class AttentionManagerService extends SystemService { return false; } - if (userState.mService == null) { - // make sure every callback is called back - if (userState.mPendingAttentionCheck != null) { - userState.mPendingAttentionCheck.cancel( - ATTENTION_FAILURE_CANCELLED); + // throttle frequent requests + final AttentionCheckCache cache = userState.mAttentionCheckCache; + if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) { + callbackInternal.onSuccess(cache.mResult, cache.mTimestamp); + return true; + } + + // prevent spamming with multiple requests, only one at a time is allowed + if (userState.mCurrentAttentionCheck != null) { + if (!userState.mCurrentAttentionCheck.mIsDispatched + || !userState.mCurrentAttentionCheck.mIsFulfilled) { + return false; } - // fire the check when the service is started - userState.mPendingAttentionCheck = new PendingAttentionCheck( - callbackInternal, () -> checkAttention(timeout, callbackInternal)); - } else { - try { - // throttle frequent requests - final AttentionCheckCache cache = userState.mAttentionCheckCache; - if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) { - callbackInternal.onSuccess(cache.mResult, cache.mTimestamp); - return true; - } + } + userState.mCurrentAttentionCheck = createAttentionCheck(callbackInternal, userState); + + if (userState.mService != null) { + try { // schedule request cancellation if not returned by that point yet cancelAfterTimeoutLocked(timeout); - - userState.mCurrentAttentionCheck = new AttentionCheck(callbackInternal, - new IAttentionCallback.Stub() { - @Override - public void onSuccess(int result, long timestamp) { - callbackInternal.onSuccess(result, timestamp); - synchronized (mLock) { - userState.mAttentionCheckCache = new AttentionCheckCache( - SystemClock.uptimeMillis(), result, - timestamp); - userState.mCurrentAttentionCheckIsFulfilled = true; - } - StatsLog.write( - StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, - result); - } - - @Override - public void onFailure(int error) { - callbackInternal.onFailure(error); - userState.mCurrentAttentionCheckIsFulfilled = true; - StatsLog.write( - StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, - error); - } - }); userState.mService.checkAttention( userState.mCurrentAttentionCheck.mIAttentionCallback); + userState.mCurrentAttentionCheck.mIsDispatched = true; } catch (RemoteException e) { Slog.e(LOG_TAG, "Cannot call into the AttentionService"); return false; @@ -239,6 +220,44 @@ public class AttentionManagerService extends SystemService { } } + private AttentionCheck createAttentionCheck(AttentionCallbackInternal callbackInternal, + UserState userState) { + final IAttentionCallback iAttentionCallback = new IAttentionCallback.Stub() { + @Override + public void onSuccess(@AttentionSuccessCodes int result, long timestamp) { + // the callback might have been cancelled already + if (!userState.mCurrentAttentionCheck.mIsFulfilled) { + callbackInternal.onSuccess(result, timestamp); + userState.mCurrentAttentionCheck.mIsFulfilled = true; + } + + synchronized (mLock) { + userState.mAttentionCheckCache = new AttentionCheckCache( + SystemClock.uptimeMillis(), result, + timestamp); + } + StatsLog.write( + StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, + result); + } + + @Override + public void onFailure(@AttentionFailureCodes int error) { + // the callback might have been cancelled already + if (!userState.mCurrentAttentionCheck.mIsFulfilled) { + callbackInternal.onFailure(error); + userState.mCurrentAttentionCheck.mIsFulfilled = true; + } + + StatsLog.write( + StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, + error); + } + }; + + return new AttentionCheck(callbackInternal, iAttentionCallback); + } + /** Cancels the specified attention check. */ private void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { synchronized (mLock) { @@ -246,25 +265,13 @@ public class AttentionManagerService extends SystemService { if (userState == null) { return; } - if (userState.mService == null) { - if (userState.mPendingAttentionCheck != null - && userState.mPendingAttentionCheck.mCallbackInternal.equals( - callbackInternal)) { - userState.mPendingAttentionCheck.cancel(ATTENTION_FAILURE_UNKNOWN); - userState.mPendingAttentionCheck = null; - } - return; - } - if (userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) { - try { - userState.mService.cancelAttentionCheck( - userState.mCurrentAttentionCheck.mIAttentionCallback); - } catch (RemoteException e) { - Slog.e(LOG_TAG, "Cannot call into the AttentionService"); - } - } else { + + if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) { Slog.e(LOG_TAG, "Cannot cancel a non-current request"); + return; } + + cancel(userState); } } @@ -272,6 +279,9 @@ public class AttentionManagerService extends SystemService { private void disableSelf() { final long identity = Binder.clearCallingIdentity(); try { + if (DEBUG) { + Slog.d(LOG_TAG, "Disabling self."); + } Settings.System.putInt(mContext.getContentResolver(), ADAPTIVE_SLEEP, 0); } finally { Binder.restoreCallingIdentity(identity); @@ -428,34 +438,21 @@ public class AttentionManagerService extends SystemService { } } - private static final class PendingAttentionCheck { - private final AttentionCallbackInternal mCallbackInternal; - private final Runnable mRunnable; - - PendingAttentionCheck(AttentionCallbackInternal callbackInternal, - Runnable runnable) { - mCallbackInternal = callbackInternal; - mRunnable = runnable; - } - - void cancel(@AttentionFailureCodes int failureCode) { - mCallbackInternal.onFailure(failureCode); - } - - void run() { - mRunnable.run(); - } - } - private static final class AttentionCheck { private final AttentionCallbackInternal mCallbackInternal; private final IAttentionCallback mIAttentionCallback; + private boolean mIsDispatched; + private boolean mIsFulfilled; AttentionCheck(AttentionCallbackInternal callbackInternal, IAttentionCallback iAttentionCallback) { mCallbackInternal = callbackInternal; mIAttentionCallback = iAttentionCallback; } + + void cancelInternal() { + mCallbackInternal.onFailure(ATTENTION_FAILURE_CANCELLED); + } } private static final class UserState { @@ -469,11 +466,6 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") AttentionCheck mCurrentAttentionCheck; @GuardedBy("mLock") - boolean mCurrentAttentionCheckIsFulfilled; - - @GuardedBy("mLock") - PendingAttentionCheck mPendingAttentionCheck; - @GuardedBy("mLock") AttentionCheckCache mAttentionCheckCache; @UserIdInt @@ -491,9 +483,17 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") private void handlePendingCallbackLocked() { - if (mService != null && mPendingAttentionCheck != null) { - mPendingAttentionCheck.run(); - mPendingAttentionCheck = null; + if (!mCurrentAttentionCheck.mIsDispatched) { + if (mService != null) { + try { + mService.checkAttention(mCurrentAttentionCheck.mIAttentionCallback); + mCurrentAttentionCheck.mIsDispatched = true; + } catch (RemoteException e) { + Slog.e(LOG_TAG, "Cannot call into the AttentionService"); + } + } else { + mCurrentAttentionCheck.mCallbackInternal.onFailure(ATTENTION_FAILURE_UNKNOWN); + } } } @@ -526,7 +526,6 @@ public class AttentionManagerService extends SystemService { pw.printPair("userId", mUserId); synchronized (mLock) { pw.printPair("binding", mBinding); - pw.printPair("isAttentionCheckPending", mPendingAttentionCheck != null); } } @@ -586,14 +585,7 @@ public class AttentionManagerService extends SystemService { // Callee is no longer interested in the attention check result - cancel. case ATTENTION_CHECK_TIMEOUT: { synchronized (mLock) { - final UserState userState = peekCurrentUserStateLocked(); - if (userState != null) { - // If not called back already. - if (!userState.mCurrentAttentionCheckIsFulfilled) { - cancel(userState, AttentionService.ATTENTION_FAILURE_TIMED_OUT); - } - - } + cancel(peekCurrentUserStateLocked()); } } break; @@ -604,19 +596,30 @@ public class AttentionManagerService extends SystemService { } } - private void cancel(@NonNull UserState userState, @AttentionFailureCodes int failureCode) { - if (userState.mService != null) { - try { - userState.mService.cancelAttentionCheck( - userState.mCurrentAttentionCheck.mIAttentionCallback); - } catch (RemoteException e) { - Slog.e(LOG_TAG, "Unable to cancel attention check"); - } + private void cancel(UserState userState) { + if (userState == null || userState.mCurrentAttentionCheck == null) { + return; + } - if (userState.mPendingAttentionCheck != null) { - userState.mPendingAttentionCheck.cancel(failureCode); - userState.mPendingAttentionCheck = null; + if (userState.mCurrentAttentionCheck.mIsFulfilled) { + if (DEBUG) { + Slog.d(LOG_TAG, "Trying to cancel the check that has been already fulfilled."); } + return; + } + userState.mCurrentAttentionCheck.mIsFulfilled = true; + + if (userState.mService == null) { + userState.mCurrentAttentionCheck.cancelInternal(); + return; + } + + try { + userState.mService.cancelAttentionCheck( + userState.mCurrentAttentionCheck.mIAttentionCallback); + } catch (RemoteException e) { + Slog.e(LOG_TAG, "Unable to cancel attention check"); + userState.mCurrentAttentionCheck.cancelInternal(); } } @@ -626,7 +629,12 @@ public class AttentionManagerService extends SystemService { if (userState == null) { return; } - cancel(userState, ATTENTION_FAILURE_UNKNOWN); + + cancel(userState); + + if (userState.mService == null) { + return; + } mContext.unbindService(userState.mConnection); userState.mConnection.cleanupService(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 32781a90348b..39dae0b139ad 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -855,8 +855,7 @@ public class AudioService extends IAudioService.Stub public void onSystemReady() { mSystemReady = true; - sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, - 0, 0, null, 0); + scheduleLoadSoundEffects(); mDeviceBroker.onSystemReady(); @@ -3225,6 +3224,14 @@ public class AudioService extends IAudioService.Stub } /** + * Schedule loading samples into the soundpool. + * This method can be overridden to schedule loading at a later time. + */ + protected void scheduleLoadSoundEffects() { + sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0); + } + + /** * Unloads samples from the sound pool. * This method can be called to free some memory when * sound effects are disabled. @@ -3361,8 +3368,14 @@ public class AudioService extends IAudioService.Stub .append(Binder.getCallingPid()).toString(); final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource); if (stateChanged) { - mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) - .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendBroadcastAsUser( + new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } } } diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index 7d4ac592a9df..f7278d2601c3 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -129,13 +129,16 @@ public abstract class AuthenticationClient extends ClientMonitor { boolean result = false; try { + if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + authenticated + ")" + + ", ID:" + identifier.getBiometricId() + + ", Owner: " + getOwnerString() + + ", isBP: " + isBiometricPrompt() + + ", listener: " + listener + + ", requireConfirmation: " + mRequireConfirmation); + if (authenticated) { mAlreadyDone = true; - if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + getOwnerString() - + ", ID:" + identifier.getBiometricId() - + ", isBP: " + isBiometricPrompt() - + ", listener: " + listener - + ", requireConfirmation: " + mRequireConfirmation); + if (listener != null) { vibrateSuccess(); } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 843ecac14b62..153133a6c669 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -41,6 +41,7 @@ import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; @@ -85,6 +86,7 @@ import java.util.Random; public class BiometricService extends SystemService { private static final String TAG = "BiometricService"; + private static final boolean DEBUG = true; private static final int MSG_ON_TASK_STACK_CHANGED = 1; private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2; @@ -96,6 +98,9 @@ public class BiometricService extends SystemService { private static final int MSG_ON_READY_FOR_AUTHENTICATION = 8; private static final int MSG_AUTHENTICATE = 9; private static final int MSG_CANCEL_AUTHENTICATION = 10; + private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11; + private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12; + private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13; private static final int[] FEATURE_ID = { TYPE_FINGERPRINT, @@ -128,8 +133,12 @@ public class BiometricService extends SystemService { * Authentication is successful, but we're waiting for the user to press "confirm" button. */ private static final int STATE_AUTH_PENDING_CONFIRM = 5; + /** + * Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential + */ + private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6; - private final class AuthSession { + private final class AuthSession implements IBinder.DeathRecipient { // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from // <Biometric>Services before we can start authenticating. Pairs that have been returned // are moved to mModalitiesMatched. @@ -164,10 +173,14 @@ public class BiometricService extends SystemService { // Timestamp when hardware authentication occurred private long mAuthenticatedTimeMs; + // TODO(b/123378871): Remove when moved. + private IBiometricConfirmDeviceCredentialCallback mConfirmDeviceCredentialCallback; + AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, int callingUid, int callingPid, int callingUserId, - int modality, boolean requireConfirmation) { + int modality, boolean requireConfirmation, + IBiometricConfirmDeviceCredentialCallback callback) { mModalitiesWaiting = modalities; mToken = token; mSessionId = sessionId; @@ -180,12 +193,25 @@ public class BiometricService extends SystemService { mCallingUserId = callingUserId; mModality = modality; mRequireConfirmation = requireConfirmation; + mConfirmDeviceCredentialCallback = callback; + + if (isFromConfirmDeviceCredential()) { + try { + token.linkToDeath(this, 0 /* flags */); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to link to death", e); + } + } } boolean isCrypto() { return mSessionId != 0; } + boolean isFromConfirmDeviceCredential() { + return mBundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false); + } + boolean containsCookie(int cookie) { if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) { return true; @@ -195,6 +221,25 @@ public class BiometricService extends SystemService { } return false; } + + // TODO(b/123378871): Remove when moved. + @Override + public void binderDied() { + mHandler.post(() -> { + Slog.e(TAG, "Binder died, killing ConfirmDeviceCredential"); + if (mConfirmDeviceCredentialCallback == null) { + Slog.e(TAG, "Callback is null"); + return; + } + + try { + mConfirmDeviceCredentialCallback.cancel(); + mConfirmDeviceCredentialCallback = null; + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send cancel", e); + } + }); + } } private final class BiometricTaskStackListener extends TaskStackListener { @@ -234,6 +279,14 @@ public class BiometricService extends SystemService { private AuthSession mCurrentAuthSession; private AuthSession mPendingAuthSession; + // TODO(b/123378871): Remove when moved. + // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the + // client (app) receiver. BiometricService internally launches CDCA which invokes + // BiometricService to start authentication (normal path). When auth is success/rejected, + // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded + // to this receiver. + private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver; + private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { @@ -311,7 +364,8 @@ public class BiometricService extends SystemService { (Bundle) args.arg5 /* bundle */, args.argi2 /* callingUid */, args.argi3 /* callingPid */, - args.argi4 /* callingUserId */); + args.argi4 /* callingUserId */, + (IBiometricConfirmDeviceCredentialCallback) args.arg6 /* callback */); args.recycle(); break; } @@ -325,7 +379,28 @@ public class BiometricService extends SystemService { break; } + case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS: { + handleOnConfirmDeviceCredentialSuccess(); + break; + } + + case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR: { + SomeArgs args = (SomeArgs) msg.obj; + handleOnConfirmDeviceCredentialError( + args.argi1 /* error */, + (String) args.arg1 /* errorMsg */); + args.recycle(); + break; + } + + case MSG_REGISTER_CANCELLATION_CALLBACK: { + handleRegisterCancellationCallback( + (IBiometricConfirmDeviceCredentialCallback) msg.obj /* callback */); + break; + } + default: + Slog.e(TAG, "Unknown message: " + msg); break; } } @@ -533,14 +608,6 @@ public class BiometricService extends SystemService { * cancelAuthentication() can go to the right place. */ private final class BiometricServiceWrapper extends IBiometricService.Stub { - // TODO(b/123378871): Remove when moved. - // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the - // client (app) receiver. BiometricService internally launches CDCA which invokes - // BiometricService to start authentication (normal path). When auth is success/rejected, - // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded - // to this receiver. - private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver; - @Override // Binder call public void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId) { checkInternalPermission(); @@ -554,12 +621,18 @@ public class BiometricService extends SystemService { @Override // Binder call public void authenticate(IBinder token, long sessionId, int userId, - IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle) + IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, + IBiometricConfirmDeviceCredentialCallback callback) throws RemoteException { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); + // TODO(b/123378871): Remove when moved. + if (callback != null) { + checkInternalPermission(); + } + // In the BiometricServiceBase, check do the AppOps and foreground check. if (userId == callingUserId) { // Check the USE_BIOMETRIC permission here. @@ -576,6 +649,12 @@ public class BiometricService extends SystemService { return; } + final boolean isFromConfirmDeviceCredential = + bundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false); + if (isFromConfirmDeviceCredential) { + checkInternalPermission(); + } + // Check the usage of this in system server. Need to remove this check if it becomes // a public API. final boolean useDefaultTitle = @@ -632,6 +711,7 @@ public class BiometricService extends SystemService { args.argi2 = callingUid; args.argi3 = callingPid; args.argi4 = callingUserId; + args.arg6 = callback; mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget(); } @@ -639,35 +719,30 @@ public class BiometricService extends SystemService { @Override // Binder call public void onConfirmDeviceCredentialSuccess() { checkInternalPermission(); - mHandler.post(() -> { - if (mConfirmDeviceCredentialReceiver == null) { - Slog.w(TAG, "onCDCASuccess null!"); - return; - } - try { - mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded(); - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException", e); - } - mConfirmDeviceCredentialReceiver = null; - }); + + mHandler.sendEmptyMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS); } @Override // Binder call public void onConfirmDeviceCredentialError(int error, String message) { checkInternalPermission(); - mHandler.post(() -> { - if (mConfirmDeviceCredentialReceiver == null) { - Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message); - return; - } - try { - mConfirmDeviceCredentialReceiver.onError(error, message); - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException", e); - } - mConfirmDeviceCredentialReceiver = null; - }); + + SomeArgs args = SomeArgs.obtain(); + args.argi1 = error; + args.arg1 = message; + mHandler.obtainMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR, args).sendToTarget(); + } + + @Override // Binder call + public void registerCancellationCallback( + IBiometricConfirmDeviceCredentialCallback callback) { + // TODO(b/123378871): Remove when moved. + // This callback replaces the one stored in the current session. If the session is null + // we can ignore this, since it means ConfirmDeviceCredential was launched by something + // else (not BiometricPrompt) + checkInternalPermission(); + + mHandler.obtainMessage(MSG_REGISTER_CANCELLATION_CALLBACK, callback).sendToTarget(); } @Override // Binder call @@ -1104,6 +1179,52 @@ public class BiometricService extends SystemService { } } + private void handleOnConfirmDeviceCredentialSuccess() { + if (mConfirmDeviceCredentialReceiver == null) { + Slog.w(TAG, "onCDCASuccess null!"); + return; + } + try { + mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); + mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded(); + if (mCurrentAuthSession != null) { + mCurrentAuthSession.mState = STATE_AUTH_IDLE; + mCurrentAuthSession = null; + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException", e); + } + mConfirmDeviceCredentialReceiver = null; + } + + private void handleOnConfirmDeviceCredentialError(int error, String message) { + if (mConfirmDeviceCredentialReceiver == null) { + Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message); + return; + } + try { + mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); + mConfirmDeviceCredentialReceiver.onError(error, message); + if (mCurrentAuthSession != null) { + mCurrentAuthSession.mState = STATE_AUTH_IDLE; + mCurrentAuthSession = null; + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException", e); + } + mConfirmDeviceCredentialReceiver = null; + } + + private void handleRegisterCancellationCallback( + IBiometricConfirmDeviceCredentialCallback callback) { + if (mCurrentAuthSession == null) { + Slog.d(TAG, "Current auth session null"); + return; + } + Slog.d(TAG, "Updating cancel callback"); + mCurrentAuthSession.mConfirmDeviceCredentialCallback = callback; + } + private void handleOnError(int cookie, int error, String message) { Slog.d(TAG, "Error: " + error + " cookie: " + cookie); // Errors can either be from the current auth session or the pending auth session. @@ -1114,7 +1235,18 @@ public class BiometricService extends SystemService { // of their intended receivers. try { if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) { - if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) { + + if (mCurrentAuthSession.isFromConfirmDeviceCredential()) { + // If we were invoked by ConfirmDeviceCredential, do not delete the current + // auth session since we still need to respond to cancel signal while + if (DEBUG) Slog.d(TAG, "From CDC, transition to CANCELED_SHOWING_CDC state"); + + // Send the error to ConfirmDeviceCredential so that it goes to Pin/Pattern/Pass + // screen + mCurrentAuthSession.mClientReceiver.onError(error, message); + mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC; + mStatusBarService.hideBiometricDialog(); + } else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) { mStatusBarService.onBiometricError(message); if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) { mActivityTaskManager.unregisterTaskStackListener( @@ -1214,9 +1346,16 @@ public class BiometricService extends SystemService { KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow); mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded(); } - mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; - mCurrentAuthSession = null; + + // Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the + // STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when + // ConfirmDeviceCredential is confirmed or canceled. + // TODO(b/123378871): Remove when moved + if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) { + mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); + mCurrentAuthSession.mState = STATE_AUTH_IDLE; + mCurrentAuthSession = null; + } } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); } @@ -1235,7 +1374,8 @@ public class BiometricService extends SystemService { mCurrentAuthSession.mCallingUid, mCurrentAuthSession.mCallingPid, mCurrentAuthSession.mCallingUserId, - mCurrentAuthSession.mModality); + mCurrentAuthSession.mModality, + mCurrentAuthSession.mConfirmDeviceCredentialCallback); } private void handleOnReadyForAuthentication(int cookie, boolean requireConfirmation, @@ -1290,7 +1430,8 @@ public class BiometricService extends SystemService { private void handleAuthenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, - int callingUid, int callingPid, int callingUserId) { + int callingUid, int callingPid, int callingUserId, + IBiometricConfirmDeviceCredentialCallback callback) { mHandler.post(() -> { final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId); @@ -1328,7 +1469,7 @@ public class BiometricService extends SystemService { // Start preparing for authentication. Authentication starts when // all modalities requested have invoked onReadyForAuthentication. authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle, - callingUid, callingPid, callingUserId, modality); + callingUid, callingPid, callingUserId, modality, callback); }); } @@ -1343,7 +1484,8 @@ public class BiometricService extends SystemService { */ private void authenticateInternal(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, - int callingUid, int callingPid, int callingUserId, int modality) { + int callingUid, int callingPid, int callingUserId, int modality, + IBiometricConfirmDeviceCredentialCallback callback) { try { boolean requireConfirmation = bundle.getBoolean( BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */); @@ -1363,7 +1505,7 @@ public class BiometricService extends SystemService { authenticators.put(modality, cookie); mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId, receiver, opPackageName, bundle, callingUid, callingPid, callingUserId, - modality, requireConfirmation); + modality, requireConfirmation, callback); mPendingAuthSession.mState = STATE_AUTH_CALLED; // No polymorphism :( if ((modality & TYPE_FINGERPRINT) != 0) { @@ -1390,10 +1532,23 @@ public class BiometricService extends SystemService { return; } - // We need to check the current authenticators state. If we're pending confirm - // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client, - // since we won't be getting an onError from the driver. - if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) { + if (mCurrentAuthSession != null + && mCurrentAuthSession.mState == STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC) { + if (DEBUG) Slog.d(TAG, "Cancel received while ConfirmDeviceCredential showing"); + try { + mCurrentAuthSession.mConfirmDeviceCredentialCallback.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to cancel ConfirmDeviceCredential", e); + } + + // TODO(b/123378871): Remove when moved. Piggy back on this for now to clean up. + handleOnConfirmDeviceCredentialError(BiometricConstants.BIOMETRIC_ERROR_CANCELED, + getContext().getString(R.string.biometric_error_canceled)); + } else if (mCurrentAuthSession != null + && mCurrentAuthSession.mState != STATE_AUTH_STARTED) { + // We need to check the current authenticators state. If we're pending confirm + // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client, + // since we won't be getting an onError from the driver. try { // Send error to client mCurrentAuthSession.mClientReceiver.onError( @@ -1409,11 +1564,22 @@ public class BiometricService extends SystemService { Slog.e(TAG, "Remote exception", e); } } else { - cancelInternal(token, opPackageName, true /* fromClient */); + boolean fromCDC = false; + if (mCurrentAuthSession != null) { + fromCDC = mCurrentAuthSession.mBundle.getBoolean( + BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false); + } + + if (fromCDC) { + if (DEBUG) Slog.d(TAG, "Cancelling from CDC"); + cancelInternal(token, opPackageName, false /* fromClient */); + } else { + cancelInternal(token, opPackageName, true /* fromClient */); + } + } } - void cancelInternal(IBinder token, String opPackageName, boolean fromClient) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java index 026837f07356..d6aa2ba02f1f 100644 --- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java +++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java @@ -28,6 +28,7 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import java.util.Arrays; @@ -73,15 +74,27 @@ public class DisplayTransformManager { private static final int SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR = 1023; private static final int SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED = 1030; - private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation"; - private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode"; + @VisibleForTesting + static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation"; + @VisibleForTesting + static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode"; private static final float COLOR_SATURATION_NATURAL = 1.0f; private static final float COLOR_SATURATION_BOOSTED = 1.1f; + /** + * Display color modes defined by DisplayColorSetting in + * frameworks/native/services/surfaceflinger/SurfaceFlinger.h. + */ private static final int DISPLAY_COLOR_MANAGED = 0; private static final int DISPLAY_COLOR_UNMANAGED = 1; private static final int DISPLAY_COLOR_ENHANCED = 2; + /** + * Display color mode range reserved for vendor customizations by the RenderIntent definition in + * hardware/interfaces/graphics/common/1.1/types.hal. + */ + private static final int VENDOR_MODE_RANGE_MIN = 256; // 0x100 + private static final int VENDOR_MODE_RANGE_MAX = 511; // 0x1ff /** * Map of level -> color transformation matrix. @@ -257,7 +270,11 @@ public class DisplayTransformManager { } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) { applySaturation(COLOR_SATURATION_NATURAL); setDisplayColor(DISPLAY_COLOR_ENHANCED); + } else if (colorMode >= VENDOR_MODE_RANGE_MIN && colorMode <= VENDOR_MODE_RANGE_MAX) { + applySaturation(COLOR_SATURATION_NATURAL); + setDisplayColor(colorMode); } + setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix); updateConfiguration(); diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java index e7181e23f15d..c32ae97da14f 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java @@ -271,7 +271,7 @@ public class DisplayWhiteBalanceController implements final long time = System.currentTimeMillis(); float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time); - if (mAmbientToDisplayColorTemperatureSpline != null) { + if (mAmbientToDisplayColorTemperatureSpline != null && ambientColorTemperature != -1.0f) { ambientColorTemperature = mAmbientToDisplayColorTemperatureSpline.interpolate(ambientColorTemperature); } diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java index 647727f795da..0f73f379900b 100644 --- a/services/core/java/com/android/server/gpu/GpuService.java +++ b/services/core/java/com/android/server/gpu/GpuService.java @@ -36,6 +36,7 @@ import android.os.Build; import android.os.Handler; import android.os.SystemProperties; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.provider.Settings; import android.util.Base64; import android.util.Slog; @@ -69,9 +70,11 @@ public class GpuService extends SystemService { private final String mDriverPackageName; private final PackageManager mPackageManager; private final Object mLock = new Object(); + private final Object mDeviceConfigLock = new Object(); private ContentResolver mContentResolver; private long mGameDriverVersionCode; private SettingsObserver mSettingsObserver; + private DeviceConfigListener mDeviceConfigListener; @GuardedBy("mLock") private Blacklists mBlacklists; @@ -101,10 +104,11 @@ public class GpuService extends SystemService { public void onBootPhase(int phase) { if (phase == PHASE_BOOT_COMPLETED) { mContentResolver = mContext.getContentResolver(); - mSettingsObserver = new SettingsObserver(); if (mDriverPackageName == null || mDriverPackageName.isEmpty()) { return; } + mSettingsObserver = new SettingsObserver(); + mDeviceConfigListener = new DeviceConfigListener(); fetchGameDriverPackageProperties(); processBlacklists(); setBlacklist(); @@ -134,6 +138,24 @@ public class GpuService extends SystemService { } } + private final class DeviceConfigListener implements DeviceConfig.OnPropertyChangedListener { + + DeviceConfigListener() { + super(); + DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER, + mContext.getMainExecutor(), this); + } + @Override + public void onPropertyChanged(String namespace, String name, String value) { + synchronized (mDeviceConfigLock) { + if (Settings.Global.GAME_DRIVER_BLACKLISTS.equals(name)) { + parseBlacklists(value != null ? value : ""); + setBlacklist(); + } + } + } + } + private final class PackageReceiver extends BroadcastReceiver { @Override public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { @@ -229,13 +251,17 @@ public class GpuService extends SystemService { } private void processBlacklists() { - // TODO(b/121350991) Switch to DeviceConfig with property listener. - String base64String = - Settings.Global.getString(mContentResolver, Settings.Global.GAME_DRIVER_BLACKLISTS); - if (base64String == null || base64String.isEmpty()) { - return; + String base64String = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_GAME_DRIVER, + Settings.Global.GAME_DRIVER_BLACKLISTS); + if (base64String == null) { + base64String = + Settings.Global.getString(mContentResolver, + Settings.Global.GAME_DRIVER_BLACKLISTS); } + parseBlacklists(base64String != null ? base64String : ""); + } + private void parseBlacklists(String base64String) { synchronized (mLock) { // Reset all blacklists mBlacklists = null; diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 647e95284534..d360a6362464 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -231,6 +231,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY | Context.BIND_FOREGROUND_SERVICE + | Context.BIND_INCLUDE_CAPABILITIES | Context.BIND_SHOWING_UI | Context.BIND_SCHEDULE_LIKE_TOP_APP; @@ -4100,13 +4101,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // ---------------------------------------------------------------------- - boolean setInputMethodEnabledLocked(String id, boolean enabled) { - // Make sure this is a valid input method. - InputMethodInfo imm = mMethodMap.get(id); - if (imm == null) { - throw new IllegalArgumentException("Unknown id: " + mCurMethodId); - } - + /** + * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}. + * + * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not + * recognized by the system. + * @param enabled {@code true} if {@code id} needs to be enabled. + * @return {@code true} if the IME was previously enabled. {@code false} otherwise. + */ + private boolean setInputMethodEnabledLocked(String id, boolean enabled) { List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings .getEnabledInputMethodsAndSubtypeListLocked(); @@ -4696,6 +4699,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) { return ShellCommandResult.SUCCESS; } + // Make sure this is a valid input method. + if (enabled && !mMethodMap.containsKey(id)) { + final PrintWriter error = shellCommand.getErrPrintWriter(); + error.print("Unknown input method "); + error.print(id); + error.println(" cannot be enabled"); + return ShellCommandResult.SUCCESS; + } previouslyEnabled = setInputMethodEnabledLocked(id, enabled); } final PrintWriter pr = shellCommand.getOutPrintWriter(); diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java index ab75b21e41ca..2948aafbb931 100644 --- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java +++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java @@ -199,29 +199,27 @@ class GnssNetworkConnectivityHandler { } /** - * called from native code to update AGPS status + * Called from native code to update AGPS connection status, or to request or release a SUPL + * connection. + * + * <p>Note: {@code suplIpAddr} parameter is not present from IAGnssCallback.hal@2.0 onwards + * and is set to {@code null}. */ void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { + if (DEBUG) Log.d(TAG, "AGPS_DATA_CONNECTION: " + agpsDataConnStatusAsString(agpsStatus)); switch (agpsStatus) { case GPS_REQUEST_AGPS_DATA_CONN: - if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); runOnHandler(() -> handleRequestSuplConnection(agpsType, suplIpAddr)); break; case GPS_RELEASE_AGPS_DATA_CONN: - if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); runOnHandler(() -> handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN)); break; case GPS_AGPS_DATA_CONNECTED: - if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); - break; case GPS_AGPS_DATA_CONN_DONE: - if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); - break; case GPS_AGPS_DATA_CONN_FAILED: - if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); break; default: - if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + agpsStatus); + Log.w(TAG, "Received unknown AGPS status: " + agpsStatus); } } @@ -459,11 +457,17 @@ class GnssNetworkConnectivityHandler { } mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; - NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder(); - requestBuilder.addCapability(getNetworkCapability(mAGpsType)); - NetworkRequest request = requestBuilder.build(); + // The NetworkRequest.Builder class is not used to construct the network request because + // the ConnectivityService requires the network request to be constructed in this way + // to extend support for requestRouteToHostAddress() method for pre-gnss@2.0 devices. + NetworkCapabilities networkCapabilities = new NetworkCapabilities(); + networkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + networkCapabilities.addCapability(getNetworkCapability(mAGpsType)); + NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, + getLegacyDataConnectionType(agpsType), ConnectivityManager.REQUEST_ID_UNSET, + NetworkRequest.Type.REQUEST); mConnMgr.requestNetwork( - request, + networkRequest, mSuplConnectivityCallback, mHandler, SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS); @@ -483,6 +487,19 @@ class GnssNetworkConnectivityHandler { } } + private int getLegacyDataConnectionType(int agpsType) { + switch (agpsType) { + case AGPS_TYPE_C2K: + case AGPS_TYPE_SUPL: + return ConnectivityManager.TYPE_MOBILE_SUPL; + case AGPS_TYPE_EIMS: + return ConnectivityManager.TYPE_MOBILE_EMERGENCY; + case AGPS_TYPE_IMS: + return ConnectivityManager.TYPE_MOBILE_IMS; + default: + throw new IllegalArgumentException("agpsType: " + agpsType); + } + } private void handleReleaseSuplConnection(int agpsDataConnStatus) { if (DEBUG) { String message = String.format( @@ -546,7 +563,7 @@ class GnssNetworkConnectivityHandler { case AGPS_DATA_CONNECTION_OPENING: return "OPENING"; default: - return "<Unknown>"; + return "<Unknown>(" + mAGpsDataConnectionState + ")"; } } @@ -566,7 +583,7 @@ class GnssNetworkConnectivityHandler { case GPS_REQUEST_AGPS_DATA_CONN: return "REQUEST"; default: - return "<Unknown>"; + return "<Unknown>(" + agpsDataConnStatus + ")"; } } @@ -581,7 +598,7 @@ class GnssNetworkConnectivityHandler { case AGPS_TYPE_IMS: return "IMS"; default: - return "<Unknown>"; + return "<Unknown>(" + agpsType + ")"; } } @@ -658,4 +675,4 @@ class GnssNetworkConnectivityHandler { private native void native_update_network_state(boolean connected, int type, boolean roaming, boolean available, String apn, long networkHandle, short capabilities); -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f2e56b589bd5..dec47a1082fc 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -29,6 +29,7 @@ import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_ import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.IMPORTANCE_NONE; +import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; @@ -2868,7 +2869,7 @@ public class NotificationManagerService extends SystemService { @Override public void allowAssistantCapability(String adjustmentType) { - checkCallerIsSystemOrShell(); + checkCallerIsSystemOrSystemUiOrShell(); mAssistants.allowAdjustmentType(adjustmentType); handleSavePolicyFile(); @@ -2876,7 +2877,7 @@ public class NotificationManagerService extends SystemService { @Override public void disallowAssistantCapability(String adjustmentType) { - checkCallerIsSystemOrShell(); + checkCallerIsSystemOrSystemUiOrShell(); mAssistants.disallowAdjustmentType(adjustmentType); handleSavePolicyFile(); @@ -3419,8 +3420,7 @@ public class NotificationManagerService extends SystemService { } @Override - public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) - throws RemoteException { + public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) { Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); if (automaticZenRule.getOwner() == null @@ -3429,6 +3429,11 @@ public class NotificationManagerService extends SystemService { "Rule must have a conditionproviderservice and/or configuration activity"); } Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); + if (automaticZenRule.getZenPolicy() != null + && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { + throw new IllegalArgumentException("ZenPolicy is only applicable to " + + "INTERRUPTION_FILTER_PRIORITY filters"); + } enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); return mZenModeHelper.addAutomaticZenRule(automaticZenRule, @@ -3806,7 +3811,7 @@ public class NotificationManagerService extends SystemService { @Override public ComponentName getAllowedNotificationAssistantForUser(int userId) { - checkCallerIsSystem(); + checkCallerIsSystemOrSystemUiOrShell(); List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); if (allowedComponents.size() > 1) { throw new IllegalStateException( @@ -3889,7 +3894,7 @@ public class NotificationManagerService extends SystemService { @Override public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, int userId, boolean granted) { - checkCallerIsSystemOrShell(); + checkCallerIsSystemOrSystemUiOrShell(); mAssistants.setUserSet(userId, true); final long identity = Binder.clearCallingIdentity(); try { @@ -3924,10 +3929,6 @@ public class NotificationManagerService extends SystemService { } } if (!foundEnqueued) { - // adjustment arrived too late to apply to enqueued; apply to posted - // However, since the notification is now posted and may have alerted, - // ignore any importance related adjustments - adjustment.getSignals().remove(Adjustment.KEY_IMPORTANCE); applyAdjustmentFromAssistant(token, adjustment); } } @@ -4118,7 +4119,7 @@ public class NotificationManagerService extends SystemService { } return; } - if (mAllowedManagedServicePackages.test(assistant.getPackageName(), userId, + if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), userId, mAssistants.getRequiredPermission())) { mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(), userId, false, granted); @@ -6990,6 +6991,16 @@ public class NotificationManagerService extends SystemService { throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); } + private void checkCallerIsSystemOrSystemUiOrShell() { + if (Binder.getCallingUid() == Process.SHELL_UID) { + return; + } + if (isCallerSystemOrPhone()) { + return; + } + getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null); + } + private void checkCallerIsSystemOrSameApp(String pkg) { if (isCallerSystemOrPhone()) { return; @@ -7297,7 +7308,7 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mLock") private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>(); - private List<String> mAllowedAdjustments = new ArrayList<>(); + private Set<String> mAllowedAdjustments = new ArraySet<>(); public NotificationAssistants(Context context, Object lock, UserProfiles up, IPackageManager pm) { @@ -7385,12 +7396,18 @@ public class NotificationManagerService extends SystemService { synchronized (mLock) { mAllowedAdjustments.add(type); } + for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { + mHandler.post(() -> notifyCapabilitiesChanged(info)); + } } protected void disallowAdjustmentType(String type) { synchronized (mLock) { mAllowedAdjustments.remove(type); } + for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { + mHandler.post(() -> notifyCapabilitiesChanged(info)); + } } protected List<String> getAllowedAssistantCapabilities() { @@ -7450,6 +7467,15 @@ public class NotificationManagerService extends SystemService { setUserSet(userId, userSet); } + private void notifyCapabilitiesChanged(final ManagedServiceInfo info) { + final INotificationListener assistant = (INotificationListener) info.service; + try { + assistant.onCapabilitiesChanged(); + } catch (RemoteException ex) { + Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex); + } + } + private void notifySeen(final ManagedServiceInfo info, final ArrayList<String> keys) { final INotificationListener assistant = (INotificationListener) info.service; diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index f34b2cb5cf29..642fa7fc3ba6 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -38,7 +38,6 @@ import android.service.notification.RankingHelperProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Pair; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; @@ -180,7 +179,7 @@ public class PreferencesHelper implements RankingConfig { } } - PackagePreferences r = getOrCreatePackagePreferences(name, uid, + PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid, XmlUtils.readIntAttribute( parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE), XmlUtils.readIntAttribute(parser, ATT_PRIORITY, @@ -264,9 +263,9 @@ public class PreferencesHelper implements RankingConfig { } try { - deleteDefaultChannelIfNeeded(r); + deleteDefaultChannelIfNeededLocked(r); } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e); + Slog.e(TAG, "deleteDefaultChannelIfNeededLocked - Exception: " + e); } } } @@ -276,50 +275,46 @@ public class PreferencesHelper implements RankingConfig { throw new IllegalStateException("Failed to reach END_DOCUMENT"); } - private PackagePreferences getPackagePreferences(String pkg, int uid) { + private PackagePreferences getPackagePreferencesLocked(String pkg, int uid) { final String key = packagePreferencesKey(pkg, uid); - synchronized (mPackagePreferences) { - return mPackagePreferences.get(key); - } + return mPackagePreferences.get(key); } - private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid) { - return getOrCreatePackagePreferences(pkg, uid, + private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) { + return getOrCreatePackagePreferencesLocked(pkg, uid, DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE, DEFAULT_ALLOW_BUBBLE); } - private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance, - int priority, int visibility, boolean showBadge, boolean allowBubble) { + private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid, + int importance, int priority, int visibility, boolean showBadge, boolean allowBubble) { final String key = packagePreferencesKey(pkg, uid); - synchronized (mPackagePreferences) { - PackagePreferences - r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg) - : mPackagePreferences.get(key); - if (r == null) { - r = new PackagePreferences(); - r.pkg = pkg; - r.uid = uid; - r.importance = importance; - r.priority = priority; - r.visibility = visibility; - r.showBadge = showBadge; - r.allowBubble = allowBubble; - - try { - createDefaultChannelIfNeeded(r); - } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e); - } + PackagePreferences + r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg) + : mPackagePreferences.get(key); + if (r == null) { + r = new PackagePreferences(); + r.pkg = pkg; + r.uid = uid; + r.importance = importance; + r.priority = priority; + r.visibility = visibility; + r.showBadge = showBadge; + r.allowBubble = allowBubble; + + try { + createDefaultChannelIfNeededLocked(r); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "createDefaultChannelIfNeededLocked - Exception: " + e); + } - if (r.uid == UNKNOWN_UID) { - mRestoredWithoutUids.put(pkg, r); - } else { - mPackagePreferences.put(key, r); - } + if (r.uid == UNKNOWN_UID) { + mRestoredWithoutUids.put(pkg, r); + } else { + mPackagePreferences.put(key, r); } - return r; } + return r; } private boolean shouldHaveDefaultChannel(PackagePreferences r) throws @@ -336,7 +331,7 @@ public class PreferencesHelper implements RankingConfig { return true; } - private void deleteDefaultChannelIfNeeded(PackagePreferences r) throws + private void deleteDefaultChannelIfNeededLocked(PackagePreferences r) throws PackageManager.NameNotFoundException { if (!r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) { // Not present @@ -352,7 +347,7 @@ public class PreferencesHelper implements RankingConfig { r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID); } - private void createDefaultChannelIfNeeded(PackagePreferences r) throws + private void createDefaultChannelIfNeededLocked(PackagePreferences r) throws PackageManager.NameNotFoundException { if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) { r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(mContext.getString( @@ -479,9 +474,11 @@ public class PreferencesHelper implements RankingConfig { * @param allowed whether bubbles are allowed. */ public void setBubblesAllowed(String pkg, int uid, boolean allowed) { - PackagePreferences p = getOrCreatePackagePreferences(pkg, uid); - p.allowBubble = allowed; - p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE; + synchronized (mPackagePreferences) { + PackagePreferences p = getOrCreatePackagePreferencesLocked(pkg, uid); + p.allowBubble = allowed; + p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE; + } } /** @@ -493,11 +490,15 @@ public class PreferencesHelper implements RankingConfig { */ @Override public boolean areBubblesAllowed(String pkg, int uid) { - return getOrCreatePackagePreferences(pkg, uid).allowBubble; + synchronized (mPackagePreferences) { + return getOrCreatePackagePreferencesLocked(pkg, uid).allowBubble; + } } public int getAppLockedFields(String pkg, int uid) { - return getOrCreatePackagePreferences(pkg, uid).lockedAppFields; + synchronized (mPackagePreferences) { + return getOrCreatePackagePreferencesLocked(pkg, uid).lockedAppFields; + } } /** @@ -505,7 +506,9 @@ public class PreferencesHelper implements RankingConfig { */ @Override public int getImportance(String packageName, int uid) { - return getOrCreatePackagePreferences(packageName, uid).importance; + synchronized (mPackagePreferences) { + return getOrCreatePackagePreferencesLocked(packageName, uid).importance; + } } /** @@ -514,18 +517,24 @@ public class PreferencesHelper implements RankingConfig { * locking field, see {@link NotificationChannel#USER_LOCKED_IMPORTANCE}. */ public boolean getIsAppImportanceLocked(String packageName, int uid) { - int userLockedFields = getOrCreatePackagePreferences(packageName, uid).lockedAppFields; - return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0; + synchronized (mPackagePreferences) { + int userLockedFields = getOrCreatePackagePreferencesLocked(packageName, uid).lockedAppFields; + return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0; + } } @Override public boolean canShowBadge(String packageName, int uid) { - return getOrCreatePackagePreferences(packageName, uid).showBadge; + synchronized (mPackagePreferences) { + return getOrCreatePackagePreferencesLocked(packageName, uid).showBadge; + } } @Override public void setShowBadge(String packageName, int uid, boolean showBadge) { - getOrCreatePackagePreferences(packageName, uid).showBadge = showBadge; + synchronized (mPackagePreferences) { + getOrCreatePackagePreferencesLocked(packageName, uid).showBadge = showBadge; + } updateConfig(); } @@ -534,20 +543,26 @@ public class PreferencesHelper implements RankingConfig { if (groupId == null) { return false; } - PackagePreferences r = getOrCreatePackagePreferences(packageName, uid); - NotificationChannelGroup group = r.groups.get(groupId); - if (group == null) { - return false; + synchronized (mPackagePreferences) { + PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); + NotificationChannelGroup group = r.groups.get(groupId); + if (group == null) { + return false; + } + return group.isBlocked(); } - return group.isBlocked(); } int getPackagePriority(String pkg, int uid) { - return getOrCreatePackagePreferences(pkg, uid).priority; + synchronized (mPackagePreferences) { + return getOrCreatePackagePreferencesLocked(pkg, uid).priority; + } } int getPackageVisibility(String pkg, int uid) { - return getOrCreatePackagePreferences(pkg, uid).visibility; + synchronized (mPackagePreferences) { + return getOrCreatePackagePreferencesLocked(pkg, uid).visibility; + } } @Override @@ -557,32 +572,34 @@ public class PreferencesHelper implements RankingConfig { Preconditions.checkNotNull(group); Preconditions.checkNotNull(group.getId()); Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName())); - PackagePreferences r = getOrCreatePackagePreferences(pkg, uid); - if (r == null) { - throw new IllegalArgumentException("Invalid package"); - } - final NotificationChannelGroup oldGroup = r.groups.get(group.getId()); - if (!group.equals(oldGroup)) { - // will log for new entries as well as name/description changes - MetricsLogger.action(getChannelGroupLog(group.getId(), pkg)); - } - if (oldGroup != null) { - group.setChannels(oldGroup.getChannels()); - - // apps can't update the blocked status or app overlay permission - if (fromTargetApp) { - group.setBlocked(oldGroup.isBlocked()); - group.unlockFields(group.getUserLockedFields()); - group.lockFields(oldGroup.getUserLockedFields()); - } else { - // but the system can - if (group.isBlocked() != oldGroup.isBlocked()) { - group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE); - updateChannelsBypassingDnd(mContext.getUserId()); + synchronized (mPackagePreferences) { + PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } + final NotificationChannelGroup oldGroup = r.groups.get(group.getId()); + if (!group.equals(oldGroup)) { + // will log for new entries as well as name/description changes + MetricsLogger.action(getChannelGroupLog(group.getId(), pkg)); + } + if (oldGroup != null) { + group.setChannels(oldGroup.getChannels()); + + // apps can't update the blocked status or app overlay permission + if (fromTargetApp) { + group.setBlocked(oldGroup.isBlocked()); + group.unlockFields(group.getUserLockedFields()); + group.lockFields(oldGroup.getUserLockedFields()); + } else { + // but the system can + if (group.isBlocked() != oldGroup.isBlocked()) { + group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE); + updateChannelsBypassingDnd(mContext.getUserId()); + } } } + r.groups.put(group.getId(), group); } - r.groups.put(group.getId(), group); } @Override @@ -592,94 +609,96 @@ public class PreferencesHelper implements RankingConfig { Preconditions.checkNotNull(channel); Preconditions.checkNotNull(channel.getId()); Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName())); - PackagePreferences r = getOrCreatePackagePreferences(pkg, uid); - if (r == null) { - throw new IllegalArgumentException("Invalid package"); - } - if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) { - throw new IllegalArgumentException("NotificationChannelGroup doesn't exist"); - } - if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) { - throw new IllegalArgumentException("Reserved id"); - } - NotificationChannel existing = r.channels.get(channel.getId()); - // Keep most of the existing settings - if (existing != null && fromTargetApp) { - if (existing.isDeleted()) { - existing.setDeleted(false); - - // log a resurrected channel as if it's new again - MetricsLogger.action(getChannelLog(channel, pkg).setType( - com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); + synchronized (mPackagePreferences) { + PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); } - - existing.setName(channel.getName().toString()); - existing.setDescription(channel.getDescription()); - existing.setBlockableSystem(channel.isBlockableSystem()); - if (existing.getGroup() == null) { - existing.setGroup(channel.getGroup()); + if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) { + throw new IllegalArgumentException("NotificationChannelGroup doesn't exist"); } - - // Apps are allowed to downgrade channel importance if the user has not changed any - // fields on this channel yet. - final int previousExistingImportance = existing.getImportance(); - if (existing.getUserLockedFields() == 0 && - channel.getImportance() < existing.getImportance()) { - existing.setImportance(channel.getImportance()); + if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) { + throw new IllegalArgumentException("Reserved id"); } + NotificationChannel existing = r.channels.get(channel.getId()); + // Keep most of the existing settings + if (existing != null && fromTargetApp) { + if (existing.isDeleted()) { + existing.setDeleted(false); + + // log a resurrected channel as if it's new again + MetricsLogger.action(getChannelLog(channel, pkg).setType( + com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); + } + + existing.setName(channel.getName().toString()); + existing.setDescription(channel.getDescription()); + existing.setBlockableSystem(channel.isBlockableSystem()); + if (existing.getGroup() == null) { + existing.setGroup(channel.getGroup()); + } + + // Apps are allowed to downgrade channel importance if the user has not changed any + // fields on this channel yet. + final int previousExistingImportance = existing.getImportance(); + if (existing.getUserLockedFields() == 0 && + channel.getImportance() < existing.getImportance()) { + existing.setImportance(channel.getImportance()); + } - // system apps and dnd access apps can bypass dnd if the user hasn't changed any - // fields on the channel yet - if (existing.getUserLockedFields() == 0 && hasDndAccess) { - boolean bypassDnd = channel.canBypassDnd(); - existing.setBypassDnd(bypassDnd); + // system apps and dnd access apps can bypass dnd if the user hasn't changed any + // fields on the channel yet + if (existing.getUserLockedFields() == 0 && hasDndAccess) { + boolean bypassDnd = channel.canBypassDnd(); + existing.setBypassDnd(bypassDnd); - if (bypassDnd != mAreChannelsBypassingDnd - || previousExistingImportance != existing.getImportance()) { - updateChannelsBypassingDnd(mContext.getUserId()); + if (bypassDnd != mAreChannelsBypassingDnd + || previousExistingImportance != existing.getImportance()) { + updateChannelsBypassingDnd(mContext.getUserId()); + } } - } - updateConfig(); - return; - } - if (channel.getImportance() < IMPORTANCE_NONE - || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) { - throw new IllegalArgumentException("Invalid importance level"); - } + updateConfig(); + return; + } + if (channel.getImportance() < IMPORTANCE_NONE + || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) { + throw new IllegalArgumentException("Invalid importance level"); + } - // Reset fields that apps aren't allowed to set. - if (fromTargetApp && !hasDndAccess) { - channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); - } - if (fromTargetApp) { - channel.setLockscreenVisibility(r.visibility); - } - clearLockedFields(channel); - channel.setImportanceLockedByOEM(r.oemLockedImportance); - if (!channel.isImportanceLockedByOEM()) { - if (r.futureOemLockedChannels.remove(channel.getId())) { - channel.setImportanceLockedByOEM(true); + // Reset fields that apps aren't allowed to set. + if (fromTargetApp && !hasDndAccess) { + channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); + } + if (fromTargetApp) { + channel.setLockscreenVisibility(r.visibility); + } + clearLockedFieldsLocked(channel); + channel.setImportanceLockedByOEM(r.oemLockedImportance); + if (!channel.isImportanceLockedByOEM()) { + if (r.futureOemLockedChannels.remove(channel.getId())) { + channel.setImportanceLockedByOEM(true); + } + } + channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance); + if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) { + channel.setLockscreenVisibility( + NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE); + } + if (!r.showBadge) { + channel.setShowBadge(false); } - } - channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance); - if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) { - channel.setLockscreenVisibility( - NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE); - } - if (!r.showBadge) { - channel.setShowBadge(false); - } - r.channels.put(channel.getId(), channel); - if (channel.canBypassDnd() != mAreChannelsBypassingDnd) { - updateChannelsBypassingDnd(mContext.getUserId()); + r.channels.put(channel.getId(), channel); + if (channel.canBypassDnd() != mAreChannelsBypassingDnd) { + updateChannelsBypassingDnd(mContext.getUserId()); + } + MetricsLogger.action(getChannelLog(channel, pkg).setType( + com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); } - MetricsLogger.action(getChannelLog(channel, pkg).setType( - com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); } - void clearLockedFields(NotificationChannel channel) { + void clearLockedFieldsLocked(NotificationChannel channel) { channel.unlockFields(channel.getUserLockedFields()); } @@ -688,55 +707,58 @@ public class PreferencesHelper implements RankingConfig { boolean fromUser) { Preconditions.checkNotNull(updatedChannel); Preconditions.checkNotNull(updatedChannel.getId()); - PackagePreferences r = getOrCreatePackagePreferences(pkg, uid); - if (r == null) { - throw new IllegalArgumentException("Invalid package"); - } - NotificationChannel channel = r.channels.get(updatedChannel.getId()); - if (channel == null || channel.isDeleted()) { - throw new IllegalArgumentException("Channel does not exist"); - } - if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) { - updatedChannel.setLockscreenVisibility( - NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE); - } - if (fromUser) { - updatedChannel.lockFields(channel.getUserLockedFields()); - lockFieldsForUpdate(channel, updatedChannel); - } else { - updatedChannel.unlockFields(updatedChannel.getUserLockedFields()); - } - // no importance updates are allowed if OEM blocked it - updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM()); - if (updatedChannel.isImportanceLockedByOEM()) { - updatedChannel.setImportance(channel.getImportance()); - } - updatedChannel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance); - if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) { - updatedChannel.setImportance(channel.getImportance()); - } + synchronized (mPackagePreferences) { + PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } + NotificationChannel channel = r.channels.get(updatedChannel.getId()); + if (channel == null || channel.isDeleted()) { + throw new IllegalArgumentException("Channel does not exist"); + } + if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) { + updatedChannel.setLockscreenVisibility( + NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE); + } + if (fromUser) { + updatedChannel.lockFields(channel.getUserLockedFields()); + lockFieldsForUpdateLocked(channel, updatedChannel); + } else { + updatedChannel.unlockFields(updatedChannel.getUserLockedFields()); + } + // no importance updates are allowed if OEM blocked it + updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM()); + if (updatedChannel.isImportanceLockedByOEM()) { + updatedChannel.setImportance(channel.getImportance()); + } + updatedChannel.setImportanceLockedByCriticalDeviceFunction( + r.defaultAppLockedImportance); + if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) { + updatedChannel.setImportance(channel.getImportance()); + } - r.channels.put(updatedChannel.getId(), updatedChannel); + r.channels.put(updatedChannel.getId(), updatedChannel); - if (onlyHasDefaultChannel(pkg, uid)) { - // copy settings to app level so they are inherited by new channels - // when the app migrates - r.importance = updatedChannel.getImportance(); - r.priority = updatedChannel.canBypassDnd() - ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT; - r.visibility = updatedChannel.getLockscreenVisibility(); - r.showBadge = updatedChannel.canShowBadge(); - } + if (onlyHasDefaultChannel(pkg, uid)) { + // copy settings to app level so they are inherited by new channels + // when the app migrates + r.importance = updatedChannel.getImportance(); + r.priority = updatedChannel.canBypassDnd() + ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT; + r.visibility = updatedChannel.getLockscreenVisibility(); + r.showBadge = updatedChannel.canShowBadge(); + } - if (!channel.equals(updatedChannel)) { - // only log if there are real changes - MetricsLogger.action(getChannelLog(updatedChannel, pkg) - .setSubtype(fromUser ? 1 : 0)); - } + if (!channel.equals(updatedChannel)) { + // only log if there are real changes + MetricsLogger.action(getChannelLog(updatedChannel, pkg) + .setSubtype(fromUser ? 1 : 0)); + } - if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd - || channel.getImportance() != updatedChannel.getImportance()) { - updateChannelsBypassingDnd(mContext.getUserId()); + if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd + || channel.getImportance() != updatedChannel.getImportance()) { + updateChannelsBypassingDnd(mContext.getUserId()); + } } updateConfig(); } @@ -745,35 +767,39 @@ public class PreferencesHelper implements RankingConfig { public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted) { Preconditions.checkNotNull(pkg); - PackagePreferences r = getOrCreatePackagePreferences(pkg, uid); - if (r == null) { + synchronized (mPackagePreferences) { + PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); + if (r == null) { + return null; + } + if (channelId == null) { + channelId = NotificationChannel.DEFAULT_CHANNEL_ID; + } + final NotificationChannel nc = r.channels.get(channelId); + if (nc != null && (includeDeleted || !nc.isDeleted())) { + return nc; + } return null; } - if (channelId == null) { - channelId = NotificationChannel.DEFAULT_CHANNEL_ID; - } - final NotificationChannel nc = r.channels.get(channelId); - if (nc != null && (includeDeleted || !nc.isDeleted())) { - return nc; - } - return null; } @Override public void deleteNotificationChannel(String pkg, int uid, String channelId) { - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return; - } - NotificationChannel channel = r.channels.get(channelId); - if (channel != null) { - channel.setDeleted(true); - LogMaker lm = getChannelLog(channel, pkg); - lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE); - MetricsLogger.action(lm); - - if (mAreChannelsBypassingDnd && channel.canBypassDnd()) { - updateChannelsBypassingDnd(mContext.getUserId()); + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return; + } + NotificationChannel channel = r.channels.get(channelId); + if (channel != null) { + channel.setDeleted(true); + LogMaker lm = getChannelLog(channel, pkg); + lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE); + MetricsLogger.action(lm); + + if (mAreChannelsBypassingDnd && channel.canBypassDnd()) { + updateChannelsBypassingDnd(mContext.getUserId()); + } } } } @@ -783,25 +809,29 @@ public class PreferencesHelper implements RankingConfig { public void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId) { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(channelId); - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return; + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return; + } + r.channels.remove(channelId); } - r.channels.remove(channelId); } @Override public void permanentlyDeleteNotificationChannels(String pkg, int uid) { Preconditions.checkNotNull(pkg); - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return; - } - int N = r.channels.size() - 1; - for (int i = N; i >= 0; i--) { - String key = r.channels.keyAt(i); - if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) { - r.channels.remove(key); + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return; + } + int N = r.channels.size() - 1; + for (int i = N; i >= 0; i--) { + String key = r.channels.keyAt(i); + if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) { + r.channels.remove(key); + } } } } @@ -875,32 +905,36 @@ public class PreferencesHelper implements RankingConfig { public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg, int uid, String groupId, boolean includeDeleted) { Preconditions.checkNotNull(pkg); - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null || groupId == null || !r.groups.containsKey(groupId)) { - return null; - } - NotificationChannelGroup group = r.groups.get(groupId).clone(); - group.setChannels(new ArrayList<>()); - int N = r.channels.size(); - for (int i = 0; i < N; i++) { - final NotificationChannel nc = r.channels.valueAt(i); - if (includeDeleted || !nc.isDeleted()) { - if (groupId.equals(nc.getGroup())) { - group.addChannel(nc); + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null || groupId == null || !r.groups.containsKey(groupId)) { + return null; + } + NotificationChannelGroup group = r.groups.get(groupId).clone(); + group.setChannels(new ArrayList<>()); + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (includeDeleted || !nc.isDeleted()) { + if (groupId.equals(nc.getGroup())) { + group.addChannel(nc); + } } } + return group; } - return group; } public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg, int uid) { Preconditions.checkNotNull(pkg); - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return null; + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return null; + } + return r.groups.get(groupId); } - return r.groups.get(groupId); } @Override @@ -908,60 +942,64 @@ public class PreferencesHelper implements RankingConfig { int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) { Preconditions.checkNotNull(pkg); Map<String, NotificationChannelGroup> groups = new ArrayMap<>(); - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return ParceledListSlice.emptyList(); - } - NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null); - int N = r.channels.size(); - for (int i = 0; i < N; i++) { - final NotificationChannel nc = r.channels.valueAt(i); - if (includeDeleted || !nc.isDeleted()) { - if (nc.getGroup() != null) { - if (r.groups.get(nc.getGroup()) != null) { - NotificationChannelGroup ncg = groups.get(nc.getGroup()); - if (ncg == null) { - ncg = r.groups.get(nc.getGroup()).clone(); - ncg.setChannels(new ArrayList<>()); - groups.put(nc.getGroup(), ncg); + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return ParceledListSlice.emptyList(); + } + NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null); + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (includeDeleted || !nc.isDeleted()) { + if (nc.getGroup() != null) { + if (r.groups.get(nc.getGroup()) != null) { + NotificationChannelGroup ncg = groups.get(nc.getGroup()); + if (ncg == null) { + ncg = r.groups.get(nc.getGroup()).clone(); + ncg.setChannels(new ArrayList<>()); + groups.put(nc.getGroup(), ncg); + } + ncg.addChannel(nc); } - ncg.addChannel(nc); + } else { + nonGrouped.addChannel(nc); } - } else { - nonGrouped.addChannel(nc); } } - } - if (includeNonGrouped && nonGrouped.getChannels().size() > 0) { - groups.put(null, nonGrouped); - } - if (includeEmpty) { - for (NotificationChannelGroup group : r.groups.values()) { - if (!groups.containsKey(group.getId())) { - groups.put(group.getId(), group); + if (includeNonGrouped && nonGrouped.getChannels().size() > 0) { + groups.put(null, nonGrouped); + } + if (includeEmpty) { + for (NotificationChannelGroup group : r.groups.values()) { + if (!groups.containsKey(group.getId())) { + groups.put(group.getId(), group); + } } } + return new ParceledListSlice<>(new ArrayList<>(groups.values())); } - return new ParceledListSlice<>(new ArrayList<>(groups.values())); } public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid, String groupId) { List<NotificationChannel> deletedChannels = new ArrayList<>(); - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null || TextUtils.isEmpty(groupId)) { - return deletedChannels; - } + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null || TextUtils.isEmpty(groupId)) { + return deletedChannels; + } - r.groups.remove(groupId); + r.groups.remove(groupId); - int N = r.channels.size(); - for (int i = 0; i < N; i++) { - final NotificationChannel nc = r.channels.valueAt(i); - if (groupId.equals(nc.getGroup())) { - nc.setDeleted(true); - deletedChannels.add(nc); + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (groupId.equals(nc.getGroup())) { + nc.setDeleted(true); + deletedChannels.add(nc); + } } } return deletedChannels; @@ -970,11 +1008,15 @@ public class PreferencesHelper implements RankingConfig { @Override public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg, int uid) { - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return new ArrayList<>(); + List<NotificationChannelGroup> groups = new ArrayList<>(); + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return groups; + } + groups.addAll(r.groups.values()); } - return r.groups.values(); + return groups; } @Override @@ -982,18 +1024,20 @@ public class PreferencesHelper implements RankingConfig { boolean includeDeleted) { Preconditions.checkNotNull(pkg); List<NotificationChannel> channels = new ArrayList<>(); - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return ParceledListSlice.emptyList(); - } - int N = r.channels.size(); - for (int i = 0; i < N; i++) { - final NotificationChannel nc = r.channels.valueAt(i); - if (includeDeleted || !nc.isDeleted()) { - channels.add(nc); + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return ParceledListSlice.emptyList(); } + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (includeDeleted || !nc.isDeleted()) { + channels.add(nc); + } + } + return new ParceledListSlice<>(channels); } - return new ParceledListSlice<>(channels); } /** @@ -1008,7 +1052,7 @@ public class PreferencesHelper implements RankingConfig { // notifications from this package aren't blocked if (r != null && r.importance != IMPORTANCE_NONE) { for (NotificationChannel channel : r.channels.values()) { - if (channelIsLive(r, channel) && channel.canBypassDnd()) { + if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { channels.add(channel); } } @@ -1024,46 +1068,52 @@ public class PreferencesHelper implements RankingConfig { * upgrades. */ public boolean onlyHasDefaultChannel(String pkg, int uid) { - PackagePreferences r = getOrCreatePackagePreferences(pkg, uid); - if (r.channels.size() == 1 - && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) { - return true; + synchronized (mPackagePreferences) { + PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); + if (r.channels.size() == 1 + && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) { + return true; + } + return false; } - return false; } public int getDeletedChannelCount(String pkg, int uid) { Preconditions.checkNotNull(pkg); int deletedCount = 0; - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return deletedCount; - } - int N = r.channels.size(); - for (int i = 0; i < N; i++) { - final NotificationChannel nc = r.channels.valueAt(i); - if (nc.isDeleted()) { - deletedCount++; + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return deletedCount; } + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (nc.isDeleted()) { + deletedCount++; + } + } + return deletedCount; } - return deletedCount; } public int getBlockedChannelCount(String pkg, int uid) { Preconditions.checkNotNull(pkg); int blockedCount = 0; - PackagePreferences r = getPackagePreferences(pkg, uid); - if (r == null) { - return blockedCount; - } - int N = r.channels.size(); - for (int i = 0; i < N; i++) { - final NotificationChannel nc = r.channels.valueAt(i); - if (!nc.isDeleted() && IMPORTANCE_NONE == nc.getImportance()) { - blockedCount++; + synchronized (mPackagePreferences) { + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return blockedCount; + } + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (!nc.isDeleted() && IMPORTANCE_NONE == nc.getImportance()) { + blockedCount++; + } } + return blockedCount; } - return blockedCount; } public int getBlockedAppCount(int userId) { @@ -1098,7 +1148,7 @@ public class PreferencesHelper implements RankingConfig { } for (NotificationChannel channel : r.channels.values()) { - if (channelIsLive(r, channel) && channel.canBypassDnd()) { + if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { count++; break; } @@ -1136,7 +1186,7 @@ public class PreferencesHelper implements RankingConfig { } for (NotificationChannel channel : r.channels.values()) { - if (channelIsLive(r, channel) && channel.canBypassDnd()) { + if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { if (!mAreChannelsBypassingDnd) { mAreChannelsBypassingDnd = true; updateZenPolicy(true); @@ -1153,7 +1203,7 @@ public class PreferencesHelper implements RankingConfig { } } - private boolean channelIsLive(PackagePreferences pkgPref, NotificationChannel channel) { + private boolean channelIsLiveLocked(PackagePreferences pkgPref, NotificationChannel channel) { // Channel is in a group that's blocked if (isGroupBlocked(pkgPref.pkg, pkgPref.uid, channel.getGroup())) { return false; @@ -1185,7 +1235,9 @@ public class PreferencesHelper implements RankingConfig { */ @Override public void setImportance(String pkgName, int uid, int importance) { - getOrCreatePackagePreferences(pkgName, uid).importance = importance; + synchronized (mPackagePreferences) { + getOrCreatePackagePreferencesLocked(pkgName, uid).importance = importance; + } updateConfig(); } @@ -1204,12 +1256,15 @@ public class PreferencesHelper implements RankingConfig { * considered for sentiment adjustments (and thus never show a blocking helper). */ public void setAppImportanceLocked(String packageName, int uid) { - PackagePreferences prefs = getOrCreatePackagePreferences(packageName, uid); - if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) { - return; - } + synchronized (mPackagePreferences) { + PackagePreferences prefs = getOrCreatePackagePreferencesLocked(packageName, uid); + if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) { + return; + } - prefs.lockedAppFields = prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE; + prefs.lockedAppFields = + prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE; + } updateConfig(); } @@ -1217,15 +1272,17 @@ public class PreferencesHelper implements RankingConfig { * Returns the delegate for a given package, if it's allowed by the package and the user. */ public @Nullable String getNotificationDelegate(String sourcePkg, int sourceUid) { - PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid); + synchronized (mPackagePreferences) { + PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid); - if (prefs == null || prefs.delegate == null) { - return null; - } - if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) { - return null; + if (prefs == null || prefs.delegate == null) { + return null; + } + if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) { + return null; + } + return prefs.delegate.mPkg; } - return prefs.delegate.mPkg; } /** @@ -1233,11 +1290,13 @@ public class PreferencesHelper implements RankingConfig { */ public void setNotificationDelegate(String sourcePkg, int sourceUid, String delegatePkg, int delegateUid) { - PackagePreferences prefs = getOrCreatePackagePreferences(sourcePkg, sourceUid); + synchronized (mPackagePreferences) { + PackagePreferences prefs = getOrCreatePackagePreferencesLocked(sourcePkg, sourceUid); - boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed; - Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed); - prefs.delegate = delegate; + boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed; + Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed); + prefs.delegate = delegate; + } updateConfig(); } @@ -1245,9 +1304,15 @@ public class PreferencesHelper implements RankingConfig { * Used by an app to turn off its notification delegate. */ public void revokeNotificationDelegate(String sourcePkg, int sourceUid) { - PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid); - if (prefs != null && prefs.delegate != null) { - prefs.delegate.mEnabled = false; + boolean changed = false; + synchronized (mPackagePreferences) { + PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid); + if (prefs != null && prefs.delegate != null) { + prefs.delegate.mEnabled = false; + changed = true; + } + } + if (changed) { updateConfig(); } } @@ -1256,9 +1321,15 @@ public class PreferencesHelper implements RankingConfig { * Toggles whether an app can have a notification delegate on behalf of a user. */ public void toggleNotificationDelegate(String sourcePkg, int sourceUid, boolean userAllowed) { - PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid); - if (prefs != null && prefs.delegate != null) { - prefs.delegate.mUserAllowed = userAllowed; + boolean changed = false; + synchronized (mPackagePreferences) { + PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid); + if (prefs != null && prefs.delegate != null) { + prefs.delegate.mUserAllowed = userAllowed; + changed = true; + } + } + if (changed) { updateConfig(); } } @@ -1269,13 +1340,16 @@ public class PreferencesHelper implements RankingConfig { */ public boolean isDelegateAllowed(String sourcePkg, int sourceUid, String potentialDelegatePkg, int potentialDelegateUid) { - PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid); + synchronized (mPackagePreferences) { + PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid); - return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, potentialDelegateUid); + return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, + potentialDelegateUid); + } } @VisibleForTesting - void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) { + void lockFieldsForUpdateLocked(NotificationChannel original, NotificationChannel update) { if (original.canBypassDnd() != update.canBypassDnd()) { update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); } @@ -1309,30 +1383,30 @@ public class PreferencesHelper implements RankingConfig { pw.print(prefix); pw.println("per-package config:"); - pw.println("PackagePreferencess:"); + pw.println("PackagePreferences:"); synchronized (mPackagePreferences) { - dumpPackagePreferencess(pw, prefix, filter, mPackagePreferences); + dumpPackagePreferencesLocked(pw, prefix, filter, mPackagePreferences); } pw.println("Restored without uid:"); - dumpPackagePreferencess(pw, prefix, filter, mRestoredWithoutUids); + dumpPackagePreferencesLocked(pw, prefix, filter, mRestoredWithoutUids); } public void dump(ProtoOutputStream proto, @NonNull NotificationManagerService.DumpFilter filter) { synchronized (mPackagePreferences) { - dumpPackagePreferencess(proto, RankingHelperProto.RECORDS, filter, + dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS, filter, mPackagePreferences); } - dumpPackagePreferencess(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter, + dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter, mRestoredWithoutUids); } - private static void dumpPackagePreferencess(PrintWriter pw, String prefix, + private static void dumpPackagePreferencesLocked(PrintWriter pw, String prefix, @NonNull NotificationManagerService.DumpFilter filter, - ArrayMap<String, PackagePreferences> PackagePreferencess) { - final int N = PackagePreferencess.size(); + ArrayMap<String, PackagePreferences> packagePreferences) { + final int N = packagePreferences.size(); for (int i = 0; i < N; i++) { - final PackagePreferences r = PackagePreferencess.valueAt(i); + final PackagePreferences r = packagePreferences.valueAt(i); if (filter.matches(r.pkg)) { pw.print(prefix); pw.print(" AppSettings: "); @@ -1369,13 +1443,13 @@ public class PreferencesHelper implements RankingConfig { } } - private static void dumpPackagePreferencess(ProtoOutputStream proto, long fieldId, + private static void dumpPackagePreferencesLocked(ProtoOutputStream proto, long fieldId, @NonNull NotificationManagerService.DumpFilter filter, - ArrayMap<String, PackagePreferences> PackagePreferencess) { - final int N = PackagePreferencess.size(); + ArrayMap<String, PackagePreferences> packagePreferences) { + final int N = packagePreferences.size(); long fToken; for (int i = 0; i < N; i++) { - final PackagePreferences r = PackagePreferencess.valueAt(i); + final PackagePreferences r = packagePreferences.valueAt(i); if (filter.matches(r.pkg)) { fToken = proto.start(fieldId); @@ -1626,11 +1700,11 @@ public class PreferencesHelper implements RankingConfig { // Package upgrade try { synchronized (mPackagePreferences) { - PackagePreferences fullPackagePreferences = getPackagePreferences(pkg, + PackagePreferences fullPackagePreferences = getPackagePreferencesLocked(pkg, mPm.getPackageUidAsUser(pkg, changeUserId)); if (fullPackagePreferences != null) { - createDefaultChannelIfNeeded(fullPackagePreferences); - deleteDefaultChannelIfNeeded(fullPackagePreferences); + createDefaultChannelIfNeededLocked(fullPackagePreferences); + deleteDefaultChannelIfNeededLocked(fullPackagePreferences); } } } catch (PackageManager.NameNotFoundException e) { diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 51d5acc9b555..ee07c7de9dbc 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -166,6 +166,13 @@ import java.util.concurrent.atomic.AtomicBoolean; * . . . . . . . . . . . . . . . . . . . . . . * </pre> * + * <p>To test the OMS, execute: + * <code> + * atest FrameworksServicesTests:com.android.server.om # internal tests + * atest OverlayDeviceTests OverlayHostTests # public API tests + * </code> + * </p> + * * <p>Finally, here is a list of keywords used in the OMS context.</p> * * <ul> diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index 36b5beb7bbb2..f35c70780db9 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -26,6 +26,7 @@ import android.util.ArrayMap; import android.util.Slog; import android.util.Xml; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; @@ -327,7 +328,8 @@ final class OverlayManagerSettings { Serializer.persist(mItems, os); } - private static final class Serializer { + @VisibleForTesting + static final class Serializer { private static final String TAG_OVERLAYS = "overlays"; private static final String TAG_ITEM = "item"; @@ -343,7 +345,8 @@ final class OverlayManagerSettings { private static final String ATTR_USER_ID = "userId"; private static final String ATTR_VERSION = "version"; - private static final int CURRENT_VERSION = 3; + @VisibleForTesting + static final int CURRENT_VERSION = 3; public static void restore(@NonNull final ArrayList<SettingsItem> table, @NonNull final InputStream is) throws IOException, XmlPullParserException { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1ce9d827d80f..6c5abe49fe13 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -757,124 +757,9 @@ public class PackageManagerService extends IPackageManager.Stub @Override public final boolean hasFeature(String feature) { return PackageManagerService.this.hasSystemFeature(feature, 0); } - - final List<PackageParser.Package> getStaticOverlayPackages( - Collection<PackageParser.Package> allPackages, String targetPackageName) { - if ("android".equals(targetPackageName)) { - // Static RROs targeting to "android", ie framework-res.apk, are already applied by - // native AssetManager. - return null; - } - - List<PackageParser.Package> overlayPackages = null; - for (PackageParser.Package p : allPackages) { - if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) { - if (overlayPackages == null) { - overlayPackages = new ArrayList<>(); - } - overlayPackages.add(p); - } - } - if (overlayPackages != null) { - Comparator<PackageParser.Package> cmp = - Comparator.comparingInt(p -> p.mOverlayPriority); - overlayPackages.sort(cmp); - } - return overlayPackages; - } - - final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages, - String targetPath) { - if (overlayPackages == null || overlayPackages.isEmpty()) { - return null; - } - List<String> overlayPathList = null; - for (PackageParser.Package overlayPackage : overlayPackages) { - if (targetPath == null) { - if (overlayPathList == null) { - overlayPathList = new ArrayList<>(); - } - overlayPathList.add(overlayPackage.baseCodePath); - continue; - } - - try { - // Creates idmaps for system to parse correctly the Android manifest of the - // target package. - // - // OverlayManagerService will update each of them with a correct gid from its - // target package app id. - mInstaller.idmap(targetPath, overlayPackage.baseCodePath, - UserHandle.getSharedAppGid( - UserHandle.getUserGid(UserHandle.USER_SYSTEM))); - if (overlayPathList == null) { - overlayPathList = new ArrayList<>(); - } - overlayPathList.add(overlayPackage.baseCodePath); - } catch (InstallerException e) { - Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " + - overlayPackage.baseCodePath); - } - } - return overlayPathList == null ? null : overlayPathList.toArray(new String[0]); - } - - String[] getStaticOverlayPaths(String targetPackageName, String targetPath) { - List<PackageParser.Package> overlayPackages; - synchronized (mInstallLock) { - synchronized (mPackages) { - overlayPackages = getStaticOverlayPackages( - mPackages.values(), targetPackageName); - } - // It is safe to keep overlayPackages without holding mPackages because static overlay - // packages can't be uninstalled or disabled. - return getStaticOverlayPaths(overlayPackages, targetPath); - } - } - - @Override public final String[] getOverlayApks(String targetPackageName) { - return getStaticOverlayPaths(targetPackageName, null); - } - - @Override public final String[] getOverlayPaths(String targetPackageName, - String targetPath) { - return getStaticOverlayPaths(targetPackageName, targetPath); - } - } - - class ParallelPackageParserCallback extends PackageParserCallback { - List<PackageParser.Package> mOverlayPackages = null; - - void findStaticOverlayPackages() { - synchronized (mPackages) { - for (PackageParser.Package p : mPackages.values()) { - if (p.mOverlayIsStatic) { - if (mOverlayPackages == null) { - mOverlayPackages = new ArrayList<>(); - } - mOverlayPackages.add(p); - } - } - } - } - - @Override - synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) { - // We can trust mOverlayPackages without holding mPackages because package uninstall - // can't happen while running parallel parsing. - // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock - // because mInstallLock is held before running parallel parsing. - // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock. - return mOverlayPackages == null ? null : - getStaticOverlayPaths( - getStaticOverlayPackages(mOverlayPackages, targetPackageName), - targetPath); - } } final PackageParser.Callback mPackageParserCallback = new PackageParserCallback(); - final ParallelPackageParserCallback mParallelPackageParserCallback = - new ParallelPackageParserCallback(); // Currently known shared libraries. final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>(); @@ -2558,8 +2443,6 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_ODM, 0); - mParallelPackageParserCallback.findStaticOverlayPackages(); - // Find base frameworks (resource packages without code). scanDirTracedLI(frameworkDir, mDefParseFlags @@ -8782,7 +8665,7 @@ public class PackageManagerService extends IPackageManager.Stub } try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser( mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, - mParallelPackageParserCallback)) { + mPackageParserCallback)) { // Submit files for parsing in parallel int fileCount = 0; for (File file : files) { @@ -24816,11 +24699,9 @@ public class PackageManagerService extends IPackageManager.Stub } if (mExternalSourcesPolicy != null) { int isTrusted = mExternalSourcesPolicy.getPackageTrustedToInstallApps(packageName, uid); - if (isTrusted != PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT) { - return isTrusted == PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED; - } + return isTrusted == PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED; } - return checkUidPermission(appOpPermission, uid) == PERMISSION_GRANTED; + return false; } @Override diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index d52ba169768f..9908b3657121 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2629,7 +2629,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub 0, null, new UserHandle(serviceUserId))); if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI - | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, + | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE + | Context.BIND_INCLUDE_CAPABILITIES, new UserHandle(serviceUserId))) { String msg = "Unable to bind service: " + componentName; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e08e1ff01348..e2253e7f83ce 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -693,13 +693,13 @@ final class ActivityRecord extends ConfigurationContainer { } } - void scheduleTopResumedActivityChanged(boolean onTop) { + boolean scheduleTopResumedActivityChanged(boolean onTop) { if (!attachedToProcess()) { if (DEBUG_STATES) { Slog.w(TAG, "Can't report activity position update - client not running" + ", activityRecord=" + this); } - return; + return false; } try { if (DEBUG_STATES) { @@ -710,7 +710,9 @@ final class ActivityRecord extends ConfigurationContainer { TopResumedActivityChangeItem.obtain(onTop)); } catch (RemoteException e) { // If process died, whatever. + return false; } + return true; } void updateMultiWindowMode() { @@ -3408,7 +3410,6 @@ final class ActivityRecord extends ConfigurationContainer { transaction.addCallback(callbackItem); transaction.setLifecycleStateRequest(lifecycleItem); mAtmService.getLifecycleManager().scheduleTransaction(transaction); - mStackSupervisor.updateTopResumedActivityIfNeeded(); // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only // request resume if this activity is currently resumed, which implies we aren't // sleeping. diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index fad4dbd5613b..419f5be5bbc8 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -1500,7 +1500,6 @@ class ActivityStack extends ConfigurationContainer { + " callers=" + Debug.getCallers(5)); r.setState(RESUMED, "minimalResumeActivityLocked"); r.completeResumeLocked(); - mStackSupervisor.updateTopResumedActivityIfNeeded(); if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Launch completed; removing icicle of " + r.icicle); } @@ -2571,7 +2570,6 @@ class ActivityStack extends ConfigurationContainer { // Protect against recursion. mInResumeTopActivity = true; result = resumeTopActivityInnerLocked(prev, options); - mStackSupervisor.updateTopResumedActivityIfNeeded(); // When resuming the top activity, it may be necessary to pause the top activity (for // example, returning to the lock screen. We suppress the normal pause logic in @@ -2606,6 +2604,7 @@ class ActivityStack extends ConfigurationContainer { if (DEBUG_STACK) Slog.d(TAG_STACK, "setResumedActivity stack:" + this + " + from: " + mResumedActivity + " to:" + r + " reason:" + reason); mResumedActivity = r; + mStackSupervisor.updateTopResumedActivityIfNeeded(); } @GuardedBy("mService") diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 53dc1df5a46a..afdbd73d520d 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -853,7 +853,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // Schedule transaction. mService.getLifecycleManager().scheduleTransaction(clientTransaction); - updateTopResumedActivityIfNeeded(); if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 && mService.mHasHeavyWeightFeature) { @@ -2321,8 +2320,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // mTopResumedActivityWaitingForPrev == true at this point would mean that an activity // before the prevTopActivity one hasn't reported back yet. So server never sent the top // resumed state change message to prevTopActivity. - if (prevActivityReceivedTopState) { - prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */); + if (prevActivityReceivedTopState + && prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */)) { scheduleTopResumedStateLossTimeout(prevTopActivity); mTopResumedActivityWaitingForPrev = true; } diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index f9980bebca9e..c1d872f23f0f 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -73,6 +73,13 @@ public class BoundsAnimationController { /** Schedule a PiP mode changed callback when this animation ends. */ public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2; + public static final int BOUNDS = 0; + public static final int FADE_IN = 1; + + @IntDef({BOUNDS, FADE_IN}) public @interface AnimationType {} + + private static final int FADE_IN_DURATION = 500; + // Only accessed on UI thread. private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); @@ -115,6 +122,7 @@ public class BoundsAnimationController { private boolean mFinishAnimationAfterTransition = false; private final AnimationHandler mAnimationHandler; private Choreographer mChoreographer; + private @AnimationType int mAnimationType; private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000; @@ -140,6 +148,7 @@ public class BoundsAnimationController { implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { private final BoundsAnimationTarget mTarget; + private final @AnimationType int mAnimationType; private final Rect mFrom = new Rect(); private final Rect mTo = new Rect(); private final Rect mTmpRect = new Rect(); @@ -166,8 +175,8 @@ public class BoundsAnimationController { // Depending on whether we are animating from // a smaller to a larger size - private final int mFrozenTaskWidth; - private final int mFrozenTaskHeight; + private int mFrozenTaskWidth; + private int mFrozenTaskHeight; // Timeout callback to ensure we continue the animation if waiting for resuming or app // windows drawn fails @@ -176,12 +185,13 @@ public class BoundsAnimationController { resume(); }; - BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to, - @SchedulePipModeChangedState int schedulePipModeChangedState, + BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from, + Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState, @SchedulePipModeChangedState int prevShedulePipModeChangedState, boolean moveFromFullscreen, boolean moveToFullscreen, Rect frozenTask) { super(); mTarget = target; + mAnimationType = animationType; mFrom.set(from); mTo.set(to); mSchedulePipModeChangedState = schedulePipModeChangedState; @@ -195,12 +205,14 @@ public class BoundsAnimationController { // to their final size immediately so we can use scaling to make the window // larger. Likewise if we are going from bigger to smaller, we want to wait until // the end so we don't have to upscale from the smaller finished size. - if (animatingToLargerSize()) { - mFrozenTaskWidth = mTo.width(); - mFrozenTaskHeight = mTo.height(); - } else { - mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width(); - mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height(); + if (mAnimationType == BOUNDS) { + if (animatingToLargerSize()) { + mFrozenTaskWidth = mTo.width(); + mFrozenTaskHeight = mTo.height(); + } else { + mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width(); + mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height(); + } } } @@ -222,8 +234,9 @@ public class BoundsAnimationController { // otherwise. boolean continueAnimation; if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) { - continueAnimation = mTarget.onAnimationStart(mSchedulePipModeChangedState == - SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */); + continueAnimation = mTarget.onAnimationStart( + mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START, + false /* forceUpdate */, mAnimationType); // When starting an animation from fullscreen, pause here and wait for the // windows-drawn signal before we start the rest of the transition down into PiP. @@ -238,7 +251,8 @@ public class BoundsAnimationController { // However, we still need to report to them that they are leaving PiP, so this will // force an update via a mode changed callback. continueAnimation = mTarget.onAnimationStart( - true /* schedulePipModeChangedCallback */, true /* forceUpdate */); + true /* schedulePipModeChangedCallback */, true /* forceUpdate */, + mAnimationType); } else { // The animation is already running, but we should check that the TaskStack is still // valid before continuing with the animation @@ -285,6 +299,13 @@ public class BoundsAnimationController { @Override public void onAnimationUpdate(ValueAnimator animation) { final float value = (Float) animation.getAnimatedValue(); + if (mAnimationType == FADE_IN) { + if (!mTarget.setPinnedStackAlpha(value)) { + cancelAndCallAnimationEnd(); + } + return; + } + final float remains = 1 - value; mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value + 0.5f); mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f); @@ -408,16 +429,29 @@ public class BoundsAnimationController { public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to, int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, - boolean moveFromFullscreen, boolean moveToFullscreen) { + boolean moveFromFullscreen, boolean moveToFullscreen, + @AnimationType int animationType) { animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState, - moveFromFullscreen, moveToFullscreen); + moveFromFullscreen, moveToFullscreen, animationType); } @VisibleForTesting BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to, int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, - boolean moveFromFullscreen, boolean moveToFullscreen) { + boolean moveFromFullscreen, boolean moveToFullscreen, + @AnimationType int animationType) { final BoundsAnimator existing = mRunningAnimations.get(target); + // animateBoundsImpl gets called twice for each animation. The second time we get the final + // to rect that respects the shelf, which is when we want to resize. Our signal for fade in + // comes in from how to enter into pip, but we also need to use the to and from rect to + // decide which animation we want to run finally. + boolean shouldResize = false; + if (isRunningFadeInAnimation(target)) { + shouldResize = true; + if (from.contains(to)) { + animationType = FADE_IN; + } + } final boolean replacing = existing != null; @SchedulePipModeChangedState int prevSchedulePipModeChangedState = NO_PIP_MODE_CHANGED_CALLBACKS; @@ -477,18 +511,34 @@ public class BoundsAnimationController { // Since we are replacing, we skip both animation start and end callbacks existing.cancel(); } - final BoundsAnimator animator = new BoundsAnimator(target, from, to, + if (shouldResize) { + target.setPinnedStackSize(to, null); + } + final BoundsAnimator animator = new BoundsAnimator(target, animationType, from, to, schedulePipModeChangedState, prevSchedulePipModeChangedState, moveFromFullscreen, moveToFullscreen, frozenTask); mRunningAnimations.put(target, animator); animator.setFloatValues(0f, 1f); - animator.setDuration((animationDuration != -1 ? animationDuration - : DEFAULT_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR); + animator.setDuration(animationType == FADE_IN ? FADE_IN_DURATION + : (animationDuration != -1 ? animationDuration : DEFAULT_TRANSITION_DURATION) + * DEBUG_ANIMATION_SLOW_DOWN_FACTOR); animator.setInterpolator(mFastOutSlowInInterpolator); animator.start(); return animator; } + public void setAnimationType(@AnimationType int animationType) { + mAnimationType = animationType; + } + + /** return the current animation type. */ + public @AnimationType int getAnimationType() { + @AnimationType int animationType = mAnimationType; + // Default to BOUNDS. + mAnimationType = BOUNDS; + return animationType; + } + public Handler getHandler() { return mHandler; } @@ -498,6 +548,11 @@ public class BoundsAnimationController { mHandler.post(this::resume); } + private boolean isRunningFadeInAnimation(final BoundsAnimationTarget target) { + final BoundsAnimator existing = mRunningAnimations.get(target); + return existing != null && existing.mAnimationType == FADE_IN && existing.isStarted(); + } + private void resume() { for (int i = 0; i < mRunningAnimations.size(); i++) { final BoundsAnimator b = mRunningAnimations.valueAt(i); diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java index 5cb80de1a36d..9f54e49e0022 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java @@ -32,7 +32,8 @@ interface BoundsAnimationTarget { * callbacks * @return whether to continue the animation */ - boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate); + boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate, + @BoundsAnimationController.AnimationType int animationType); /** * @return Whether the animation should be paused waiting for the windows to draw before @@ -53,6 +54,9 @@ interface BoundsAnimationTarget { */ boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds); + /** Sets the alpha of the animation target */ + boolean setPinnedStackAlpha(float alpha); + /** * Callback for the target to inform it that the animation has ended, so it can do some * necessary cleanup. diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 144efb49e84a..07d3fb990470 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -26,6 +26,8 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.WindowManager.TRANSIT_NONE; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.BoundsAnimationController.BOUNDS; +import static com.android.server.wm.BoundsAnimationController.FADE_IN; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; @@ -201,7 +203,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } } - private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { + private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode, + boolean sendUserLeaveHint) { synchronized (mService.mGlobalLock) { if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller=" + mWindowManager.getRecentsAnimationController() @@ -246,7 +249,18 @@ class RecentsAnimation implements RecentsAnimationCallbacks, if (reorderMode == REORDER_MOVE_TO_TOP) { // Bring the target stack to the front mStackSupervisor.mNoAnimActivities.add(targetActivity); - targetStack.moveToFront("RecentsAnimation.onAnimationFinished()"); + + if (sendUserLeaveHint) { + // Setting this allows the previous app to PiP. + mStackSupervisor.mUserLeaving = true; + targetStack.moveTaskToFrontLocked(targetActivity.getTaskRecord(), + true /* noAnimation */, null /* activityOptions */, + targetActivity.appTimeTracker, + "RecentsAnimation.onAnimationFinished()"); + } else { + targetStack.moveToFront("RecentsAnimation.onAnimationFinished()"); + } + if (DEBUG) { final ActivityStack topStack = getTopNonAlwaysOnTopStack(); if (topStack != targetStack) { @@ -300,11 +314,11 @@ class RecentsAnimation implements RecentsAnimationCallbacks, @Override public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode, - boolean runSychronously) { + boolean runSychronously, boolean sendUserLeaveHint) { if (runSychronously) { - finishAnimation(reorderMode); + finishAnimation(reorderMode, sendUserLeaveHint); } else { - mService.mH.post(() -> finishAnimation(reorderMode)); + mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint)); } } @@ -317,6 +331,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } final RecentsAnimationController controller = mWindowManager.getRecentsAnimationController(); + final DisplayContent dc = + mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent; + dc.mBoundsAnimationController.setAnimationType( + controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS); // Cancel running recents animation and screenshot previous task when the next // transition starts in below cases: diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 381366995dd5..d2c510fa8902 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -27,6 +27,7 @@ import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM; import static com.android.server.wm.AnimationAdapterProto.REMOTE; +import static com.android.server.wm.BoundsAnimationController.FADE_IN; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; @@ -142,7 +143,9 @@ public class RecentsAnimationController implements DeathRecipient { }; public interface RecentsAnimationCallbacks { - void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously); + /** Callback when recents animation is finished. */ + void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously, + boolean sendUserLeaveHint); } private final IRecentsAnimationController mController = @@ -179,7 +182,7 @@ public class RecentsAnimationController implements DeathRecipient { } @Override - public void finish(boolean moveHomeToTop) { + public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) { if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):" + " mCanceled=" + mCanceled); final long token = Binder.clearCallingIdentity(); @@ -195,7 +198,9 @@ public class RecentsAnimationController implements DeathRecipient { mCallbacks.onAnimationFinished(moveHomeToTop ? REORDER_MOVE_TO_TOP : REORDER_MOVE_TO_ORIGINAL_POSITION, - true /* runSynchronously */); + true /* runSynchronously */, sendUserLeaveHint); + final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId); + dc.mBoundsAnimationController.setAnimationType(FADE_IN); } finally { Binder.restoreCallingIdentity(token); } @@ -497,7 +502,8 @@ public class RecentsAnimationController implements DeathRecipient { Slog.e(TAG, "Failed to cancel recents animation", e); } // Clean up and return to the previous app - mCallbacks.onAnimationFinished(reorderMode, runSynchronously); + mCallbacks.onAnimationFinished(reorderMode, runSynchronously, + false /* sendUserLeaveHint */); } } @@ -542,7 +548,8 @@ public class RecentsAnimationController implements DeathRecipient { if (DEBUG_RECENTS_ANIMATIONS) { Slog.d(TAG, "mRecentScreenshotAnimator finish"); } - mCallbacks.onAnimationFinished(reorderMode, runSynchronously); + mCallbacks.onAnimationFinished(reorderMode, runSynchronously, + false /* sendUserLeaveHint */); }, mService); mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator); } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 09baf8cf1111..bdb4d0474865 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -34,6 +34,7 @@ import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; +import static com.android.server.wm.BoundsAnimationController.FADE_IN; import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS; import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START; @@ -148,6 +149,7 @@ public class TaskStack extends WindowContainer<Task> implements private boolean mCancelCurrentBoundsAnimation = false; private Rect mBoundsAnimationTarget = new Rect(); private Rect mBoundsAnimationSourceHintBounds = new Rect(); + private @BoundsAnimationController.AnimationType int mAnimationType; Rect mPreAnimationBounds = new Rect(); @@ -1572,7 +1574,8 @@ public class TaskStack extends WindowContainer<Task> implements } @Override // AnimatesBounds - public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) { + public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate, + @BoundsAnimationController.AnimationType int animationType) { // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mWmService.mGlobalLock) { if (!isAttached()) { @@ -1583,6 +1586,7 @@ public class TaskStack extends WindowContainer<Task> implements mBoundsAnimatingRequested = false; mBoundsAnimating = true; mCancelCurrentBoundsAnimation = false; + mAnimationType = animationType; // If we are changing UI mode, as in the PiP to fullscreen // transition, then we need to wait for the window to draw. @@ -1599,7 +1603,8 @@ public class TaskStack extends WindowContainer<Task> implements // I don't believe you... } - if (schedulePipModeChangedCallback && mActivityStack != null) { + if ((schedulePipModeChangedCallback || animationType == FADE_IN) + && mActivityStack != null) { // We need to schedule the PiP mode change before the animation up. It is possible // in this case for the animation down to not have been completed, so always // force-schedule and update to the client to ensure that it is notified that it @@ -1614,6 +1619,21 @@ public class TaskStack extends WindowContainer<Task> implements @Override // AnimatesBounds public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize, boolean moveToFullscreen) { + if (mAnimationType == BoundsAnimationController.FADE_IN) { + setPinnedStackAlpha(1f); + try { + mWmService.mActivityTaskManager.notifyPinnedStackAnimationEnded(); + } catch (RemoteException e) { + // I don't believe you... + } + return; + } + + onBoundAnimationEnd(schedulePipModeChangedCallback, finalStackSize, moveToFullscreen); + } + + private void onBoundAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize, + boolean moveToFullscreen) { if (inPinnedWindowingMode()) { // Update to the final bounds if requested. This is done here instead of in the bounds // animator to allow us to coordinate this after we notify the PiP mode changed @@ -1725,10 +1745,23 @@ public class TaskStack extends WindowContainer<Task> implements final @SchedulePipModeChangedState int finalSchedulePipModeChangedState = schedulePipModeChangedState; final DisplayContent displayContent = getDisplayContent(); + @BoundsAnimationController.AnimationType int intendedAnimationType = + displayContent.mBoundsAnimationController.getAnimationType(); + if (intendedAnimationType == FADE_IN) { + if (fromFullscreen) { + setPinnedStackAlpha(0f); + } + if (toBounds.width() == fromBounds.width() + && toBounds.height() == fromBounds.height()) { + intendedAnimationType = BoundsAnimationController.BOUNDS; + } + } + + final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType; displayContent.mBoundsAnimationController.getHandler().post(() -> { displayContent.mBoundsAnimationController.animateBounds(this, fromBounds, finalToBounds, animationDuration, finalSchedulePipModeChangedState, - fromFullscreen, toFullscreen); + fromFullscreen, toFullscreen, animationType); }); } @@ -1905,6 +1938,20 @@ public class TaskStack extends WindowContainer<Task> implements } } + @Override + public boolean setPinnedStackAlpha(float alpha) { + // Hold the lock since this is called from the BoundsAnimator running on the UiThread + synchronized (mWmService.mGlobalLock) { + if (mCancelCurrentBoundsAnimation) { + return false; + } + getPendingTransaction().setAlpha(getSurfaceControl(), alpha); + scheduleAnimation(); + } + + return true; + } + public DisplayInfo getDisplayInfo() { return mDisplayContent.getDisplayInfo(); } diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index fce7599d0b59..01f2f6b26415 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -68,6 +68,7 @@ <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" /> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.HARDWARE_TEST"/> <!-- Uses API introduced in O (26) --> <uses-sdk android:minSdkVersion="1" diff --git a/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java new file mode 100644 index 000000000000..fc74c972ed83 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display.color; + +import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; +import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR; +import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION; + +import static com.google.common.truth.Truth.assertThat; + +import android.hardware.display.ColorDisplayManager; +import android.os.SystemProperties; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class DisplayTransformManagerTest { + + private DisplayTransformManager mDtm; + private float[] mNightDisplayMatrix; + + @Before + public void setUp() { + mDtm = new DisplayTransformManager(); + mNightDisplayMatrix = mDtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY); + + SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, null); + SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, null); + } + + @Test + public void setColorMode_natural() { + mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + .isEqualTo("0" /* managed */); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + .isEqualTo("1.0" /* natural */); + } + + @Test + public void setColorMode_boosted() { + mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + .isEqualTo("0" /* managed */); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + .isEqualTo("1.1" /* boosted */); + } + + @Test + public void setColorMode_saturated() { + mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + .isEqualTo("1" /* unmanaged */); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + .isEqualTo("1.0" /* natural */); + } + + @Test + public void setColorMode_automatic() { + mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + .isEqualTo("2" /* enhanced */); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + .isEqualTo("1.0" /* natural */); + } + + @Test + public void setColorMode_vendor() { + mDtm.setColorMode(0x100, mNightDisplayMatrix); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + .isEqualTo(Integer.toString(0x100) /* pass-through */); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + .isEqualTo("1.0" /* default */); + } + + @Test + public void setColorMode_outOfBounds() { + mDtm.setColorMode(0x50, mNightDisplayMatrix); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + .isEqualTo("" /* default */); + assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + .isEqualTo("" /* default */); + } +} diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java new file mode 100644 index 000000000000..3f9a57e07876 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.om; + +import static android.content.om.OverlayInfo.STATE_DISABLED; +import static android.content.om.OverlayInfo.STATE_ENABLED; +import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; +import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.annotation.NonNull; +import android.content.om.OverlayInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.util.ArraySet; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +public class OverlayManagerServiceImplTests { + private OverlayManagerServiceImpl mImpl; + private DummyDeviceState mState; + private DummyListener mListener; + + private static final String OVERLAY = "com.dummy.overlay"; + private static final String TARGET = "com.dummy.target"; + private static final int USER = 0; + + private static final String OVERLAY2 = OVERLAY + "2"; + private static final String TARGET2 = TARGET + "2"; + private static final int USER2 = USER + 1; + + private static final String OVERLAY3 = OVERLAY + "3"; + private static final int USER3 = USER2 + 1; + + + @Before + public void setUp() throws Exception { + mState = new DummyDeviceState(); + mListener = new DummyListener(); + DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState); + mImpl = new OverlayManagerServiceImpl(pmh, + new DummyIdmapManager(mState, pmh), + new OverlayManagerSettings(), + new String[0], + mListener); + } + + // tests: basics + + @Test + public void testGetOverlayInfo() throws Exception { + installOverlayPackage(OVERLAY, TARGET, USER, false); + final OverlayInfo oi = mImpl.getOverlayInfo(OVERLAY, USER); + assertNotNull(oi); + assertEquals(oi.packageName, OVERLAY); + assertEquals(oi.targetPackageName, TARGET); + assertEquals(oi.userId, USER); + } + + @Test + public void testGetOverlayInfosForTarget() throws Exception { + installOverlayPackage(OVERLAY, TARGET, USER, false); + installOverlayPackage(OVERLAY2, TARGET, USER, false); + + installOverlayPackage(OVERLAY3, TARGET, USER2, false); + + final List<OverlayInfo> ois = mImpl.getOverlayInfosForTarget(TARGET, USER); + assertEquals(ois.size(), 2); + assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER))); + assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER))); + + final List<OverlayInfo> ois2 = mImpl.getOverlayInfosForTarget(TARGET, USER2); + assertEquals(ois2.size(), 1); + assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER2))); + + final List<OverlayInfo> ois3 = mImpl.getOverlayInfosForTarget(TARGET, USER3); + assertNotNull(ois3); + assertEquals(ois3.size(), 0); + + final List<OverlayInfo> ois4 = mImpl.getOverlayInfosForTarget("no.such.overlay", USER); + assertNotNull(ois4); + assertEquals(ois4.size(), 0); + } + + @Test + public void testGetOverlayInfosForUser() throws Exception { + installOverlayPackage(OVERLAY, TARGET, USER, false); + installOverlayPackage(OVERLAY2, TARGET, USER, false); + installOverlayPackage(OVERLAY3, TARGET2, USER, false); + + final Map<String, List<OverlayInfo>> everything = mImpl.getOverlaysForUser(USER); + assertEquals(everything.size(), 2); + + final List<OverlayInfo> ois = everything.get(TARGET); + assertNotNull(ois); + assertEquals(ois.size(), 2); + assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER))); + assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER))); + + final List<OverlayInfo> ois2 = everything.get(TARGET2); + assertNotNull(ois2); + assertEquals(ois2.size(), 1); + assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER))); + + final Map<String, List<OverlayInfo>> everything2 = mImpl.getOverlaysForUser(USER2); + assertNotNull(everything2); + assertEquals(everything2.size(), 0); + } + + @Test + public void testPriority() throws Exception { + installOverlayPackage(OVERLAY, TARGET, USER, false); + installOverlayPackage(OVERLAY2, TARGET, USER, false); + installOverlayPackage(OVERLAY3, TARGET, USER, false); + + final OverlayInfo o1 = mImpl.getOverlayInfo(OVERLAY, USER); + final OverlayInfo o2 = mImpl.getOverlayInfo(OVERLAY2, USER); + final OverlayInfo o3 = mImpl.getOverlayInfo(OVERLAY3, USER); + + assertOverlayInfoList(TARGET, USER, o1, o2, o3); + + assertTrue(mImpl.setLowestPriority(OVERLAY3, USER)); + assertOverlayInfoList(TARGET, USER, o3, o1, o2); + + assertTrue(mImpl.setHighestPriority(OVERLAY3, USER)); + assertOverlayInfoList(TARGET, USER, o1, o2, o3); + + assertTrue(mImpl.setPriority(OVERLAY, OVERLAY2, USER)); + assertOverlayInfoList(TARGET, USER, o2, o1, o3); + } + + @Test + public void testOverlayInfoStateTransitions() throws Exception { + assertNull(mImpl.getOverlayInfo(OVERLAY, USER)); + + installOverlayPackage(OVERLAY, TARGET, USER, true); + assertState(STATE_MISSING_TARGET, OVERLAY, USER); + + installTargetPackage(TARGET, USER); + assertState(STATE_DISABLED, OVERLAY, USER); + + mImpl.setEnabled(OVERLAY, true, USER); + assertState(STATE_ENABLED, OVERLAY, USER); + + beginUpgradeTargetPackage(TARGET, USER); + assertState(STATE_TARGET_IS_BEING_REPLACED, OVERLAY, USER); + + endUpgradeTargetPackage(TARGET, USER); + assertState(STATE_ENABLED, OVERLAY, USER); + + uninstallTargetPackage(TARGET, USER); + assertState(STATE_MISSING_TARGET, OVERLAY, USER); + + installTargetPackage(TARGET, USER); + assertState(STATE_ENABLED, OVERLAY, USER); + } + + @Test + public void testUpdateOverlaysForUser() throws Exception { + installTargetPackage(TARGET, USER); + installTargetPackage("some.other.target", USER); + installOverlayPackage(OVERLAY, TARGET, USER, true); + + // do nothing, expect no change + List<String> a = mImpl.updateOverlaysForUser(USER); + assertEquals(1, a.size()); + assertTrue(a.contains(TARGET)); + + // upgrade overlay, keep target + upgradeOverlayPackage(OVERLAY, TARGET, USER, true); + List<String> b = mImpl.updateOverlaysForUser(USER); + assertEquals(1, b.size()); + assertTrue(b.contains(TARGET)); + + // do nothing, expect no change + List<String> c = mImpl.updateOverlaysForUser(USER); + assertEquals(1, c.size()); + assertTrue(c.contains(TARGET)); + + // upgrade overlay, switch to new target + upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true); + List<String> d = mImpl.updateOverlaysForUser(USER); + assertEquals(2, d.size()); + assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target"))); + + // do nothing, expect no change + List<String> e = mImpl.updateOverlaysForUser(USER); + assertEquals(1, e.size()); + assertTrue(e.contains("some.other.target")); + } + + @Test + public void testOnOverlayPackageUpgraded() throws Exception { + installTargetPackage(TARGET, USER); + installOverlayPackage(OVERLAY, TARGET, USER, true); + mImpl.onOverlayPackageReplacing(OVERLAY, USER); + mListener.count = 0; + mImpl.onOverlayPackageReplaced(OVERLAY, USER); + assertEquals(1, mListener.count); + + // upgrade to a version where the overlay has changed its target + upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true); + mImpl.onOverlayPackageReplacing(OVERLAY, USER); + mListener.count = 0; + mImpl.onOverlayPackageReplaced(OVERLAY, USER); + // expect once for the old target package, once for the new target package + assertEquals(2, mListener.count); + + upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true); + mImpl.onOverlayPackageReplacing(OVERLAY, USER); + mListener.count = 0; + mImpl.onOverlayPackageReplaced(OVERLAY, USER); + assertEquals(1, mListener.count); + } + + // tests: listener interface + + @Test + public void testListener() throws Exception { + installOverlayPackage(OVERLAY, TARGET, USER, true); + assertEquals(1, mListener.count); + mListener.count = 0; + + installTargetPackage(TARGET, USER); + assertEquals(1, mListener.count); + mListener.count = 0; + + mImpl.setEnabled(OVERLAY, true, USER); + assertEquals(1, mListener.count); + mListener.count = 0; + + mImpl.setEnabled(OVERLAY, true, USER); + assertEquals(0, mListener.count); + } + + // helper methods + + private void assertState(int expected, final String overlayPackageName, int userId) { + int actual = mImpl.getOverlayInfo(OVERLAY, USER).state; + String msg = String.format("expected %s but was %s:", + OverlayInfo.stateToString(expected), OverlayInfo.stateToString(actual)); + assertEquals(msg, expected, actual); + } + + private void assertOverlayInfoList(final String targetPackageName, int userId, + OverlayInfo... overlayInfos) { + final List<OverlayInfo> expected = + mImpl.getOverlayInfosForTarget(targetPackageName, userId); + final List<OverlayInfo> actual = Arrays.asList(overlayInfos); + assertEquals(expected, actual); + } + + private void installTargetPackage(String packageName, int userId) { + if (mState.select(packageName, userId) != null) { + throw new IllegalStateException("package already installed"); + } + mState.add(packageName, null, userId, false); + mImpl.onTargetPackageAdded(packageName, userId); + } + + private void beginUpgradeTargetPackage(String packageName, int userId) { + if (mState.select(packageName, userId) == null) { + throw new IllegalStateException("package not installed"); + } + mState.add(packageName, null, userId, false); + mImpl.onTargetPackageReplacing(packageName, userId); + } + + private void endUpgradeTargetPackage(String packageName, int userId) { + if (mState.select(packageName, userId) == null) { + throw new IllegalStateException("package not installed"); + } + mState.add(packageName, null, userId, false); + mImpl.onTargetPackageReplaced(packageName, userId); + } + + private void uninstallTargetPackage(String packageName, int userId) { + if (mState.select(packageName, userId) == null) { + throw new IllegalStateException("package not installed"); + } + mState.remove(packageName, userId); + mImpl.onTargetPackageRemoved(packageName, userId); + } + + private void installOverlayPackage(String packageName, String targetPackageName, int userId, + boolean canCreateIdmap) { + if (mState.select(packageName, userId) != null) { + throw new IllegalStateException("package already installed"); + } + mState.add(packageName, targetPackageName, userId, canCreateIdmap); + mImpl.onOverlayPackageAdded(packageName, userId); + } + + private void upgradeOverlayPackage(String packageName, String targetPackageName, int userId, + boolean canCreateIdmap) { + DummyDeviceState.Package pkg = mState.select(packageName, userId); + if (pkg == null) { + throw new IllegalStateException("package not installed, cannot upgrade"); + } + pkg.targetPackageName = targetPackageName; + pkg.canCreateIdmap = canCreateIdmap; + } + + private void uninstallOverlayPackage(String packageName, int userId) { + // implement this when adding support for downloadable overlays + throw new IllegalArgumentException("not implemented"); + } + + private static final class DummyDeviceState { + private List<Package> mPackages = new ArrayList<>(); + + public void add(String packageName, String targetPackageName, int userId, + boolean canCreateIdmap) { + remove(packageName, userId); + Package pkg = new Package(); + pkg.packageName = packageName; + pkg.targetPackageName = targetPackageName; + pkg.userId = userId; + pkg.canCreateIdmap = canCreateIdmap; + mPackages.add(pkg); + } + + public void remove(String packageName, int userId) { + final Iterator<Package> iter = mPackages.iterator(); + while (iter.hasNext()) { + final Package pkg = iter.next(); + if (pkg.packageName.equals(packageName) && pkg.userId == userId) { + iter.remove(); + return; + } + } + } + + public List<Package> select(int userId) { + List<Package> out = new ArrayList<>(); + final int packageCount = mPackages.size(); + for (int i = 0; i < packageCount; i++) { + final Package pkg = mPackages.get(i); + if (pkg.userId == userId) { + out.add(pkg); + } + } + return out; + } + + public Package select(String packageName, int userId) { + final int packageCount = mPackages.size(); + for (int i = 0; i < packageCount; i++) { + final Package pkg = mPackages.get(i); + if (pkg.packageName.equals(packageName) && pkg.userId == userId) { + return pkg; + } + } + return null; + } + + private static final class Package { + public String packageName; + public int userId; + public String targetPackageName; + public boolean canCreateIdmap; + } + } + + private static final class DummyPackageManagerHelper implements + OverlayManagerServiceImpl.PackageManagerHelper { + private final DummyDeviceState mState; + + DummyPackageManagerHelper(DummyDeviceState state) { + mState = state; + } + + @Override + public PackageInfo getPackageInfo(@NonNull String packageName, int userId) { + final DummyDeviceState.Package pkg = mState.select(packageName, userId); + if (pkg == null) { + return null; + } + ApplicationInfo ai = new ApplicationInfo(); + ai.sourceDir = String.format("%s/%s/base.apk", + pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/", + pkg.packageName); + PackageInfo pi = new PackageInfo(); + pi.applicationInfo = ai; + pi.packageName = pkg.packageName; + pi.overlayTarget = pkg.targetPackageName; + pi.overlayCategory = "dummy-category-" + pkg.targetPackageName; + return pi; + } + + @Override + public boolean signaturesMatching(@NonNull String packageName1, + @NonNull String packageName2, int userId) { + return false; + } + + @Override + public List<PackageInfo> getOverlayPackages(int userId) { + List<PackageInfo> out = new ArrayList<>(); + final List<DummyDeviceState.Package> packages = mState.select(userId); + final int packageCount = packages.size(); + for (int i = 0; i < packageCount; i++) { + final DummyDeviceState.Package pkg = packages.get(i); + if (pkg.targetPackageName != null) { + out.add(getPackageInfo(pkg.packageName, pkg.userId)); + } + } + return out; + } + } + + private static class DummyIdmapManager extends IdmapManager { + private final DummyDeviceState mState; + private Set<String> mIdmapFiles = new ArraySet<>(); + + DummyIdmapManager(DummyDeviceState state, DummyPackageManagerHelper packageManagerHelper) { + super(null, packageManagerHelper); + mState = state; + } + + @Override + boolean createIdmap(@NonNull final PackageInfo targetPackage, + @NonNull final PackageInfo overlayPackage, int userId) { + final DummyDeviceState.Package t = mState.select(targetPackage.packageName, userId); + if (t == null) { + return false; + } + final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId); + if (o == null) { + return false; + } + if (!o.canCreateIdmap) { + return false; + } + final String key = createKey(overlayPackage.packageName, userId); + mIdmapFiles.add(key); + return true; + } + + @Override + boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) { + final String key = createKey(oi.packageName, oi.userId); + if (!mIdmapFiles.contains(key)) { + return false; + } + mIdmapFiles.remove(key); + return true; + } + + @Override + boolean idmapExists(@NonNull final OverlayInfo oi) { + final String key = createKey(oi.packageName, oi.userId); + return mIdmapFiles.contains(key); + } + + @Override + boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) { + final String key = createKey(overlayPackage.packageName, userId); + return mIdmapFiles.contains(key); + } + + private String createKey(@NonNull final String packageName, final int userId) { + return String.format("%s:%d", packageName, userId); + } + } + + private static class DummyListener implements OverlayManagerServiceImpl.OverlayChangeListener { + public int count; + + public void onOverlaysChanged(@NonNull String targetPackage, int userId) { + count++; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java new file mode 100644 index 000000000000..8ff8b6e4a9e0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.om; + +import static android.content.om.OverlayInfo.STATE_DISABLED; +import static android.content.om.OverlayInfo.STATE_ENABLED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.om.OverlayInfo; +import android.text.TextUtils; +import android.util.Xml; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +@RunWith(AndroidJUnit4.class) +public class OverlayManagerSettingsTests { + private OverlayManagerSettings mSettings; + + private static final OverlayInfo OVERLAY_A0 = new OverlayInfo( + "com.dummy.overlay_a", + "com.dummy.target", + null, + "some-category", + "/data/app/com.dummy.overlay_a-1/base.apk", + STATE_DISABLED, + 0, + 0, + false); + + private static final OverlayInfo OVERLAY_B0 = new OverlayInfo( + "com.dummy.overlay_b", + "com.dummy.target", + null, + "some-category", + "/data/app/com.dummy.overlay_b-1/base.apk", + STATE_DISABLED, + 0, + 0, + false); + + private static final OverlayInfo OVERLAY_C0 = new OverlayInfo( + "com.dummy.overlay_c", + "com.dummy.target", + null, + "some-category", + "/data/app/com.dummy.overlay_c-1/base.apk", + STATE_DISABLED, + 0, + 0, + false); + + private static final OverlayInfo OVERLAY_A1 = new OverlayInfo( + "com.dummy.overlay_a", + "com.dummy.target", + null, + "some-category", + "/data/app/com.dummy.overlay_a-1/base.apk", + STATE_DISABLED, + 1, + 0, + false); + + private static final OverlayInfo OVERLAY_B1 = new OverlayInfo( + "com.dummy.overlay_b", + "com.dummy.target", + null, + "some-category", + "/data/app/com.dummy.overlay_b-1/base.apk", + STATE_DISABLED, + 1, + 0, + false); + + @Before + public void setUp() throws Exception { + mSettings = new OverlayManagerSettings(); + } + + // tests: generic functionality + + @Test + public void testSettingsInitiallyEmpty() throws Exception { + final int userId = 0; + Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(userId); + assertEquals(0, map.size()); + } + + @Test + public void testBasicSetAndGet() throws Exception { + assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId); + + insert(OVERLAY_A0); + assertContains(mSettings, OVERLAY_A0); + OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId); + assertEquals(OVERLAY_A0, oi); + + assertTrue(mSettings.remove(OVERLAY_A0.packageName, OVERLAY_A0.userId)); + assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId); + } + + @Test + public void testGetUsers() throws Exception { + int[] users = mSettings.getUsers(); + assertEquals(0, users.length); + + insert(OVERLAY_A0); + users = mSettings.getUsers(); + assertEquals(1, users.length); + assertContains(users, OVERLAY_A0.userId); + + insert(OVERLAY_A1); + insert(OVERLAY_B1); + users = mSettings.getUsers(); + assertEquals(2, users.length); + assertContains(users, OVERLAY_A0.userId); + assertContains(users, OVERLAY_A1.userId); + } + + @Test + public void testGetOverlaysForUser() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_B0); + insert(OVERLAY_A1); + insert(OVERLAY_B1); + + Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(OVERLAY_A0.userId); + assertEquals(1, map.keySet().size()); + assertTrue(map.keySet().contains(OVERLAY_A0.targetPackageName)); + + List<OverlayInfo> list = map.get(OVERLAY_A0.targetPackageName); + assertEquals(2, list.size()); + assertTrue(list.contains(OVERLAY_A0)); + assertTrue(list.contains(OVERLAY_B0)); + + // getOverlaysForUser should never return null + map = mSettings.getOverlaysForUser(-1); + assertNotNull(map); + assertEquals(0, map.size()); + } + + @Test + public void testRemoveUser() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_B0); + insert(OVERLAY_A1); + + assertContains(mSettings, OVERLAY_A0); + assertContains(mSettings, OVERLAY_B0); + assertContains(mSettings, OVERLAY_A1); + + mSettings.removeUser(OVERLAY_A0.userId); + + assertDoesNotContain(mSettings, OVERLAY_A0); + assertDoesNotContain(mSettings, OVERLAY_B0); + assertContains(mSettings, OVERLAY_A1); + } + + @Test + public void testOrderOfNewlyAddedItems() throws Exception { + // new items are appended to the list + insert(OVERLAY_A0); + insert(OVERLAY_B0); + insert(OVERLAY_C0); + + List<OverlayInfo> list = + mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0); + + // overlays keep their positions when updated + mSettings.setState(OVERLAY_B0.packageName, OVERLAY_B0.userId, STATE_ENABLED); + OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_B0.packageName, OVERLAY_B0.userId); + + list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, oi, OVERLAY_C0); + } + + @Test + public void testSetPriority() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_B0); + insert(OVERLAY_C0); + + List<OverlayInfo> list = + mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0); + + boolean changed = mSettings.setPriority(OVERLAY_B0.packageName, OVERLAY_C0.packageName, + OVERLAY_B0.userId); + assertTrue(changed); + list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0); + + changed = + mSettings.setPriority(OVERLAY_B0.packageName, "does.not.exist", OVERLAY_B0.userId); + assertFalse(changed); + list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0); + + OverlayInfo otherTarget = new OverlayInfo( + "com.dummy.overlay_other", + "com.dummy.some.other.target", + null, + "some-category", + "/data/app/com.dummy.overlay_other-1/base.apk", + STATE_DISABLED, + 0, + 0, + false); + insert(otherTarget); + changed = mSettings.setPriority(OVERLAY_A0.packageName, otherTarget.packageName, + OVERLAY_A0.userId); + assertFalse(changed); + } + + @Test + public void testSetLowestPriority() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_B0); + insert(OVERLAY_C0); + + List<OverlayInfo> list = + mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0); + + boolean changed = mSettings.setLowestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId); + assertTrue(changed); + + list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_B0, OVERLAY_A0, OVERLAY_C0); + } + + @Test + public void testSetHighestPriority() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_B0); + insert(OVERLAY_C0); + + List<OverlayInfo> list = + mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0); + + boolean changed = mSettings.setHighestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId); + assertTrue(changed); + + list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId); + assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0); + } + + // tests: persist and restore + + @Test + public void testPersistEmpty() throws Exception { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + mSettings.persist(os); + String xml = new String(os.toByteArray(), "utf-8"); + + assertEquals(1, countXmlTags(xml, "overlays")); + assertEquals(0, countXmlTags(xml, "item")); + } + + @Test + public void testPersistDifferentOverlaysSameUser() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_B0); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + mSettings.persist(os); + final String xml = new String(os.toByteArray(), "utf-8"); + + assertEquals(1, countXmlTags(xml, "overlays")); + assertEquals(2, countXmlTags(xml, "item")); + assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName", + OVERLAY_A0.packageName)); + assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName", + OVERLAY_B0.packageName)); + assertEquals(2, countXmlAttributesWhere(xml, "item", "userId", + Integer.toString(OVERLAY_A0.userId))); + } + + @Test + public void testPersistSameOverlayDifferentUsers() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_A1); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + mSettings.persist(os); + String xml = new String(os.toByteArray(), "utf-8"); + + assertEquals(1, countXmlTags(xml, "overlays")); + assertEquals(2, countXmlTags(xml, "item")); + assertEquals(2, countXmlAttributesWhere(xml, "item", "packageName", + OVERLAY_A0.packageName)); + assertEquals(1, countXmlAttributesWhere(xml, "item", "userId", + Integer.toString(OVERLAY_A0.userId))); + assertEquals(1, countXmlAttributesWhere(xml, "item", "userId", + Integer.toString(OVERLAY_A1.userId))); + } + + @Test + public void testPersistEnabled() throws Exception { + insert(OVERLAY_A0); + mSettings.setEnabled(OVERLAY_A0.packageName, OVERLAY_A0.userId, true); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + mSettings.persist(os); + String xml = new String(os.toByteArray(), "utf-8"); + + assertEquals(1, countXmlAttributesWhere(xml, "item", "isEnabled", "true")); + } + + @Test + public void testRestoreEmpty() throws Exception { + final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION; + final String xml = + "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + + "<overlays version=\"" + version + "\" />\n"; + ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8")); + + mSettings.restore(is); + assertDoesNotContain(mSettings, "com.dummy.overlay", 0); + } + + @Test + public void testRestoreSingleUserSingleOverlay() throws Exception { + final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION; + final String xml = + "<?xml version='1.0' encoding='utf-8' standalone='yes'?>\n" + + "<overlays version='" + version + "'>\n" + + "<item packageName='com.dummy.overlay'\n" + + " userId='1234'\n" + + " targetPackageName='com.dummy.target'\n" + + " baseCodePath='/data/app/com.dummy.overlay-1/base.apk'\n" + + " state='" + STATE_DISABLED + "'\n" + + " isEnabled='false'\n" + + " category='dummy-category'\n" + + " isStatic='false'\n" + + " priority='0' />\n" + + "</overlays>\n"; + ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8")); + + mSettings.restore(is); + OverlayInfo oi = mSettings.getOverlayInfo("com.dummy.overlay", 1234); + assertNotNull(oi); + assertEquals("com.dummy.overlay", oi.packageName); + assertEquals("com.dummy.target", oi.targetPackageName); + assertEquals("/data/app/com.dummy.overlay-1/base.apk", oi.baseCodePath); + assertEquals(1234, oi.userId); + assertEquals(STATE_DISABLED, oi.state); + assertFalse(mSettings.getEnabled("com.dummy.overlay", 1234)); + } + + @Test + public void testPersistAndRestore() throws Exception { + insert(OVERLAY_A0); + insert(OVERLAY_B1); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + mSettings.persist(os); + String xml = new String(os.toByteArray(), "utf-8"); + ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8")); + OverlayManagerSettings newSettings = new OverlayManagerSettings(); + newSettings.restore(is); + + OverlayInfo a = newSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId); + assertEquals(OVERLAY_A0, a); + + OverlayInfo b = newSettings.getOverlayInfo(OVERLAY_B1.packageName, OVERLAY_B1.userId); + assertEquals(OVERLAY_B1, b); + } + + private int countXmlTags(String xml, String tagToLookFor) throws Exception { + int count = 0; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new StringReader(xml)); + int event = parser.getEventType(); + while (event != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG && tagToLookFor.equals(parser.getName())) { + count++; + } + event = parser.next(); + } + return count; + } + + private int countXmlAttributesWhere(String xml, String tag, String attr, String value) + throws Exception { + int count = 0; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new StringReader(xml)); + int event = parser.getEventType(); + while (event != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG && tag.equals(parser.getName())) { + String v = parser.getAttributeValue(null, attr); + if (value.equals(v)) { + count++; + } + } + event = parser.next(); + } + return count; + } + + private void insert(OverlayInfo oi) throws Exception { + mSettings.init(oi.packageName, oi.userId, oi.targetPackageName, null, oi.baseCodePath, + false, 0, oi.category); + mSettings.setState(oi.packageName, oi.userId, oi.state); + mSettings.setEnabled(oi.packageName, oi.userId, false); + } + + private static void assertContains(final OverlayManagerSettings settings, + final OverlayInfo oi) { + assertContains(settings, oi.packageName, oi.userId); + } + + private static void assertContains(final OverlayManagerSettings settings, + final String packageName, int userId) { + try { + settings.getOverlayInfo(packageName, userId); + } catch (OverlayManagerSettings.BadKeyException e) { + fail(String.format("settings does not contain packageName=%s userId=%d", + packageName, userId)); + } + } + + private static void assertDoesNotContain(final OverlayManagerSettings settings, + final OverlayInfo oi) { + assertDoesNotContain(settings, oi.packageName, oi.userId); + } + + private static void assertDoesNotContain(final OverlayManagerSettings settings, + final String packageName, int userId) { + try { + settings.getOverlayInfo(packageName, userId); + fail(String.format("settings contains packageName=%s userId=%d", packageName, userId)); + } catch (OverlayManagerSettings.BadKeyException e) { + // do nothing: we expect to end up here + } + } + + private static void assertContains(int[] haystack, int needle) { + List<Integer> list = IntStream.of(haystack) + .boxed() + .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); + if (!list.contains(needle)) { + fail(String.format("integer array [%s] does not contain value %s", + TextUtils.join(",", list), needle)); + } + } + + private static void assertDoesNotContain(int[] haystack, int needle) { + List<Integer> list = IntStream.of(haystack) + .boxed() + .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); + if (list.contains(needle)) { + fail(String.format("integer array [%s] contains value %s", + TextUtils.join(",", list), needle)); + } + } + + private static void assertListsAreEqual(List<OverlayInfo> list, OverlayInfo... array) { + List<OverlayInfo> other = Stream.of(array) + .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); + assertListsAreEqual(list, other); + } + + private static void assertListsAreEqual(List<OverlayInfo> list, List<OverlayInfo> other) { + if (!list.equals(other)) { + fail(String.format("lists [%s] and [%s] differ", + TextUtils.join(",", list), TextUtils.join(",", other))); + } + } +} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index ca7a71ecad75..b0788253d0a7 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -71,8 +71,10 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; import android.app.ActivityManager; import android.app.AppOpsManager; +import android.app.AutomaticZenRule; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; @@ -117,6 +119,7 @@ import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; import android.service.notification.NotifyingApp; import android.service.notification.StatusBarNotification; +import android.service.notification.ZenPolicy; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; @@ -2887,7 +2890,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testApplyEnqueuedAdjustmentFromAssistant_importance_onTime() throws Exception { + public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addEnqueuedNotification(r); NotificationManagerService.WorkerHandler handler = mock( @@ -2905,25 +2908,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testApplyEnqueuedAdjustmentFromAssistant_importance_tooLate() throws Exception { - final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); - mService.addNotification(r); - NotificationManagerService.WorkerHandler handler = mock( - NotificationManagerService.WorkerHandler.class); - mService.setHandler(handler); - when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); - - Bundle signals = new Bundle(); - signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); - Adjustment adjustment = new Adjustment( - r.sbn.getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); - mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); - - assertEquals(IMPORTANCE_DEFAULT, r.getImportance()); - assertFalse(r.hasAdjustment(KEY_IMPORTANCE)); - } - - @Test public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addEnqueuedNotification(r); @@ -4967,6 +4951,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment()); } + public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception { + ComponentName owner = mock(ComponentName.class); + ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); + boolean isEnabled = true; + AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), + zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); + + try { + mBinderService.addAutomaticZenRule(rule); + fail("Zen policy only aplies to priority only mode"); + } catch (IllegalArgumentException e) { + // yay + } + + rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), + zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); + mBinderService.addAutomaticZenRule(rule); + + rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), + null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); + mBinderService.addAutomaticZenRule(rule); + } + public void testAreNotificationsEnabledForPackage_crossUser() throws Exception { try { mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 6ed78b36190f..b34bd2595287 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -940,12 +940,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testClearLockedFields() { final NotificationChannel channel = getChannel(); - mHelper.clearLockedFields(channel); + mHelper.clearLockedFieldsLocked(channel); assertEquals(0, channel.getUserLockedFields()); channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY | NotificationChannel.USER_LOCKED_IMPORTANCE); - mHelper.clearLockedFields(channel); + mHelper.clearLockedFieldsLocked(channel); assertEquals(0, channel.getUserLockedFields()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java index 9ce579512eda..beec1a8b8942 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.server.wm.BoundsAnimationController.BOUNDS; +import static com.android.server.wm.BoundsAnimationController.FADE_IN; import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS; import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START; @@ -131,6 +133,8 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { boolean mCancelRequested; Rect mStackBounds; Rect mTaskBounds; + float mAlpha; + @BoundsAnimationController.AnimationType int mAnimationType; void initialize(Rect from) { mAwaitingAnimationStart = true; @@ -148,11 +152,12 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @Override public boolean onAnimationStart(boolean schedulePipModeChangedCallback, - boolean forceUpdate) { + boolean forceUpdate, @BoundsAnimationController.AnimationType int animationType) { mAwaitingAnimationStart = false; mAnimationStarted = true; mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback; mForcePipModeChangedCallback = forceUpdate; + mAnimationType = animationType; return true; } @@ -185,6 +190,12 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { mMovedToFullscreen = moveToFullscreen; mTaskBounds = null; } + + @Override + public boolean setPinnedStackAlpha(float alpha) { + mAlpha = alpha; + return true; + } } /** @@ -201,6 +212,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { private Rect mTo; private Rect mLargerBounds; private Rect mExpectedFinalBounds; + private @BoundsAnimationController.AnimationType int mAnimationType; BoundsAnimationDriver(BoundsAnimationController controller, TestBoundsAnimationTarget target, MockValueAnimator mockValueAnimator) { @@ -209,7 +221,8 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { mMockAnimator = mockValueAnimator; } - BoundsAnimationDriver start(Rect from, Rect to) { + BoundsAnimationDriver start(Rect from, Rect to, + @BoundsAnimationController.AnimationType int animationType) { if (mAnimator != null) { throw new IllegalArgumentException("Call restart() to restart an animation"); } @@ -223,7 +236,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { assertTrue(mTarget.mAwaitingAnimationStart); assertFalse(mTarget.mAnimationStarted); - startImpl(from, to); + startImpl(from, to, animationType); // Ensure that the animator is paused for the all windows drawn signal when animating // to/from fullscreen @@ -253,7 +266,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { mTarget.mAnimationStarted = false; // Start animation - startImpl(mTarget.mStackBounds, to); + startImpl(mTarget.mStackBounds, to, BOUNDS); if (toSameBounds) { // Same animator if same final bounds @@ -273,13 +286,15 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { return this; } - private BoundsAnimationDriver startImpl(Rect from, Rect to) { + private BoundsAnimationDriver startImpl(Rect from, Rect to, + @BoundsAnimationController.AnimationType int animationType) { boolean fromFullscreen = from.equals(BOUNDS_FULL); boolean toFullscreen = to.equals(BOUNDS_FULL); mFrom = new Rect(from); mTo = new Rect(to); mExpectedFinalBounds = new Rect(to); mLargerBounds = getLargerBounds(mFrom, mTo); + mAnimationType = animationType; // Start animation final @SchedulePipModeChangedState int schedulePipModeChangedState = toFullscreen @@ -288,17 +303,19 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { ? SCHEDULE_PIP_MODE_CHANGED_ON_END : NO_PIP_MODE_CHANGED_CALLBACKS; mAnimator = mController.animateBoundsImpl(mTarget, from, to, DURATION, - schedulePipModeChangedState, fromFullscreen, toFullscreen); - - // Original stack bounds, frozen task bounds - assertEquals(mFrom, mTarget.mStackBounds); - assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); + schedulePipModeChangedState, fromFullscreen, toFullscreen, animationType); - // Animating to larger size - if (mFrom.equals(mLargerBounds)) { - assertFalse(mAnimator.animatingToLargerSize()); - } else if (mTo.equals(mLargerBounds)) { - assertTrue(mAnimator.animatingToLargerSize()); + if (animationType == BOUNDS) { + // Original stack bounds, frozen task bounds + assertEquals(mFrom, mTarget.mStackBounds); + assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); + + // Animating to larger size + if (mFrom.equals(mLargerBounds)) { + assertFalse(mAnimator.animatingToLargerSize()); + } else if (mTo.equals(mLargerBounds)) { + assertTrue(mAnimator.animatingToLargerSize()); + } } return this; @@ -315,16 +332,20 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { BoundsAnimationDriver update(float t) { mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(t)); - // Temporary stack bounds, frozen task bounds - if (t == 0f) { - assertEquals(mFrom, mTarget.mStackBounds); - } else if (t == 1f) { - assertEquals(mTo, mTarget.mStackBounds); + if (mAnimationType == BOUNDS) { + // Temporary stack bounds, frozen task bounds + if (t == 0f) { + assertEquals(mFrom, mTarget.mStackBounds); + } else if (t == 1f) { + assertEquals(mTo, mTarget.mStackBounds); + } else { + assertNotEquals(mFrom, mTarget.mStackBounds); + assertNotEquals(mTo, mTarget.mStackBounds); + } + assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); } else { - assertNotEquals(mFrom, mTarget.mStackBounds); - assertNotEquals(mTo, mTarget.mStackBounds); + assertEquals((float) mMockAnimator.getAnimatedValue(), mTarget.mAlpha, 0.01f); } - assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); return this; } @@ -353,10 +374,14 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { BoundsAnimationDriver end() { mAnimator.end(); - // Final stack bounds - assertEquals(mTo, mTarget.mStackBounds); - assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds); - assertNull(mTarget.mTaskBounds); + if (mAnimationType == BOUNDS) { + // Final stack bounds + assertEquals(mTo, mTarget.mStackBounds); + assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds); + assertNull(mTarget.mTaskBounds); + } else { + assertEquals(mTarget.mAlpha, 1f, 0.01f); + } return this; } @@ -413,7 +438,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFullscreenToFloatingTransition() { - mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0f) .update(0.5f) @@ -425,7 +450,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToFullscreenTransition() { - mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0f) .update(0.5f) @@ -437,7 +462,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToSmallerFloatingTransition() { - mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) + mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0f) .update(0.5f) @@ -449,7 +474,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToLargerFloatingTransition() { - mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) + mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0f) .update(0.5f) @@ -463,7 +488,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFullscreenToFloatingCancelFromTarget() { - mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .cancel() @@ -473,7 +498,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFullscreenToFloatingCancelFromAnimationToSameBounds() { - mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .restart(BOUNDS_FLOATING, false /* expectStartedAndPipModeChangedCallback */) @@ -484,7 +509,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() { - mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .restart(BOUNDS_SMALLER_FLOATING, @@ -498,7 +523,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() { // When animating from fullscreen and the animation is interruped, we expect the animation // start callback to be made, with a forced pip mode change callback - mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .restart(BOUNDS_FULL, true /* expectStartedAndPipModeChangedCallback */) @@ -511,7 +536,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToFullscreenCancelFromTarget() { - mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .cancel() @@ -521,7 +546,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToFullscreenCancelFromAnimationToSameBounds() { - mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .restart(BOUNDS_FULL, false /* expectStartedAndPipModeChangedCallback */) @@ -532,7 +557,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() { - mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .restart(BOUNDS_SMALLER_FLOATING, @@ -546,7 +571,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToSmallerFloatingCancelFromTarget() { - mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) + mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .cancel() @@ -556,13 +581,25 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test public void testFloatingToLargerFloatingCancelFromTarget() { - mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) + mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) .cancel() .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); } + @UiThreadTest + @Test + public void testFadeIn() { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, FADE_IN) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + /** MISC **/ @UiThreadTest @@ -570,7 +607,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { public void testBoundsAreCopied() { Rect from = new Rect(0, 0, 100, 100); Rect to = new Rect(25, 25, 75, 75); - mDriver.start(from, to) + mDriver.start(from, to, BOUNDS) .update(0.25f) .end(); assertEquals(new Rect(0, 0, 100, 100), from); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index e392353a8875..0c2ce614b772 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -163,7 +163,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot // animation. mController.mRecentScreenshotAnimator.cancelAnimation(); - verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true); + verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false); } private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 5625ea42726f..f615823a645c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -71,6 +71,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { @Test public void testCancelAnimationOnVisibleStackOrderChange() { ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); + display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class); ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mService) diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index ad1e3ef43ea4..4d7ae7309e27 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -1238,6 +1238,9 @@ public class VoiceInteractionManagerService extends SystemService { RoleObserver(@NonNull @CallbackExecutor Executor executor) { mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL); + UserHandle currentUser = UserHandle.of(LocalServices.getService( + ActivityManagerInternal.class).getCurrentUserId()); + onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser); } private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) { @@ -1285,7 +1288,9 @@ public class VoiceInteractionManagerService extends SystemService { // Try to set role holder as VoiceInteractionService List<ResolveInfo> services = mPm.queryIntentServicesAsUser( new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg), - PackageManager.GET_META_DATA, userId); + PackageManager.GET_META_DATA + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); for (ResolveInfo resolveInfo : services) { ServiceInfo serviceInfo = resolveInfo.serviceInfo; @@ -1318,7 +1323,9 @@ public class VoiceInteractionManagerService extends SystemService { // If no service could be found try to set assist activity final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser( new Intent(Intent.ACTION_ASSIST).setPackage(pkg), - PackageManager.MATCH_DEFAULT_ONLY, userId); + PackageManager.MATCH_DEFAULT_ONLY + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); for (ResolveInfo resolveInfo : activities) { ActivityInfo activityInfo = resolveInfo.activityInfo; @@ -1331,6 +1338,7 @@ public class VoiceInteractionManagerService extends SystemService { Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user), userId); + return; } } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 8d2cbca08586..ea523774bf84 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -25,9 +25,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; - -import com.android.internal.app.IVoiceActionCheckCallback; -import com.android.server.wm.ActivityTaskManagerInternal; import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.content.BroadcastReceiver; @@ -51,15 +48,16 @@ import android.util.PrintWriterPrinter; import android.util.Slog; import android.view.IWindowManager; +import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceInteractionSessionShowCallback; import com.android.internal.app.IVoiceInteractor; import com.android.server.LocalServices; +import com.android.server.wm.ActivityTaskManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import java.util.Set; class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback { final static String TAG = "VoiceInteractionServiceManager"; @@ -358,6 +356,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne intent.setComponent(mComponent); mBound = mContext.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE + | Context.BIND_INCLUDE_CAPABILITIES | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser)); if (!mBound) { Slog.w(TAG, "Failed binding to voice interaction service " + mComponent); diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java index 37fab09cd745..36c637723c0a 100644 --- a/telecomm/java/android/telecom/CallRedirectionService.java +++ b/telecomm/java/android/telecom/CallRedirectionService.java @@ -119,18 +119,18 @@ public abstract class CallRedirectionService extends Service { * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. * - * @param handle the new phone number to dial + * @param gatewayUri the gateway uri for call redirection. * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call. * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog * if the confirmFirst is true, and if the redirection request of this * response was sent with a true flag of allowInteractiveResponse via * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} */ - public final void redirectCall(@NonNull Uri handle, + public final void redirectCall(@NonNull Uri gatewayUri, @NonNull PhoneAccountHandle targetPhoneAccount, boolean confirmFirst) { try { - mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst); + mCallRedirectionAdapter.redirectCall(gatewayUri, targetPhoneAccount, confirmFirst); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 52e0ebd334b5..2d8a8cbae59f 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -4321,6 +4321,22 @@ public final class Telephony { * @hide */ public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation"; + + /** + * The current registered raw data network operator name in long alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}. + * @hide + */ + public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw"; + + /** + * The current registered raw data network operator name in short alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}. + * @hide + */ + public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw"; } /** diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0f8f873b6847..9f6528bc4709 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1312,6 +1312,24 @@ public class CarrierConfigManager { "hide_lte_plus_data_icon_bool"; /** + * The string is used to filter redundant string from PLMN Network Name that's supplied by + * specific carrier. + * + * @hide + */ + public static final String KEY_OPERATOR_NAME_FILTER_PATTERN_STRING = + "operator_name_filter_pattern_string"; + + /** + * The string is used to compare with operator name. If it matches the pattern then show + * specific data icon. + * + * @hide + */ + public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = + "show_carrier_data_icon_pattern_string"; + + /** * Boolean to decide whether to show precise call failed cause to user * @hide */ @@ -2803,6 +2821,19 @@ public class CarrierConfigManager { public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "key_is_opportunistic_subscription_bool"; + /** + * A list of 4 GSM RSSI thresholds above which a signal level is considered POOR, + * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting. + * + * Note that the min and max thresholds are fixed at -113 and -51, as set in 3GPP TS 27.007 + * section 8.5. + * <p> + * See CellSignalStrengthGsm#GSM_RSSI_MAX and CellSignalStrengthGsm#GSM_RSSI_MIN. Any signal + * level outside these boundaries is considered invalid. + * @hide + */ + public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY = + "gsm_rssi_thresholds_int_array"; /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -3139,6 +3170,8 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false); sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false); + sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, ""); + sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ""); sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false); @@ -3204,6 +3237,13 @@ public class CarrierConfigManager { false); sDefaults.putString(KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); sDefaults.putBoolean(KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false); + sDefaults.putIntArray(KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY, + new int[] { + -107, /* SIGNAL_STRENGTH_POOR */ + -103, /* SIGNAL_STRENGTH_MODERATE */ + -97, /* SIGNAL_STRENGTH_GOOD */ + -89, /* SIGNAL_STRENGTH_GREAT */ + }); } /** diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 374527749354..30875165867a 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -49,10 +49,10 @@ public abstract class CellIdentity implements Parcelable { // long alpha Operator Name String or Enhanced Operator Name String /** @hide */ - protected final String mAlphaLong; + protected String mAlphaLong; // short alpha Operator Name String or Enhanced Operator Name String /** @hide */ - protected final String mAlphaShort; + protected String mAlphaShort; /** @hide */ protected CellIdentity(String tag, int type, String mcc, String mnc, String alphal, @@ -145,6 +145,13 @@ public abstract class CellIdentity implements Parcelable { } /** + * @hide + */ + public void setOperatorAlphaLong(String alphaLong) { + mAlphaLong = alphaLong; + } + + /** * @return The short alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ @@ -154,6 +161,13 @@ public abstract class CellIdentity implements Parcelable { } /** + * @hide + */ + public void setOperatorAlphaShort(String alphaShort) { + mAlphaShort = alphaShort; + } + + /** * @return a CellLocation object for this CellIdentity * @hide */ diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index 5e44bf2e37a8..864540d91be3 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -166,6 +166,7 @@ public final class CellIdentityGsm extends CellIdentity { /** * @return Mobile Country Code in string format, null if unavailable. */ + @Nullable public String getMccString() { return mMccStr; } @@ -173,6 +174,7 @@ public final class CellIdentityGsm extends CellIdentity { /** * @return Mobile Network Code in string format, null if unavailable. */ + @Nullable public String getMncString() { return mMncStr; } diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 2dd72d6ea69c..14503c7cdd4d 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -187,6 +187,7 @@ public final class CellIdentityLte extends CellIdentity { /** * @return Mobile Country Code in string format, null if unavailable. */ + @Nullable public String getMccString() { return mMccStr; } @@ -194,6 +195,7 @@ public final class CellIdentityLte extends CellIdentity { /** * @return Mobile Network Code in string format, null if unavailable. */ + @Nullable public String getMncString() { return mMncStr; } diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index a591bd15f95f..937de706aec0 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -104,6 +104,7 @@ public final class CellIdentityTdscdma extends CellIdentity { * Get Mobile Country Code in string format * @return Mobile Country Code in string format, null if unknown */ + @Nullable public String getMccString() { return mMccStr; } @@ -112,6 +113,7 @@ public final class CellIdentityTdscdma extends CellIdentity { * Get Mobile Network Code in string format * @return Mobile Network Code in string format, null if unknown */ + @Nullable public String getMncString() { return mMncStr; } diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index 674c40c2d36f..b4a2ead7fc3d 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -150,6 +150,7 @@ public final class CellIdentityWcdma extends CellIdentity { /** * @return Mobile Country Code in string version, null if unavailable. */ + @Nullable public String getMccString() { return mMccStr; } @@ -157,6 +158,7 @@ public final class CellIdentityWcdma extends CellIdentity { /** * @return Mobile Network Code in string version, null if unavailable. */ + @Nullable public String getMncString() { return mMncStr; } diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java index a4570e41dc26..30b131faf51d 100644 --- a/telephony/java/android/telephony/CellInfoCdma.java +++ b/telephony/java/android/telephony/CellInfoCdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -76,18 +77,25 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo); } + /** + * @return a {@link CellIdentityCdma} instance. + */ @Override - public CellIdentityCdma getCellIdentity() { + public @NonNull CellIdentityCdma getCellIdentity() { return mCellIdentityCdma; } + /** @hide */ @UnsupportedAppUsage public void setCellIdentity(CellIdentityCdma cid) { mCellIdentityCdma = cid; } + /** + * @return a {@link CellSignalStrengthCdma} instance. + */ @Override - public CellSignalStrengthCdma getCellSignalStrength() { + public @NonNull CellSignalStrengthCdma getCellSignalStrength() { return mCellSignalStrengthCdma; } diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java index ce32bc1b9cb7..137f97eeee62 100644 --- a/telephony/java/android/telephony/CellInfoGsm.java +++ b/telephony/java/android/telephony/CellInfoGsm.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -71,17 +72,24 @@ public final class CellInfoGsm extends CellInfo implements Parcelable { mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm); } + /** + * @return a {@link CellIdentityGsm} instance. + */ @Override - public CellIdentityGsm getCellIdentity() { + public @NonNull CellIdentityGsm getCellIdentity() { return mCellIdentityGsm; } + /** @hide */ public void setCellIdentity(CellIdentityGsm cid) { mCellIdentityGsm = cid; } + /** + * @return a {@link CellSignalStrengthGsm} instance. + */ @Override - public CellSignalStrengthGsm getCellSignalStrength() { + public @NonNull CellSignalStrengthGsm getCellSignalStrength() { return mCellSignalStrengthGsm; } diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java index 01ee20a7fa1e..da7b7ab1488d 100644 --- a/telephony/java/android/telephony/CellInfoLte.java +++ b/telephony/java/android/telephony/CellInfoLte.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -79,11 +80,15 @@ public final class CellInfoLte extends CellInfo implements Parcelable { mCellConfig = new CellConfigLte(cil.cellConfig); } + /** + * @return a {@link CellIdentityLte} instance. + */ @Override - public CellIdentityLte getCellIdentity() { + public @NonNull CellIdentityLte getCellIdentity() { if (DBG) log("getCellIdentity: " + mCellIdentityLte); return mCellIdentityLte; } + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void setCellIdentity(CellIdentityLte cid) { @@ -91,8 +96,11 @@ public final class CellInfoLte extends CellInfo implements Parcelable { mCellIdentityLte = cid; } + /** + * @return a {@link CellSignalStrengthLte} instance. + */ @Override - public CellSignalStrengthLte getCellSignalStrength() { + public @NonNull CellSignalStrengthLte getCellSignalStrength() { if (DBG) log("getCellSignalStrength: " + mCellSignalStrengthLte); return mCellSignalStrengthLte; } diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java index ba4a907fdce8..9775abd5075c 100644 --- a/telephony/java/android/telephony/CellInfoNr.java +++ b/telephony/java/android/telephony/CellInfoNr.java @@ -43,12 +43,18 @@ public final class CellInfoNr extends CellInfo { mCellSignalStrength = other.mCellSignalStrength; } + /** + * @return a {@link CellIdentityNr} instance. + */ @Override @NonNull public CellIdentity getCellIdentity() { return mCellIdentity; } + /** + * @return a {@link CellSignalStrengthNr} instance. + */ @Override @NonNull public CellSignalStrength getCellSignalStrength() { diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java index ccafda61a177..f1305f5ca768 100644 --- a/telephony/java/android/telephony/CellInfoTdscdma.java +++ b/telephony/java/android/telephony/CellInfoTdscdma.java @@ -75,6 +75,9 @@ public final class CellInfoTdscdma extends CellInfo implements Parcelable { mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma); } + /** + * @return a {@link CellIdentityTdscdma} instance. + */ @Override public @NonNull CellIdentityTdscdma getCellIdentity() { return mCellIdentityTdscdma; @@ -85,6 +88,9 @@ public final class CellInfoTdscdma extends CellInfo implements Parcelable { mCellIdentityTdscdma = cid; } + /** + * @return a {@link CellSignalStrengthTdscdma} instance. + */ @Override public @NonNull CellSignalStrengthTdscdma getCellSignalStrength() { return mCellSignalStrengthTdscdma; diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java index 1b32178db337..ee5fec838d2d 100644 --- a/telephony/java/android/telephony/CellInfoWcdma.java +++ b/telephony/java/android/telephony/CellInfoWcdma.java @@ -71,15 +71,22 @@ public final class CellInfoWcdma extends CellInfo implements Parcelable { mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma); } + /** + * @return a {@link CellIdentityWcdma} instance. + */ @Override public CellIdentityWcdma getCellIdentity() { return mCellIdentityWcdma; } + /** @hide */ public void setCellIdentity(CellIdentityWcdma cid) { mCellIdentityWcdma = cid; } + /** + * @return a {@link CellSignalStrengthWcdma} instance. + */ @Override public CellSignalStrengthWcdma getCellSignalStrength() { return mCellSignalStrengthWcdma; diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java index 740b970b8e7c..e65b048ec0a5 100644 --- a/telephony/java/android/telephony/CellSignalStrength.java +++ b/telephony/java/android/telephony/CellSignalStrength.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntRange; import android.os.PersistableBundle; /** @@ -57,23 +58,24 @@ public abstract class CellSignalStrength { public abstract void setDefaultValues(); /** - * Get signal level as an int from 0..4 - * <p> - * @see #SIGNAL_STRENGTH_NONE_OR_UNKNOWN - * @see #SIGNAL_STRENGTH_POOR - * @see #SIGNAL_STRENGTH_MODERATE - * @see #SIGNAL_STRENGTH_GOOD - * @see #SIGNAL_STRENGTH_GREAT + * Retrieve an abstract level value for the overall signal quality. + * + * @return a single integer from 0 to 4 representing the general signal quality. + * 0 represents very poor or unknown signal quality while 4 represents excellent + * signal quality. */ + @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) public abstract int getLevel(); /** - * Get the signal level as an asu value between 0..31, 99 is unknown + * Get the technology-specific signal strength in Arbitrary Strength Units, calculated from the + * strength of the pilot signal or equivalent. */ public abstract int getAsuLevel(); /** - * Get the signal strength as dBm + * Get the technology-specific signal strength in dBm, which is the signal strength of the + * pilot signal or equivalent. */ public abstract int getDbm(); diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java index 5b195999078c..199843905854 100644 --- a/telephony/java/android/telephony/CellSignalStrengthCdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntRange; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -114,13 +115,9 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } - /** - * Retrieve an abstract level value for the overall signal strength. - * - * @return a single integer from 0 to 4 representing the general signal quality. - * 0 represents very poor signal strength while 4 represents a very strong signal strength. - */ + /** {@inheritDoc} */ @Override + @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) public int getLevel() { return mLevel; } diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java index 0aeb0f6e66d8..14ae68981745 100644 --- a/telephony/java/android/telephony/CellSignalStrengthGsm.java +++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntRange; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -37,6 +38,10 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P private static final int GSM_RSSI_GOOD = -97; private static final int GSM_RSSI_MODERATE = -103; private static final int GSM_RSSI_POOR = -107; + private static final int GSM_RSSI_MIN = -113; + + private static final int[] sRssiThresholds = new int[] { + GSM_RSSI_POOR, GSM_RSSI_MODERATE, GSM_RSSI_GOOD, GSM_RSSI_GREAT}; private int mRssi; // in dBm [-113, -51] or UNAVAILABLE @UnsupportedAppUsage @@ -53,7 +58,7 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P /** @hide */ public CellSignalStrengthGsm(int rssi, int ber, int ta) { - mRssi = inRangeOrUnavailable(rssi, -113, -51); + mRssi = inRangeOrUnavailable(rssi, GSM_RSSI_MIN, GSM_RSSI_MAX); mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99); mTimingAdvance = inRangeOrUnavailable(ta, 0, 219); updateLevel(null, null); @@ -97,13 +102,9 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } - /** - * Retrieve an abstract level value for the overall signal strength. - * - * @return a single integer from 0 to 4 representing the general signal quality. - * 0 represents very poor signal strength while 4 represents a very strong signal strength. - */ + /** {@inheritDoc} */ @Override + @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) public int getLevel() { return mLevel; } @@ -111,12 +112,22 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P /** @hide */ @Override public void updateLevel(PersistableBundle cc, ServiceState ss) { - if (mRssi > GSM_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - else if (mRssi >= GSM_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT; - else if (mRssi >= GSM_RSSI_GOOD) mLevel = SIGNAL_STRENGTH_GOOD; - else if (mRssi >= GSM_RSSI_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE; - else if (mRssi >= GSM_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR; - else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + int[] rssiThresholds; + if (cc == null) { + rssiThresholds = sRssiThresholds; + } else { + rssiThresholds = cc.getIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY); + if (rssiThresholds == null || rssiThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) { + rssiThresholds = sRssiThresholds; + } + } + int level = NUM_SIGNAL_STRENGTH_THRESHOLDS; + if (mRssi < GSM_RSSI_MIN || mRssi > GSM_RSSI_MAX) { + mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + return; + } + while (level > 0 && mRssi < rssiThresholds[level - 1]) level--; + mLevel = level; } /** @@ -141,7 +152,7 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P /** * Get the RSSI in ASU. * - * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69 + * Asu is calculated based on 3GPP RSSI. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69 * * @return RSSI in ASU 0..31, 99, or UNAVAILABLE */ diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 5687adaabed5..2272dc9071ea 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntRange; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -145,13 +146,9 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } - /** - * Retrieve an abstract level value for the overall signal strength. - * - * @return a single integer from 0 to 4 representing the general signal quality. - * 0 represents very poor signal strength while 4 represents a very strong signal strength. - */ + /** {@inheritDoc} */ @Override + @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) public int getLevel() { return mLevel; } diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index fff3adf04f7b..1912c60ac122 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntRange; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -183,7 +184,9 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } + /** {@inheritDoc} */ @Override + @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) public int getLevel() { return mLevel; } @@ -227,6 +230,9 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa return asuLevel; } + /** + * Get the CSI-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. + */ @Override public int getDbm() { return mCsiRsrp; diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java index ddbd851bbce5..f4a3dbb37988 100644 --- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntRange; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; @@ -34,14 +35,14 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen private static final String LOG_TAG = "CellSignalStrengthTdscdma"; private static final boolean DBG = false; - private static final int TDSCDMA_RSSI_MAX = -51; - private static final int TDSCDMA_RSSI_GREAT = -77; - private static final int TDSCDMA_RSSI_GOOD = -87; - private static final int TDSCDMA_RSSI_MODERATE = -97; - private static final int TDSCDMA_RSSI_POOR = -107; - - private static final int TDSCDMA_RSCP_MIN = -120; + // These levels are arbitrary but carried over from SignalStrength.java for consistency. private static final int TDSCDMA_RSCP_MAX = -24; + private static final int TDSCDMA_RSCP_GREAT = -49; + private static final int TDSCDMA_RSCP_GOOD = -73; + private static final int TDSCDMA_RSCP_MODERATE = -97; + private static final int TDSCDMA_RSCP_POOR = -110; + private static final int TDSCDMA_RSCP_MIN = -120; + private int mRssi; // in dBm [-113, -51], CellInfo.UNAVAILABLE @@ -121,13 +122,10 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } - /** - * Retrieve an abstract level value for the overall signal strength. - * - * @return a single integer from 0 to 4 representing the general signal quality. - * 0 represents very poor signal strength while 4 represents a very strong signal strength. - */ + + /** {@inheritDoc} */ @Override + @IntRange(from = 0, to = 4) public int getLevel() { return mLevel; } @@ -135,16 +133,16 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen /** @hide */ @Override public void updateLevel(PersistableBundle cc, ServiceState ss) { - if (mRssi > TDSCDMA_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - else if (mRssi >= TDSCDMA_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT; - else if (mRssi >= TDSCDMA_RSSI_GOOD) mLevel = SIGNAL_STRENGTH_GOOD; - else if (mRssi >= TDSCDMA_RSSI_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE; - else if (mRssi >= TDSCDMA_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR; + if (mRscp > TDSCDMA_RSCP_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + else if (mRscp >= TDSCDMA_RSCP_GREAT) mLevel = SIGNAL_STRENGTH_GREAT; + else if (mRscp >= TDSCDMA_RSCP_GOOD) mLevel = SIGNAL_STRENGTH_GOOD; + else if (mRscp >= TDSCDMA_RSCP_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE; + else if (mRscp >= TDSCDMA_RSCP_POOR) mLevel = SIGNAL_STRENGTH_POOR; else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } /** - * Get the signal strength as dBm + * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. */ @Override public int getDbm() { @@ -159,6 +157,23 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen } /** + * Get the RSSI as dBm value -113..-51dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. + * + * @hide + */ + public int getRssi() { + return mRssi; + } + + /** + * Get the BER as an ASU value 0..7, 99, or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. + * @hide + */ + public int getBitErrorRate() { + return mBitErrorRate; + } + + /** * Get the RSCP in ASU. * * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69 diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java index d9fd7f39aed3..169325276821 100644 --- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntRange; import android.annotation.StringDef; import android.os.Parcel; import android.os.Parcelable; @@ -66,7 +67,7 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp"; // Default to RSSI for backwards compatibility with older devices - private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI; + private static final String DEFAULT_LEVEL_CALCULATION_METHOD = LEVEL_CALCULATION_METHOD_RSSI; private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or @@ -143,13 +144,9 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } - /** - * Retrieve an abstract level value for the overall signal strength. - * - * @return a single integer from 0 to 4 representing the general signal quality. - * 0 represents very poor signal strength while 4 represents a very strong signal strength. - */ + /** {@inheritDoc} */ @Override + @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) public int getLevel() { return mLevel; } @@ -161,14 +158,14 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements int[] rscpThresholds; if (cc == null) { - calcMethod = sLevelCalculationMethod; + calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD; rscpThresholds = sRscpThresholds; } else { // TODO: abstract this entire thing into a series of functions calcMethod = cc.getString( CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, - sLevelCalculationMethod); - if (TextUtils.isEmpty(calcMethod)) calcMethod = sLevelCalculationMethod; + DEFAULT_LEVEL_CALCULATION_METHOD); + if (TextUtils.isEmpty(calcMethod)) calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD; rscpThresholds = cc.getIntArray( CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY); if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) { @@ -202,7 +199,7 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements } /** - * Get the signal strength as dBm + * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. */ @Override public int getDbm() { diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 8c92e84b45b6..1a160f4f57a6 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -339,6 +339,9 @@ public class ServiceState implements Parcelable { private List<NetworkRegistrationInfo> mNetworkRegistrationInfos = new ArrayList<>(); + private String mOperatorAlphaLongRaw; + private String mOperatorAlphaShortRaw; + /** * get String description of roaming type * @hide @@ -420,6 +423,8 @@ public class ServiceState implements Parcelable { mNetworkRegistrationInfos = s.mNetworkRegistrationInfos == null ? null : new ArrayList<>(s.mNetworkRegistrationInfos); mNrFrequencyRange = s.mNrFrequencyRange; + mOperatorAlphaLongRaw = s.mOperatorAlphaLongRaw; + mOperatorAlphaShortRaw = s.mOperatorAlphaShortRaw; } /** @@ -453,6 +458,8 @@ public class ServiceState implements Parcelable { mChannelNumber = in.readInt(); mCellBandwidths = in.createIntArray(); mNrFrequencyRange = in.readInt(); + mOperatorAlphaLongRaw = in.readString(); + mOperatorAlphaShortRaw = in.readString(); } public void writeToParcel(Parcel out, int flags) { @@ -478,6 +485,8 @@ public class ServiceState implements Parcelable { out.writeInt(mChannelNumber); out.writeIntArray(mCellBandwidths); out.writeInt(mNrFrequencyRange); + out.writeString(mOperatorAlphaLongRaw); + out.writeString(mOperatorAlphaShortRaw); } public int describeContents() { @@ -836,7 +845,9 @@ public class ServiceState implements Parcelable { mIsEmergencyOnly, mLteEarfcnRsrpBoost, mNetworkRegistrationInfos, - mNrFrequencyRange); + mNrFrequencyRange, + mOperatorAlphaLongRaw, + mOperatorAlphaShortRaw); } @Override @@ -862,6 +873,8 @@ public class ServiceState implements Parcelable { && equalsHandlesNulls(mCdmaDefaultRoamingIndicator, s.mCdmaDefaultRoamingIndicator) && mIsEmergencyOnly == s.mIsEmergencyOnly + && equalsHandlesNulls(mOperatorAlphaLongRaw, s.mOperatorAlphaLongRaw) + && equalsHandlesNulls(mOperatorAlphaShortRaw, s.mOperatorAlphaShortRaw) && (mNetworkRegistrationInfos == null ? s.mNetworkRegistrationInfos == null : s.mNetworkRegistrationInfos != null && mNetworkRegistrationInfos.containsAll(s.mNetworkRegistrationInfos)) @@ -1019,6 +1032,8 @@ public class ServiceState implements Parcelable { .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost) .append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos) .append(", mNrFrequencyRange=").append(mNrFrequencyRange) + .append(", mOperatorAlphaLongRaw=").append(mOperatorAlphaLongRaw) + .append(", mOperatorAlphaShortRaw=").append(mOperatorAlphaShortRaw) .append("}").toString(); } @@ -1056,6 +1071,8 @@ public class ServiceState implements Parcelable { .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) .build()); + mOperatorAlphaLongRaw = null; + mOperatorAlphaShortRaw = null; } public void setStateOutOfService() { @@ -1297,6 +1314,8 @@ public class ServiceState implements Parcelable { m.putInt("ChannelNumber", mChannelNumber); m.putIntArray("CellBandwidths", mCellBandwidths); m.putInt("mNrFrequencyRange", mNrFrequencyRange); + m.putString("operator-alpha-long-raw", mOperatorAlphaLongRaw); + m.putString("operator-alpha-short-raw", mOperatorAlphaShortRaw); } /** @hide */ @@ -1906,4 +1925,36 @@ public class ServiceState implements Parcelable { return state; } + + /** + * @hide + */ + public void setOperatorAlphaLongRaw(String operatorAlphaLong) { + mOperatorAlphaLongRaw = operatorAlphaLong; + } + + /** + * The current registered raw data network operator name in long alphanumeric format. + * + * @hide + */ + public String getOperatorAlphaLongRaw() { + return mOperatorAlphaLongRaw; + } + + /** + * @hide + */ + public void setOperatorAlphaShortRaw(String operatorAlphaShort) { + mOperatorAlphaShortRaw = operatorAlphaShort; + } + + /** + * The current registered raw data network operator name in short alphanumeric format. + * + * @hide + */ + public String getOperatorAlphaShortRaw() { + return mOperatorAlphaShortRaw; + } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index a933da753c41..57c84a638f12 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2749,6 +2749,8 @@ public class SubscriptionManager { * * @throws SecurityException if the caller doesn't meet the requirements * outlined above. + * @throws IllegalArgumentException if any of the subscriptions in the list doesn't exist. + * @throws IllegalStateException if Telephony service is in bad state. * * @param subIdList list of subId that will be in the same group * @return groupUUID a UUID assigned to the subscription group. @@ -2797,6 +2799,7 @@ public class SubscriptionManager { * outlined above. * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist, * or the groupUuid doesn't exist. + * @throws IllegalStateException if Telephony service is in bad state. * * @param subIdList list of subId that need adding into the group * @param groupUuid the groupUuid the subscriptions are being added to. @@ -2849,6 +2852,7 @@ public class SubscriptionManager { * outlined above. * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong * the specified group. + * @throws IllegalStateException if Telephony service is in bad state. * * @param subIdList list of subId that need removing from their groups. * diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 7eea21860bce..a86fda4454d7 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -78,10 +78,11 @@ public class ApnSetting implements Parcelable { */ public static final int TYPE_NONE = ApnTypes.NONE; /** - * APN type for all APNs. + * APN type for all APNs (except wild-cardable types). * @hide */ - public static final int TYPE_ALL = ApnTypes.ALL | ApnTypes.MCX; + public static final int TYPE_ALL = ApnTypes.DEFAULT | ApnTypes.HIPRI | ApnTypes.MMS + | ApnTypes.SUPL | ApnTypes.DUN | ApnTypes.FOTA | ApnTypes.IMS | ApnTypes.CBS; /** APN type for default data traffic. */ public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI; /** APN type for MMS traffic. */ diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 4e6d07303b02..1aad4be5d66f 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -1177,7 +1177,7 @@ static int write_java_method_for_module( // Initialize the buffer with list data type. fprintf(out, " buff[pos] = LIST_TYPE;\n"); - fprintf(out, " buff[pos + 1] = %lu;\n", signature.size() + 2); + fprintf(out, " buff[pos + 1] = %zu;\n", signature.size() + 2); fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n"); // Write timestamp. diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java index 1e46d1b16feb..b07d8edde3d4 100644 --- a/wifi/java/android/net/wifi/aware/ConfigRequest.java +++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java @@ -213,7 +213,7 @@ public final class ConfigRequest implements Parcelable { * Builder used to build {@link ConfigRequest} objects. */ public static final class Builder { - private boolean mSupport5gBand = false; + private boolean mSupport5gBand = true; private int mMasterPreference = 0; private int mClusterLow = CLUSTER_ID_MIN; private int mClusterHigh = CLUSTER_ID_MAX; diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 52bb28485c72..db8220b41910 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -576,7 +576,7 @@ public class WifiAwareManagerTest { equalTo(configRequest.mClusterLow)); collector.checkThat("mMasterPreference", 0, equalTo(configRequest.mMasterPreference)); - collector.checkThat("mSupport5gBand", false, equalTo(configRequest.mSupport5gBand)); + collector.checkThat("mSupport5gBand", true, equalTo(configRequest.mSupport5gBand)); collector.checkThat("mDiscoveryWindowInterval.length", 2, equalTo(configRequest.mDiscoveryWindowInterval.length)); collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT, |