diff options
153 files changed, 3801 insertions, 1371 deletions
diff --git a/api/current.txt b/api/current.txt index 5997043cdd4a..535fbbcf1d73 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"; @@ -44380,9 +44381,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 +44395,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 +44420,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 +44432,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 +44457,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 +44508,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 +44528,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 +44538,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 +44549,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 +44566,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 +44578,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 +44588,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/system-current.txt b/api/system-current.txt index 3ee6a49c1b44..76b8f6610590 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5980,7 +5980,7 @@ package android.provider { field public static final String NON_INDEXABLES_KEYS_PATH = "settings/non_indexables_key"; field public static final String PROVIDER_INTERFACE = "android.content.action.SEARCH_INDEXABLES_PROVIDER"; field public static final String SLICE_URI_PAIRS = "slice_uri_pairs"; - field public static final String[] SLICE_URI_PAIRS_COLUMNS; + field @NonNull public static final String[] SLICE_URI_PAIRS_COLUMNS; field public static final String SLICE_URI_PAIRS_PATH = "settings/slice_uri_pairs"; } @@ -6028,7 +6028,7 @@ package android.provider { method public android.database.Cursor query(android.net.Uri, String[], String, String[], String); method public abstract android.database.Cursor queryNonIndexableKeys(String[]); method public abstract android.database.Cursor queryRawData(String[]); - method public android.database.Cursor querySliceUriPairs(); + method @Nullable public android.database.Cursor querySliceUriPairs(); method public abstract android.database.Cursor queryXmlResources(String[]); method public final int update(android.net.Uri, android.content.ContentValues, String, String[]); } @@ -6062,11 +6062,6 @@ package android.provider { field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; field public static final String CARRIER_APP_NAMES = "carrier_app_names"; field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist"; - field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold"; - field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type"; - field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1 - field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval"; - field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold"; field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus"; field public static final String DEVICE_DEMO_MODE = "device_demo_mode"; field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data"; diff --git a/api/test-current.txt b/api/test-current.txt index b35b90f70749..f76881d19e93 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2160,11 +2160,6 @@ package android.provider { field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls"; field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; - field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold"; - field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type"; - field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1 - field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval"; - field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold"; field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold"; field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions"; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 146cf0cd2da9..f7608f5320e8 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -159,7 +159,7 @@ message Atom { BiometricAcquired biometric_acquired = 87; BiometricAuthenticated biometric_authenticated = 88; BiometricErrorOccurred biometric_error_occurred = 89; - Notification notification = 90; + // Atom number 90 is available for use. BatteryHealthSnapshot battery_health_snapshot = 91; SlowIo slow_io = 92; BatteryCausedShutdown battery_caused_shutdown = 93; @@ -3199,76 +3199,6 @@ message BiometricEnrolled { optional bool success = 4; } -message Notification { - - // Type of notification event. - enum Type { - TYPE_UNKNOWN = 0; - // Notification became visible to the user. - TYPE_OPEN = 1; - // Notification became hidden. - TYPE_CLOSE = 2; - // Notification switched to detail mode. - TYPE_DETAIL = 3; - // Notification was clicked. - TYPE_ACTION = 4; - // Notification was dismissed. - TYPE_DISMISS = 5; - // Notification switched to summary mode. The enum value of 14 is to - // match that of metrics_constants. - TYPE_COLLAPSE = 14; - } - optional Type type = 1; - - // Package name associated with the notification. - optional string package_name = 2; - - // Tag associated with notification. - optional string tag = 3; - - // Application-supplied ID associated with the notification. - optional int32 id = 4; - - // Index of notification in the notification panel. - optional int32 shade_index = 5; - - // The number of notifications in the notification panel. - optional int32 shade_count = 6; - - // Importance for the notification. - optional int32 importance = 7; - - // ID for the notification channel. - optional string channel_id = 8; - - // Importance for the notification channel. - optional int32 channel_importance = 9; - - // Application-supplied ID associated with the notifications group. - optional string group_id = 10; - - // Whether notification was a group summary. - optional bool group_summary = 11; - - // Reason for dismissal of a notification. This field is only meaningful for - // TYPE_DISMISS events. - optional int32 dismiss_reason = 12; - - // The first post time of notification, stable across updates. - optional int64 creation_millis = 13; - - // The most recent interruption time, or the creation time if no updates. - // Differs from update_millis because updates are filtered based on whether - // they actually interrupted the user. - optional int64 interruption_millis = 14; - - // The most recent update time, or the creation time if no updates. - optional int64 update_millis = 15; - - // The most recent visibility event. - optional int64 visible_millis = 16; -} - /* * Logs when a flag flip update occurrs. Used for mainline modules that update via flag flips. */ @@ -4989,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/Activity.java b/core/java/android/app/Activity.java index 883bcb896841..54fe65db499c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -820,8 +820,6 @@ public class Activity extends ContextThemeWrapper /** {@code true} if the activity lifecycle is in a state which supports picture-in-picture. * This only affects the client-side exception, the actual state check still happens in AMS. */ private boolean mCanEnterPictureInPicture = false; - /** true if the activity is going through a transient pause */ - /*package*/ boolean mTemporaryPause = false; /** true if the activity is being destroyed in order to recreate it with a new configuration */ /*package*/ boolean mChangingConfigurations = false; @UnsupportedAppUsage diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 38006dc5b943..b37d117238af 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -615,7 +615,6 @@ public final class ActivityThread extends ClientTransactionHandler { sb.append(", finished=").append(activity.isFinishing()); sb.append(", destroyed=").append(activity.isDestroyed()); sb.append(", startedActivity=").append(activity.mStartedActivity); - sb.append(", temporaryPause=").append(activity.mTemporaryPause); sb.append(", changingConfigurations=").append(activity.mChangingConfigurations); sb.append("}"); } @@ -3319,35 +3318,15 @@ public final class ActivityThread extends ClientTransactionHandler { } } - @UnsupportedAppUsage - void performNewIntents(IBinder token, List<ReferrerIntent> intents, boolean andPause) { + @Override + public void handleNewIntent(IBinder token, List<ReferrerIntent> intents) { final ActivityClientRecord r = mActivities.get(token); if (r == null) { return; } - final boolean resumed = !r.paused; - if (resumed) { - r.activity.mTemporaryPause = true; - performPauseActivityIfNeeded(r, "performNewIntents"); - } checkAndBlockForNetworkAccess(); deliverNewIntents(r, intents); - if (resumed) { - performResumeActivity(token, false, "performNewIntents"); - r.activity.mTemporaryPause = false; - } else if (andPause) { - // In this case the activity was in the paused state when we delivered the intent, - // to guarantee onResume gets called after onNewIntent we temporarily resume the - // activity and pause again as the caller wanted. - performResumeActivity(token, false, "performNewIntents"); - performPauseActivityIfNeeded(r, "performNewIntents"); - } - } - - @Override - public void handleNewIntent(IBinder token, List<ReferrerIntent> intents, boolean andPause) { - performNewIntents(token, intents, andPause); } public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) { @@ -4662,7 +4641,6 @@ public final class ActivityThread extends ClientTransactionHandler { try { // Now we are idle. r.activity.mCalled = false; - r.activity.mTemporaryPause = true; mInstrumentation.callActivityOnPause(r.activity); if (!r.activity.mCalled) { throw new SuperNotCalledException( @@ -4684,7 +4662,6 @@ public final class ActivityThread extends ClientTransactionHandler { deliverResults(r, results, reason); if (resumed) { r.activity.performResume(false, reason); - r.activity.mTemporaryPause = false; } } } diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 70badfae4a20..9dc8b45a71dc 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -150,8 +150,7 @@ public abstract class ClientTransactionHandler { Configuration overrideConfig); /** Deliver new intent. */ - public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents, - boolean andPause); + public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents); /** Deliver picture-in-picture mode change notification. */ public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode, diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index a52fb1a07b84..94b1d7770307 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -339,7 +339,7 @@ public class LocalActivityManager { ArrayList<ReferrerIntent> intents = new ArrayList<>(1); intents.add(new ReferrerIntent(intent, mParent.getPackageName())); if (localLOGV) Log.v(TAG, r.id + ": new intent"); - mActivityThread.performNewIntents(r, intents, false /* andPause */); + mActivityThread.handleNewIntent(r, intents); r.intent = intent; moveToState(r, mCurState); if (mSingleMode) { diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java index 4c7f56d4b076..2d1883836d02 100644 --- a/core/java/android/app/servertransaction/NewIntentItem.java +++ b/core/java/android/app/servertransaction/NewIntentItem.java @@ -16,6 +16,8 @@ package android.app.servertransaction; +import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; + import android.annotation.UnsupportedAppUsage; import android.app.ClientTransactionHandler; import android.os.IBinder; @@ -36,19 +38,17 @@ public class NewIntentItem extends ClientTransactionItem { @UnsupportedAppUsage private List<ReferrerIntent> mIntents; - private boolean mPause; - // TODO(lifecycler): Switch new intent handling to this scheme. - /*@Override + @Override public int getPostExecutionState() { return ON_RESUME; - }*/ + } @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); - client.handleNewIntent(token, mIntents, mPause); + client.handleNewIntent(token, mIntents); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } @@ -58,13 +58,12 @@ public class NewIntentItem extends ClientTransactionItem { private NewIntentItem() {} /** Obtain an instance initialized with provided params. */ - public static NewIntentItem obtain(List<ReferrerIntent> intents, boolean pause) { + public static NewIntentItem obtain(List<ReferrerIntent> intents) { NewIntentItem instance = ObjectPool.obtain(NewIntentItem.class); if (instance == null) { instance = new NewIntentItem(); } instance.mIntents = intents; - instance.mPause = pause; return instance; } @@ -72,7 +71,6 @@ public class NewIntentItem extends ClientTransactionItem { @Override public void recycle() { mIntents = null; - mPause = false; ObjectPool.recycle(this); } @@ -82,13 +80,11 @@ public class NewIntentItem extends ClientTransactionItem { /** Write to Parcel. */ @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeBoolean(mPause); dest.writeTypedList(mIntents, flags); } /** Read from Parcel. */ private NewIntentItem(Parcel in) { - mPause = in.readBoolean(); mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR); } @@ -112,19 +108,18 @@ public class NewIntentItem extends ClientTransactionItem { return false; } final NewIntentItem other = (NewIntentItem) o; - return mPause == other.mPause && Objects.equals(mIntents, other.mIntents); + return Objects.equals(mIntents, other.mIntents); } @Override public int hashCode() { int result = 17; - result = 31 * result + (mPause ? 1 : 0); result = 31 * result + mIntents.hashCode(); return result; } @Override public String toString() { - return "NewIntentItem{pause=" + mPause + ",intents=" + mIntents + "}"; + return "NewIntentItem{intents=" + mIntents + "}"; } } 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/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 8231985970aa..c9551378c190 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -25,6 +25,7 @@ import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; +import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; /** @@ -64,13 +65,12 @@ public abstract class DisplayManagerInternal { public abstract boolean isProximitySensorAvailable(); /** - * Take a screenshot of the specified display into the provided {@link Surface}. + * Take a screenshot of the specified display and return a buffer. * * @param displayId The display id to take the screenshot of. - * @param outSurface The {@link Surface} to take the screenshot into. - * @return True if the screenshot is taken. + * @return The buffer or null if we have failed. */ - public abstract boolean screenshot(int displayId, Surface outSurface); + public abstract SurfaceControl.ScreenshotGraphicBuffer screenshot(int displayId); /** * Returns information about the specified logical display. 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/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java index 8f68723e1b7d..f1f24fb4dd89 100644 --- a/core/java/android/os/image/DynamicSystemClient.java +++ b/core/java/android/os/image/DynamicSystemClient.java @@ -211,7 +211,7 @@ public class DynamicSystemClient { * Intent Keys */ /** - * Intent key: Size of system image, in bytes. + * Intent key: Size of the system image, in bytes. * @hide */ public static final String KEY_SYSTEM_SIZE = "KEY_SYSTEM_SIZE"; @@ -365,7 +365,7 @@ public class DynamicSystemClient { * * This function doesn't require prior calling {@link #bind}. * - * @param systemUrl A network URL or a file URL to system image. + * @param systemUrl a network Uri, a file Uri or a content Uri pointing to a system image file. * @param systemSize size of system image. */ @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) @@ -381,7 +381,7 @@ public class DynamicSystemClient { * * This function doesn't require prior calling {@link #bind}. * - * @param systemUrl A network URL or a file URL to system image. + * @param systemUrl a network Uri, a file Uri or a content Uri pointing to a system image file. * @param systemSize size of system image. * @param userdataSize bytes reserved for userdata. */ 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/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java index 42c2d5ced806..5f8266d2b579 100644 --- a/core/java/android/provider/SearchIndexablesContract.java +++ b/core/java/android/provider/SearchIndexablesContract.java @@ -16,6 +16,7 @@ package android.provider; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.ContentResolver; @@ -210,6 +211,7 @@ public class SearchIndexablesContract { /** * Cursor schema for SliceUriPairs. */ + @NonNull public static final String[] SLICE_URI_PAIRS_COLUMNS = new String[]{ SliceUriPairColumns.KEY, SliceUriPairColumns.SLICE_URI diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java index d505f02468d0..da29e2e5e39f 100644 --- a/core/java/android/provider/SearchIndexablesProvider.java +++ b/core/java/android/provider/SearchIndexablesProvider.java @@ -16,6 +16,7 @@ package android.provider; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.slice.Slice; import android.content.ContentProvider; @@ -184,6 +185,7 @@ public abstract class SearchIndexablesProvider extends ContentProvider { * Returns a {@link Cursor} linking {@link Slice} {@link Uri Uris} to the * corresponding Settings key. */ + @Nullable public Cursor querySliceUriPairs() { // By default no-op; return null; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3db6b2bcaa89..6e897975963f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11199,62 +11199,6 @@ public final class Settings { public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; /** - * The threshold value for the number of consecutive dns timeout events received to be a - * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this - * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note - * that the value should be {@code > 0} if the DNS data stall detection is enabled. - * - * @hide - */ - @SystemApi - @TestApi - public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = - "data_stall_consecutive_dns_timeout_threshold"; - - /** - * The minimal time interval in milliseconds for data stall reevaluation. - * - * @hide - */ - @SystemApi - @TestApi - public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = - "data_stall_min_evaluate_interval"; - - /** - * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting - * a data stall. - * - * @hide - */ - @SystemApi - @TestApi - public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = - "data_stall_valid_dns_time_threshold"; - - /** - * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing - * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values. - * - * Type: int - * Valid values: - * {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal. - * @hide - */ - @SystemApi - @TestApi - public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type"; - - /** - * Use dns timeout counts to detect data stall. - * - * @hide - */ - @SystemApi - @TestApi - public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; - - /** * Whether to try cellular data recovery when a bad network is reported. * * @hide diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index f39ef9afdb3c..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() { } @@ -695,6 +697,8 @@ public abstract class AutofillService extends Service { * finishing the {@link FillCallback}. * * @return The history or {@code null} if there are no events. + * + * @throws RuntimeException if the event history could not be retrieved. */ @Nullable public final FillEventHistory getFillEventHistory() { final AutofillManager afm = getSystemService(AutofillManager.class); diff --git a/core/java/android/service/autofill/IFillCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl index 1bad1d7f474a..32cf712b5fd4 100644 --- a/core/java/android/service/autofill/IFillCallback.aidl +++ b/core/java/android/service/autofill/IFillCallback.aidl @@ -25,7 +25,7 @@ import android.service.autofill.FillResponse; * * @hide */ -interface IFillCallback { +oneway interface IFillCallback { void onCancellable(in ICancellationSignal cancellation); void onSuccess(in FillResponse response); void onFailure(int requestId, CharSequence message); 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/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 04046fe066e7..feff9db1a63e 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -42,6 +42,8 @@ public class FeatureFlagUtils { "settings_global_actions_force_grid_enabled"; public static final String GLOBAL_ACTIONS_PANEL_ENABLED = "settings_global_actions_panel_enabled"; + public static final String PIXEL_WALLPAPER_CATEGORY_SWITCH = + "settings_pixel_wallpaper_category_switch"; public static final String DYNAMIC_SYSTEM = "settings_dynamic_system"; private static final Map<String, String> DEFAULT_FLAGS; @@ -60,6 +62,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false"); DEFAULT_FLAGS.put(FORCE_GLOBAL_ACTIONS_GRID_ENABLED, "false"); DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true"); + DEFAULT_FLAGS.put(PIXEL_WALLPAPER_CATEGORY_SWITCH, "false"); DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "true"); DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false"); } diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index 30d3d7d069b5..dd22a26d61af 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -136,7 +136,13 @@ public final class StatsLog extends StatsLogInternal { * @param trainName name of install train. * @param trainVersionCode version code of the train. * @param options optional flags about this install. - * @param state current install state. + * The last 3 bits indicate options: + * 0x01: FLAG_REQUIRE_STAGING + * 0x02: FLAG_ROLLBACK_ENABLED + * 0x04: FLAG_REQUIRE_LOW_LATENCY_MONITOR + * @param state current install state. Defined as State enums in + * BinaryPushStateChanged atom in + * frameworks/base/cmds/statsd/src/atoms.proto * @param experimentIds experiment ids. * @return True if the log request was sent to statsd. */ 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/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index 1383463ef72f..a7801583f643 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -153,6 +153,7 @@ public class InsetsSourceConsumer { return; } mVisible = visible; + applyHiddenToControl(); applyLocalVisibilityOverride(); mController.notifyVisibilityChanged(); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index ec62e190d0b4..79363edb0955 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -439,10 +439,13 @@ public final class SurfaceControl implements Parcelable { public static class ScreenshotGraphicBuffer { private final GraphicBuffer mGraphicBuffer; private final ColorSpace mColorSpace; + private final boolean mContainsSecureLayers; - public ScreenshotGraphicBuffer(GraphicBuffer graphicBuffer, ColorSpace colorSpace) { + public ScreenshotGraphicBuffer(GraphicBuffer graphicBuffer, ColorSpace colorSpace, + boolean containsSecureLayers) { mGraphicBuffer = graphicBuffer; mColorSpace = colorSpace; + mContainsSecureLayers = containsSecureLayers; } /** @@ -453,13 +456,16 @@ public final class SurfaceControl implements Parcelable { * @param usage Hint indicating how the buffer will be used * @param unwrappedNativeObject The native object of GraphicBuffer * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named} + * @param containsSecureLayer Indicates whether this graphic buffer contains captured contents + * of secure layers, in which case the screenshot should not be persisted. */ private static ScreenshotGraphicBuffer createFromNative(int width, int height, int format, - int usage, long unwrappedNativeObject, int namedColorSpace) { + int usage, long unwrappedNativeObject, int namedColorSpace, + boolean containsSecureLayers) { GraphicBuffer graphicBuffer = GraphicBuffer.createFromExisting(width, height, format, usage, unwrappedNativeObject); ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]); - return new ScreenshotGraphicBuffer(graphicBuffer, colorSpace); + return new ScreenshotGraphicBuffer(graphicBuffer, colorSpace, containsSecureLayers); } public ColorSpace getColorSpace() { @@ -469,6 +475,10 @@ public final class SurfaceControl implements Parcelable { public GraphicBuffer getGraphicBuffer() { return mGraphicBuffer; } + + public boolean containsSecureLayers() { + return mContainsSecureLayers; + } } /** diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 94be25f00e4c..988fad2fb28e 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -43,6 +43,7 @@ import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.LabeledIntent; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; @@ -117,12 +118,18 @@ import com.google.android.collect.Lists; import java.io.IOException; import java.lang.annotation.Retention; +import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +/** + * The Chooser Activity handles intent resolution specifically for sharing intents - + * for example, those generated by @see android.content.Intent#createChooser(Intent, CharSequence). + * + */ public class ChooserActivity extends ResolverActivity { private static final String TAG = "ChooserActivity"; @@ -200,6 +207,8 @@ public class ChooserActivity extends ResolverActivity { /** {@link ChooserActivity#getBaseScore} */ private static final float SHORTCUT_TARGET_SCORE_BOOST = 10.f; private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment"; + // TODO: Update to handle landscape instead of using static value + private static final int MAX_RANKED_TARGETS = 4; private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>(); @@ -216,6 +225,7 @@ public class ChooserActivity extends ResolverActivity { private boolean mListViewDataChanged = false; + @Retention(SOURCE) @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT}) private @interface ContentPreviewType { @@ -228,6 +238,9 @@ public class ChooserActivity extends ResolverActivity { private static final int CONTENT_PREVIEW_TEXT = 3; protected MetricsLogger mMetricsLogger; + // Sorted list of DisplayResolveInfos for the alphabetical app section. + private List<ResolverActivity.DisplayResolveInfo> mSortedList = new ArrayList<>(); + private final Handler mChooserHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -935,8 +948,11 @@ public class ChooserActivity extends ResolverActivity { // Note that this is only safe because the Intent handled by the ChooserActivity is // guaranteed to contain no extras unknown to the local ClassLoader. That is why this // method can not be replaced in the ResolverActivity whole hog. - return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, - super.shouldAutoLaunchSingleChoice(target)); + if (!super.shouldAutoLaunchSingleChoice(target)) { + return false; + } + + return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true); } @Override @@ -961,10 +977,6 @@ public class ChooserActivity extends ResolverActivity { @Override protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) { - if (target instanceof NotSelectableTargetInfo) { - return false; - } - if (mRefinementIntentSender != null) { final Intent fillIn = new Intent(); final List<Intent> sourceIntents = target.getAllSourceIntents(); @@ -997,6 +1009,11 @@ public class ChooserActivity extends ResolverActivity { @Override public void startSelected(int which, boolean always, boolean filtered) { + TargetInfo targetInfo = mChooserListAdapter.targetInfoForPosition(which, filtered); + if (targetInfo != null && targetInfo instanceof NotSelectableTargetInfo) { + return; + } + final long selectionCost = System.currentTimeMillis() - mChooserShownTime; super.startSelected(which, always, filtered); @@ -1405,6 +1422,30 @@ public class ChooserActivity extends ResolverActivity { } } + private void updateAlphabeticalList() { + if (getDisplayList().size() > MAX_RANKED_TARGETS) { + mSortedList.clear(); + mSortedList.addAll(getDisplayList()); + Collections.sort(mSortedList, new AzInfoComparator(ChooserActivity.this)); + } + } + + /** + * Sort intents alphabetically based on display label. + */ + class AzInfoComparator implements Comparator<ResolverActivity.DisplayResolveInfo> { + Collator mCollator; + AzInfoComparator(Context context) { + mCollator = Collator.getInstance(context.getResources().getConfiguration().locale); + } + + @Override + public int compare(ResolverActivity.DisplayResolveInfo lhsp, + ResolverActivity.DisplayResolveInfo rhsp) { + return mCollator.compare(lhsp.getDisplayLabel(), rhsp.getDisplayLabel()); + } + } + protected MetricsLogger getMetricsLogger() { if (mMetricsLogger == null) { mMetricsLogger = new MetricsLogger(); @@ -1451,7 +1492,8 @@ public class ChooserActivity extends ResolverActivity { mPm, getTargetIntent(), getReferrerPackageName(), - mLaunchedFromUid); + mLaunchedFromUid + ); } @VisibleForTesting @@ -1527,6 +1569,10 @@ public class ChooserActivity extends ResolverActivity { public ChooserTarget getChooserTarget() { return null; } + + public boolean isSuspended() { + return false; + } } final class PlaceHolderTargetInfo extends NotSelectableTargetInfo { @@ -1552,6 +1598,7 @@ public class ChooserActivity extends ResolverActivity { private final Intent mFillInIntent; private final int mFillInFlags; private final float mModifiedScore; + private boolean mIsSuspended; SelectableTargetInfo(DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget, float modifiedScore) { @@ -1580,6 +1627,8 @@ public class ChooserActivity extends ResolverActivity { mFillInIntent = null; mFillInFlags = 0; + ApplicationInfo ai = sourceInfo.getResolveInfo().activityInfo.applicationInfo; + mIsSuspended = (ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0; } private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) { @@ -1594,6 +1643,10 @@ public class ChooserActivity extends ResolverActivity { mModifiedScore = other.mModifiedScore; } + public boolean isSuspended() { + return mIsSuspended; + } + /** * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip * the call to LauncherApps#getShortcuts(ShortcutQuery). @@ -1974,6 +2027,7 @@ public class ChooserActivity extends ResolverActivity { queryTargetServices(this); } + updateAlphabeticalList(); } @Override @@ -1983,13 +2037,17 @@ public class ChooserActivity extends ResolverActivity { @Override public int getCount() { - return super.getCount() + getSelectableServiceTargetCount() + getCallerTargetCount(); + return getStandardTargetCount() + getAlphaTargetCount() + + getSelectableServiceTargetCount() + getCallerTargetCount(); } @Override public int getUnfilteredCount() { - return super.getUnfilteredCount() + getSelectableServiceTargetCount() - + getCallerTargetCount(); + int appTargets = super.getUnfilteredCount(); + if (appTargets > MAX_RANKED_TARGETS) { + appTargets = appTargets + MAX_RANKED_TARGETS; + } + return appTargets + getSelectableServiceTargetCount() + getCallerTargetCount(); } public int getCallerTargetCount() { @@ -2018,7 +2076,13 @@ public class ChooserActivity extends ResolverActivity { } public int getStandardTargetCount() { - return super.getCount(); + int standardCount = super.getCount(); + return standardCount > MAX_RANKED_TARGETS ? MAX_RANKED_TARGETS : standardCount; + } + + int getAlphaTargetCount() { + int standardCount = super.getCount(); + return standardCount > MAX_RANKED_TARGETS ? standardCount : 0; } public int getPositionTargetType(int position) { @@ -2036,7 +2100,7 @@ public class ChooserActivity extends ResolverActivity { } offset += callerTargetCount; - final int standardTargetCount = super.getCount(); + final int standardTargetCount = getStandardTargetCount(); if (position - offset < standardTargetCount) { return TARGET_STANDARD; } @@ -2049,10 +2113,17 @@ public class ChooserActivity extends ResolverActivity { return targetInfoForPosition(position, true); } + + /** + * Find target info for a given position. + * Since ChooserActivity displays several sections of content, determine which + * section provides this item. + */ @Override public TargetInfo targetInfoForPosition(int position, boolean filtered) { int offset = 0; + // Direct share targets final int serviceTargetCount = filtered ? getServiceTargetCount() : getSelectableServiceTargetCount(); if (position < serviceTargetCount) { @@ -2060,16 +2131,32 @@ public class ChooserActivity extends ResolverActivity { } offset += serviceTargetCount; + // Targets provided by calling app final int callerTargetCount = getCallerTargetCount(); if (position - offset < callerTargetCount) { return mCallerTargets.get(position - offset); } offset += callerTargetCount; - return filtered ? super.getItem(position - offset) - : getDisplayResolveInfo(position - offset); + // Ranked app targets + if (position - offset < MAX_RANKED_TARGETS) { + return filtered ? super.getItem(position - offset) + : getDisplayResolveInfo(position - offset); + } + offset += MAX_RANKED_TARGETS; + + // Alphabetical complete app target list. + Log.e(TAG, mSortedList.toString()); + if (position - offset < mSortedList.size()) { + return mSortedList.get(position - offset); + } + + return null; + } + + /** * Evaluate targets for inclusion in the direct share area. May not be included * if score is too low. @@ -2100,6 +2187,9 @@ public class ChooserActivity extends ResolverActivity { final float baseScore = getBaseScore(origTarget, isShortcutResult); Collections.sort(targets, mBaseTargetComparator); + + + float lastScore = 0; boolean shouldNotify = false; for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) { @@ -2204,6 +2294,7 @@ public class ChooserActivity extends ResolverActivity { } } + private boolean isSendAction(Intent targetIntent) { if (targetIntent == null) { return false; @@ -2299,6 +2390,9 @@ public class ChooserActivity extends ResolverActivity { + Math.ceil( (float) mChooserListAdapter.getStandardTargetCount() / getMaxTargetsPerRow()) + + Math.ceil( + (float) mChooserListAdapter.getAlphaTargetCount() + / getMaxTargetsPerRow()) ); } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index f671a753493e..ad1e767f011a 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -44,6 +44,8 @@ import android.content.pm.UserInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -132,6 +134,8 @@ public class ResolverActivity extends Activity { private boolean mRegistered; + private ColorMatrixColorFilter mSuspendedMatrixColorFilter; + /** See {@link #setRetainInOnStop}. */ private boolean mRetainInOnStop; @@ -350,6 +354,8 @@ public class ResolverActivity extends Activity { bindProfileView(); } + initSuspendedColorMatrix(); + if (isVoiceInteraction()) { onSetupVoiceInteraction(); } @@ -367,6 +373,25 @@ public class ResolverActivity extends Activity { mAdapter.handlePackagesChanged(); } + private void initSuspendedColorMatrix() { + int grayValue = 127; + float scale = 0.5f; // half bright + + ColorMatrix tempBrightnessMatrix = new ColorMatrix(); + float[] mat = tempBrightnessMatrix.getArray(); + mat[0] = scale; + mat[6] = scale; + mat[12] = scale; + mat[4] = grayValue; + mat[9] = grayValue; + mat[14] = grayValue; + + ColorMatrix matrix = new ColorMatrix(); + matrix.setSaturation(0.0f); + matrix.preConcat(tempBrightnessMatrix); + mSuspendedMatrixColorFilter = new ColorMatrixColorFilter(matrix); + } + /** * Perform any initialization needed for voice interaction. */ @@ -1019,7 +1044,14 @@ public class ResolverActivity extends Activity { if (target != null) { safelyStartActivity(target); + + // Rely on the ActivityManager to pop up a dialog regarding app suspension + // and return false + if (target.isSuspended()) { + return false; + } } + return true; } @@ -1106,7 +1138,7 @@ public class ResolverActivity extends Activity { } public boolean shouldAutoLaunchSingleChoice(TargetInfo target) { - return true; + return !target.isSuspended(); } public void showTargetDetails(ResolveInfo ri) { @@ -1326,6 +1358,7 @@ public class ResolverActivity extends Activity { private final CharSequence mExtendedInfo; private final Intent mResolvedIntent; private final List<Intent> mSourceIntents = new ArrayList<>(); + private boolean mIsSuspended; public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel, CharSequence pInfo, Intent pOrigIntent) { @@ -1341,6 +1374,8 @@ public class ResolverActivity extends Activity { final ActivityInfo ai = mResolveInfo.activityInfo; intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name)); + mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0; + mResolvedIntent = intent; } @@ -1410,7 +1445,6 @@ public class ResolverActivity extends Activity { @Override public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) { - if (mEnableChooserDelegate) { return activity.startAsCallerImpl(mResolvedIntent, options, false, userId); } else { @@ -1424,6 +1458,14 @@ public class ResolverActivity extends Activity { activity.startActivityAsUser(mResolvedIntent, options, user); return false; } + + public boolean isSuspended() { + return mIsSuspended; + } + } + + List<DisplayResolveInfo> getDisplayList() { + return mAdapter.mDisplayList; } /** @@ -1515,6 +1557,11 @@ public class ResolverActivity extends Activity { * @return the list of supported source intents deduped against this single target */ List<Intent> getAllSourceIntents(); + + /** + * @return true if this target can be selected by the user + */ + boolean isSuspended(); } public class ResolveListAdapter extends BaseAdapter { @@ -1523,12 +1570,12 @@ public class ResolverActivity extends Activity { private final List<ResolveInfo> mBaseResolveList; protected ResolveInfo mLastChosen; private DisplayResolveInfo mOtherProfile; - private boolean mHasExtendedInfo; private ResolverListController mResolverListController; private int mPlaceholderCount; protected final LayoutInflater mInflater; + // This one is the list that the Adapter will actually present. List<DisplayResolveInfo> mDisplayList; List<ResolvedComponentInfo> mUnfilteredResolveList; @@ -1709,6 +1756,7 @@ public class ResolverActivity extends Activity { } } + private void processSortedList(List<ResolvedComponentInfo> sortedComponents) { int N; if (sortedComponents != null && (N = sortedComponents.size()) != 0) { @@ -1746,6 +1794,7 @@ public class ResolverActivity extends Activity { } } + for (ResolvedComponentInfo rci : sortedComponents) { final ResolveInfo ri = rci.getResolveInfoAt(0); if (ri != null) { @@ -1755,9 +1804,12 @@ public class ResolverActivity extends Activity { } } + postListReadyRunnable(); } + + /** * Some necessary methods for creating the list are initiated in onCreate and will also * determine the layout known. We therefore can't update the UI inline and post to the @@ -1891,19 +1943,6 @@ public class ResolverActivity extends Activity { return position; } - public boolean hasExtendedInfo() { - return mHasExtendedInfo; - } - - public boolean hasResolvedTarget(ResolveInfo info) { - for (int i = 0, N = mDisplayList.size(); i < N; i++) { - if (resolveInfoMatch(info, mDisplayList.get(i).getResolveInfo())) { - return true; - } - } - return false; - } - public int getDisplayResolveInfoCount() { return mDisplayList.size(); } @@ -1960,6 +1999,12 @@ public class ResolverActivity extends Activity { holder.text2.setText(subLabel); } + if (info.isSuspended()) { + holder.icon.setColorFilter(mSuspendedMatrixColorFilter); + } else { + holder.icon.setColorFilter(null); + } + if (info instanceof DisplayResolveInfo && !((DisplayResolveInfo) info).hasDisplayIcon()) { new LoadIconTask((DisplayResolveInfo) info, holder.icon).execute(); @@ -1969,6 +2014,7 @@ public class ResolverActivity extends Activity { } } + @VisibleForTesting public static final class ResolvedComponentInfo { public final ComponentName name; diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index 156baf03f563..a3cfa8786d59 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -25,7 +25,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.RemoteException; @@ -153,11 +152,6 @@ public class ResolverListController { } // Filter out any activities that the launched uid does not have permission for. - // - // Also filter out those that are suspended because they couldn't be started. We don't do this - // when we have an explicit list of resolved activities, because that only happens when - // we are being subclassed, so we can safely launch whatever they gave us. - // // To preserve the inputList, optionally will return the original list if any modification has // been made. @VisibleForTesting @@ -171,9 +165,8 @@ public class ResolverListController { int granted = ActivityManager.checkComponentPermission( ai.permission, mLaunchedFromUid, ai.applicationInfo.uid, ai.exported); - boolean suspended = (ai.applicationInfo.flags - & ApplicationInfo.FLAG_SUSPENDED) != 0; - if (granted != PackageManager.PERMISSION_GRANTED || suspended + + if (granted != PackageManager.PERMISSION_GRANTED || isComponentFiltered(ai.getComponentName())) { // Access not allowed! We're about to filter an item, // so modify the unfiltered version if it hasn't already been modified. @@ -253,6 +246,7 @@ public class ResolverListController { isComputed = true; } Collections.sort(inputList, mResolverComparator); + long afterRank = System.currentTimeMillis(); if (DEBUG) { Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank)); @@ -262,6 +256,7 @@ public class ResolverListController { } } + private static boolean isSameResolvedComponent(ResolveInfo a, ResolverActivity.ResolvedComponentInfo b) { final ActivityInfo ai = a.activityInfo; 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/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java index 1155854efd55..ef5178aca40a 100644 --- a/core/java/com/android/internal/infra/AbstractRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractRemoteService.java @@ -449,13 +449,13 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I return; } mBinding = false; - mService = getServiceInterface(service); try { service.linkToDeath(AbstractRemoteService.this, 0); } catch (RemoteException re) { handleBinderDied(); return; } + mService = getServiceInterface(service); handleOnConnectedStateChangedInternal(true); mServiceDied = false; } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index c254266961cf..3135c62c9c61 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -250,10 +250,11 @@ static jobject nativeScreenshot(JNIEnv* env, jclass clazz, Rect sourceCrop = rectFromObj(env, sourceCropObj); sp<GraphicBuffer> buffer; + bool capturedSecureLayers = false; status_t res = ScreenshotClient::capture(displayToken, dataspace, ui::PixelFormat::RGBA_8888, sourceCrop, width, height, - useIdentityTransform, rotation, captureSecureLayers, &buffer); + useIdentityTransform, rotation, captureSecureLayers, &buffer, capturedSecureLayers); if (res != NO_ERROR) { return NULL; } @@ -266,7 +267,8 @@ static jobject nativeScreenshot(JNIEnv* env, jclass clazz, buffer->getPixelFormat(), (jint)buffer->getUsage(), (jlong)buffer.get(), - namedColorSpace); + namedColorSpace, + capturedSecureLayers); } static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken, @@ -315,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) { @@ -1455,7 +1458,7 @@ int register_android_view_SurfaceControl(JNIEnv* env) MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz); gScreenshotGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, screenshotGraphicsBufferClazz, - "createFromNative", "(IIIIJI)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;"); + "createFromNative", "(IIIIJIZ)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;"); jclass displayedContentSampleClazz = FindClassOrDie(env, "android/hardware/display/DisplayedContentSample"); 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/config.xml b/core/res/res/values/config.xml index e8cc96cbd848..0163fc0e20ce 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3345,6 +3345,9 @@ <!-- True if the device supports system decorations on secondary displays. --> <bool name="config_supportsSystemDecorsOnSecondaryDisplays">true</bool> + <!-- True if the device supports insecure lock screen. --> + <bool name="config_supportsInsecureLockScreen">true</bool> + <!-- True if the device requires AppWidgetService even if it does not have the PackageManager.FEATURE_APP_WIDGETS feature --> <bool name="config_enableAppWidgetService">false</bool> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 6f3adfd11a48..f8a2ac9f3e18 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -525,7 +525,7 @@ <!-- label for screenshot item in power menu --> <string name="global_action_screenshot">Screenshot</string> - <!-- Take bug report menu title [CHAR LIMIT=20] --> + <!-- Take bug report menu title [CHAR LIMIT=30] --> <string name="bugreport_title">Bug report</string> <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] --> <!-- TODO: remove if not used anymore --> @@ -1551,25 +1551,25 @@ <string-array name="face_acquired_vendor"> </string-array> - <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=50] --> + <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=69] --> <string name="face_error_hw_not_available">Can\u2019t verify face. Hardware not available.</string> <!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] --> <string name="face_error_timeout">Face timeout reached. Try again.</string> - <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=60] --> + <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=69] --> <string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string> <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] --> <string name="face_error_canceled">Face operation canceled</string> - <!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=50] --> + <!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=54] --> <string name="face_error_user_canceled">Face authentication canceled by user</string> <!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] --> <string name="face_error_lockout">Too many attempts. Try again later.</string> - <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=60] --> + <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=71] --> <string name="face_error_lockout_permanent">Too many attempts. Face authentication disabled.</string> <!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] --> <string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string> <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=52] --> <string name="face_error_not_enrolled">You haven\u2019t set up face authentication</string> - <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=60] --> + <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=61] --> <string name="face_error_hw_not_present">Face authentication is not supported on this device</string> <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 664059afd6bc..b87381364b1a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -391,6 +391,7 @@ <java-symbol type="bool" name="config_supportsMultiDisplay" /> <java-symbol type="bool" name="config_noHomeScreen" /> <java-symbol type="bool" name="config_supportsSystemDecorsOnSecondaryDisplays" /> + <java-symbol type="bool" name="config_supportsInsecureLockScreen" /> <java-symbol type="bool" name="config_guestUserEphemeral" /> <java-symbol type="bool" name="config_localDisplaysMirrorContent" /> <java-symbol type="bool" name="config_localDisplaysPrivate" /> diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index 447f28e06d7e..5c8bced25108 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -212,15 +212,15 @@ public class ObjectPoolTests { @Test public void testRecycleNewIntentItem() { - NewIntentItem emptyItem = NewIntentItem.obtain(null, false); - NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), true); + NewIntentItem emptyItem = NewIntentItem.obtain(null); + NewIntentItem item = NewIntentItem.obtain(referrerIntentList()); assertNotSame(item, emptyItem); assertFalse(item.equals(emptyItem)); item.recycle(); assertEquals(item, emptyItem); - NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList(), true); + NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList()); assertSame(item, item2); assertFalse(item2.equals(emptyItem)); } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index d117b4096ca0..bffeb2a6c90e 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -128,7 +128,7 @@ public class TransactionParcelTests { @Test public void testNewIntent() { // Write to parcel - NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), true /* pause */); + NewIntentItem item = NewIntentItem.obtain(referrerIntentList()); writeAndPrepareForReading(item); // Read from parcel and assert diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 8cc6e37db48a..655070722c9a 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -203,11 +203,7 @@ public class SettingsBackupTest { Settings.Global.DATA_ROAMING, Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, - Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD, - Settings.Global.DATA_STALL_EVALUATION_TYPE, - Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, - Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD, Settings.Global.DEBUG_APP, Settings.Global.DEBUG_VIEW_ATTRIBUTES, Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index 36f540c47973..be78b694f53a 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -266,47 +266,46 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT; } - if (nullptr != vkManager.mGetPhysicalDeviceImageFormatProperties2) { - VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo; - externalImageFormatInfo.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; - externalImageFormatInfo.pNext = nullptr; - externalImageFormatInfo.handleType = - VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; - - VkPhysicalDeviceImageFormatInfo2 imageFormatInfo; - imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; - imageFormatInfo.pNext = &externalImageFormatInfo; - imageFormatInfo.format = vkPixelFormat; - imageFormatInfo.type = VK_IMAGE_TYPE_2D; - imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageFormatInfo.usage = usageFlags; - imageFormatInfo.flags = 0; - - VkAndroidHardwareBufferUsageANDROID hwbUsage; - hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID; - hwbUsage.pNext = nullptr; - - VkImageFormatProperties2 imgFormProps; - imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; - imgFormProps.pNext = &hwbUsage; - - res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice, - &imageFormatInfo, &imgFormProps); - if (VK_SUCCESS != res) { - ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2"); - return nullptr; - } + LOG_ALWAYS_FATAL_IF(nullptr == vkManager.mGetPhysicalDeviceImageFormatProperties2, + "vkGetPhysicalDeviceImageFormatProperties2 is missing"); + VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo; + externalImageFormatInfo.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; + externalImageFormatInfo.pNext = nullptr; + externalImageFormatInfo.handleType = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + VkPhysicalDeviceImageFormatInfo2 imageFormatInfo; + imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; + imageFormatInfo.pNext = &externalImageFormatInfo; + imageFormatInfo.format = vkPixelFormat; + imageFormatInfo.type = VK_IMAGE_TYPE_2D; + imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageFormatInfo.usage = usageFlags; + imageFormatInfo.flags = 0; + + VkAndroidHardwareBufferUsageANDROID hwbUsage; + hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID; + hwbUsage.pNext = nullptr; + + VkImageFormatProperties2 imgFormProps; + imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; + imgFormProps.pNext = &hwbUsage; + + res = vkManager.mGetPhysicalDeviceImageFormatProperties2(vkManager.mPhysicalDevice, + &imageFormatInfo, &imgFormProps); + if (VK_SUCCESS != res) { + ALOGE("Failed to query GetPhysicalDeviceImageFormatProperties2"); + return nullptr; + } - windowInfo.windowUsageFlags = hwbUsage.androidHardwareBufferUsage; - if (vkManager.isQualcomm()) { - windowInfo.windowUsageFlags = - windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0; - } + uint64_t consumerUsage; + native_window_get_consumer_usage(window, &consumerUsage); + windowInfo.windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage; - } else { - ALOGE("VulkanSurface::Create() vkmGetPhysicalDeviceImageFormatProperties2 is missing"); - return nullptr; + if (vkManager.isQualcomm()) { + windowInfo.windowUsageFlags = + windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0; } /* diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp index 302cbd11da4b..9791da63359b 100644 --- a/native/android/system_fonts.cpp +++ b/native/android/system_fonts.cpp @@ -250,7 +250,8 @@ AFont* _Nonnull AFontMatcher_match( minikin::U16StringPiece(text, textLength), matcher->mFontStyle, matcher->mLocaleListId, - static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant)); + static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant), + 1 /* maxRun */); const minikin::Font* font = runs[0].fakedFont.font; std::unique_ptr<AFont> result = std::make_unique<AFont>(); diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml index a72e4e2c1b74..2a66db124d10 100644 --- a/packages/DynamicSystemInstallationService/res/values/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values/strings.xml @@ -13,11 +13,11 @@ <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string> <!-- Displayed on notification: AndroidOnTap installation is completed [CHAR LIMIT=128] --> - <string name="notification_install_completed">New system is ready, you can reboot into it or discard it.</string> + <string name="notification_install_completed">System update is ready. To finish installing, restart your device.</string> <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] --> - <string name="notification_install_inprogress">Installation is in progress.</string> + <string name="notification_install_inprogress">Install in progress</string> <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] --> - <string name="notification_install_failed">Installation Failed.</string> + <string name="notification_install_failed">Install Failed</string> <!-- Displayed on notification: We are running in AndroidOnTap [CHAR LIMIT=128] --> <string name="notification_dynsystem_in_use">We are running in AndroidOnTap.</string> @@ -27,12 +27,12 @@ <string name="notification_action_discard">Discard</string> <!-- Action on notification: Uninstall AndroidOnTap [CHAR LIMIT=16] --> <string name="notification_action_uninstall">Uninstall</string> - <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] --> - <string name="notification_action_reboot_to_dynsystem">Reboot</string> + <!-- Action on notification: Restart to AndroidOnTap [CHAR LIMIT=16] --> + <string name="notification_action_reboot_to_dynsystem">Restart</string> <!-- Toast when installed AndroidOnTap is discarded [CHAR LIMIT=64] --> <string name="toast_dynsystem_discarded">Installed AndroidOnTap is discarded.</string> <!-- Toast when we fail to launch into AndroidOnTap [CHAR LIMIT=64] --> - <string name="toast_failed_to_reboot_to_dynsystem">Failed to reboot into AndroidOnTap.</string> + <string name="toast_failed_to_reboot_to_dynsystem">Failed to restart to AndroidOnTap.</string> </resources> diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java index 5c6885a801e8..fcbda1d5c63b 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java @@ -380,13 +380,13 @@ public class DynamicSystemInstallationService extends Service builder.setContentText(getString(R.string.notification_install_completed)); builder.addAction(new Notification.Action.Builder( - null, getString(R.string.notification_action_reboot_to_dynsystem), - createPendingIntent(ACTION_REBOOT_TO_DYN_SYSTEM)).build()); - - builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_discard), createPendingIntent(ACTION_DISCARD_INSTALL)).build()); + builder.addAction(new Notification.Action.Builder( + null, getString(R.string.notification_action_reboot_to_dynsystem), + createPendingIntent(ACTION_REBOOT_TO_DYN_SYSTEM)).build()); + break; case STATUS_IN_USE: diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java index c1f178a7f5f1..80d139cb6153 100644 --- a/packages/NetworkStack/src/android/net/ip/IpClient.java +++ b/packages/NetworkStack/src/android/net/ip/IpClient.java @@ -51,6 +51,7 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; @@ -298,6 +299,7 @@ public class IpClient extends StateMachine { private static final int EVENT_READ_PACKET_FILTER_COMPLETE = 12; private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13; private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14; + private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15; // Internal commands to use instead of trying to call transitionTo() inside // a given State's enter() method. Calling transitionTo() from enter/exit @@ -364,6 +366,8 @@ public class IpClient extends StateMachine { private String mTcpBufferSizes; private ProxyInfo mHttpProxy; private ApfFilter mApfFilter; + private String mL2Key; // The L2 key for this network, for writing into the memory store + private String mGroupHint; // The group hint for this network, for writing into the memory store private boolean mMulticastFiltering; private long mStartTimeMillis; @@ -524,6 +528,11 @@ public class IpClient extends StateMachine { IpClient.this.stop(); } @Override + public void setL2KeyAndGroupHint(String l2Key, String groupHint) { + checkNetworkStackCallingPermission(); + IpClient.this.setL2KeyAndGroupHint(l2Key, groupHint); + } + @Override public void setTcpBufferSizes(String tcpBufferSizes) { checkNetworkStackCallingPermission(); IpClient.this.setTcpBufferSizes(tcpBufferSizes); @@ -652,6 +661,13 @@ public class IpClient extends StateMachine { } /** + * Set the L2 key and group hint for storing info into the memory store. + */ + public void setL2KeyAndGroupHint(String l2Key, String groupHint) { + sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint)); + } + + /** * Set the HTTP Proxy configuration to use. * * This may be called, repeatedly, at any time before or after a call to @@ -1068,6 +1084,10 @@ public class IpClient extends StateMachine { return true; } final int delta = setLinkProperties(newLp); + // Most of the attributes stored in the memory store are deduced from + // the link properties, therefore when the properties update the memory + // store record should be updated too. + maybeSaveNetworkToIpMemoryStore(); if (sendCallbacks) { dispatchCallback(delta, newLp); } @@ -1083,6 +1103,7 @@ public class IpClient extends StateMachine { Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")"); } mCallback.onNewDhcpResults(dhcpResults); + maybeSaveNetworkToIpMemoryStore(); dispatchCallback(delta, newLp); } @@ -1213,6 +1234,10 @@ public class IpClient extends StateMachine { mInterfaceCtrl.clearAllAddresses(); } + private void maybeSaveNetworkToIpMemoryStore() { + // TODO : implement this + } + class StoppedState extends State { @Override public void enter() { @@ -1258,6 +1283,13 @@ public class IpClient extends StateMachine { handleLinkPropertiesUpdate(NO_CALLBACKS); break; + case CMD_UPDATE_L2KEY_GROUPHINT: { + final Pair<String, String> args = (Pair<String, String>) msg.obj; + mL2Key = args.first; + mGroupHint = args.second; + break; + } + case CMD_SET_MULTICAST_FILTER: mMulticastFiltering = (boolean) msg.obj; break; @@ -1357,6 +1389,20 @@ public class IpClient extends StateMachine { } break; + case CMD_UPDATE_L2KEY_GROUPHINT: { + final Pair<String, String> args = (Pair<String, String>) msg.obj; + mL2Key = args.first; + mGroupHint = args.second; + // TODO : attributes should be saved to the memory store with + // these new values if they differ from the previous ones. + // If the state machine is in pure StartedState, then the values to input + // are not known yet and should be updated when the LinkProperties are updated. + // If the state machine is in RunningState (which is a child of StartedState) + // then the next NUD check should be used to store the new values to avoid + // inputting current values for what may be a different L3 network. + break; + } + case EVENT_PROVISIONING_TIMEOUT: handleProvisioningFailure(); break; diff --git a/packages/NetworkStack/src/android/net/util/DataStallUtils.java b/packages/NetworkStack/src/android/net/util/DataStallUtils.java new file mode 100644 index 000000000000..b6dbeb19ad1d --- /dev/null +++ b/packages/NetworkStack/src/android/net/util/DataStallUtils.java @@ -0,0 +1,72 @@ +/* + * 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.net.util; + +/** + * Collection of utilities for data stall. + */ +public class DataStallUtils { + /** + * Detect data stall via using dns timeout counts. + */ + public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; + // Default configuration values for data stall detection. + public static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5; + public static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000; + public static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000; + /** + * The threshold value for the number of consecutive dns timeout events received to be a + * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this + * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note + * that the value should be {@code > 0} if the DNS data stall detection is enabled. + * + */ + public static final String CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = + "data_stall_consecutive_dns_timeout_threshold"; + + /** + * The minimal time interval in milliseconds for data stall reevaluation. + * + */ + public static final String CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL = + "data_stall_min_evaluate_interval"; + + /** + * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting + * a data stall. + * + */ + public static final String CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD = + "data_stall_valid_dns_time_threshold"; + + /** + * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing + * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values. + * + * Type: int + * Valid values: + * {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal. + */ + public static final String CONFIG_DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type"; + public static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = DATA_STALL_EVALUATION_TYPE_DNS; + // The default number of DNS events kept of the log kept for dns signal evaluation. Each event + // is represented by a {@link com.android.server.connectivity.NetworkMonitor#DnsResult} objects. + // It's also the size of array of {@link com.android.server.connectivity.nano.DnsEvent} kept in + // metrics. Note that increasing the size may cause statsd log buffer bust. Need to check the + // design in statsd when you try to increase the size. + public static final int DEFAULT_DNS_LOG_SIZE = 20; +} diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java index dada61ce9618..e7a607b1f921 100644 --- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java +++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java @@ -32,6 +32,9 @@ import java.util.function.Predicate; * Collection of utilities for the network stack. */ public class NetworkStackUtils { + // TODO: Refer to DeviceConfig definition. + public static final String NAMESPACE_CONNECTIVITY = "connectivity"; + static { System.loadLibrary("networkstackutilsjni"); } @@ -104,6 +107,24 @@ public class NetworkStackUtils { } /** + * Look up the value of a property for a particular namespace from {@link DeviceConfig}. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultValue The value to return if the property does not exist or has no non-null + * value. + * @return the corresponding value, or defaultValue if none exists. + */ + public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name, + int defaultValue) { + String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */); + try { + return (value != null) ? Integer.parseInt(value) : defaultValue; + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** * Attaches a socket filter that accepts DHCP packets to the given socket. */ public static native void attachDhcpFilter(FileDescriptor fd) throws SocketException; diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 8f7d98876e4c..7b77d66ca01f 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -32,8 +32,18 @@ import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE; import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS; import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK; import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD; +import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS; +import static android.net.util.DataStallUtils.DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD; +import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_EVALUATION_TYPES; +import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS; +import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS; +import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE; +import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY; import static android.net.util.NetworkStackUtils.isEmpty; -import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS; import android.annotation.NonNull; import android.annotation.Nullable; @@ -60,6 +70,7 @@ import android.net.metrics.NetworkEvent; import android.net.metrics.ValidationProbeEvent; import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; +import android.net.util.NetworkStackUtils; import android.net.util.SharedLog; import android.net.util.Stopwatch; import android.net.wifi.WifiInfo; @@ -126,18 +137,6 @@ public class NetworkMonitor extends StateMachine { private static final int SOCKET_TIMEOUT_MS = 10000; private static final int PROBE_TIMEOUT_MS = 3000; - - // Default configuration values for data stall detection. - private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5; - private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000; - private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000; - - private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = - DATA_STALL_EVALUATION_TYPE_DNS; - // Reevaluate it as intending to increase the number. Larger log size may cause statsd - // log buffer bust and have stats log lost. - private static final int DEFAULT_DNS_LOG_SIZE = 20; - enum EvaluationResult { VALIDATED(true), CAPTIVE_PORTAL(false); @@ -388,7 +387,7 @@ public class NetworkMonitor extends StateMachine { mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold); mDataStallMinEvaluateTime = getDataStallMinEvaluateTime(); mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold(); - mDataStallEvaluationType = getDataStallEvalutionType(); + mDataStallEvaluationType = getDataStallEvaluationType(); // Provide empty LinkProperties and NetworkCapabilities to make sure they are never null, // even before notifyNetworkConnected. @@ -542,10 +541,6 @@ public class NetworkMonitor extends StateMachine { return HANDLED; case CMD_NETWORK_DISCONNECTED: logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED); - if (mLaunchCaptivePortalAppBroadcastReceiver != null) { - mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver); - mLaunchCaptivePortalAppBroadcastReceiver = null; - } quit(); return HANDLED; case CMD_FORCE_REEVALUATION: @@ -779,7 +774,10 @@ public class NetworkMonitor extends StateMachine { @Override public void exit() { - mLaunchCaptivePortalAppBroadcastReceiver = null; + if (mLaunchCaptivePortalAppBroadcastReceiver != null) { + mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver); + mLaunchCaptivePortalAppBroadcastReceiver = null; + } hideProvisioningNotification(); } } @@ -1185,25 +1183,26 @@ public class NetworkMonitor extends StateMachine { } private int getConsecutiveDnsTimeoutThreshold() { - return mDependencies.getSetting(mContext, - Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD, + return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, + CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD, DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD); } private int getDataStallMinEvaluateTime() { - return mDependencies.getSetting(mContext, - Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL, + return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, + CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL, DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS); } private int getDataStallValidDnsTimeThreshold() { - return mDependencies.getSetting(mContext, - Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD, + return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, + CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD, DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS); } - private int getDataStallEvalutionType() { - return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE, + private int getDataStallEvaluationType() { + return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, + CONFIG_DATA_STALL_EVALUATION_TYPE, DEFAULT_DATA_STALL_EVALUATION_TYPES); } @@ -1726,6 +1725,33 @@ public class NetworkMonitor extends StateMachine { return value != null ? value : defaultValue; } + /** + * Look up the value of a property in DeviceConfig. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultValue The value to return if the property does not exist or has no non-null + * value. + * @return the corresponding value, or defaultValue if none exists. + */ + @Nullable + public String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name, + @Nullable String defaultValue) { + return NetworkStackUtils.getDeviceConfigProperty(namespace, name, defaultValue); + } + + /** + * Look up the value of a property in DeviceConfig. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultValue The value to return if the property does not exist or has no non-null + * value. + * @return the corresponding value, or defaultValue if none exists. + */ + public int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name, + int defaultValue) { + return NetworkStackUtils.getDeviceConfigPropertyInt(namespace, name, defaultValue); + } + public static final Dependencies DEFAULT = new Dependencies(); } diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java index eee12d6f8c7c..5f8000634ffa 100644 --- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java +++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.AlarmManager; @@ -40,7 +41,9 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; +import android.net.NetworkStackIpMemoryStore; import android.net.RouteInfo; +import android.net.ipmemorystore.NetworkAttributes; import android.net.shared.InitialConfiguration; import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; @@ -81,6 +84,8 @@ public class IpClientTest { // See RFC 7042#section-2.1.2 for EUI-48 documentation values. private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01"); private static final int TEST_TIMEOUT_MS = 400; + private static final String TEST_L2KEY = "some l2key"; + private static final String TEST_GROUPHINT = "some grouphint"; @Mock private Context mContext; @Mock private ConnectivityManager mCm; @@ -92,6 +97,7 @@ public class IpClientTest { @Mock private IpClient.Dependencies mDependencies; @Mock private ContentResolver mContentResolver; @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager; + @Mock private NetworkStackIpMemoryStore mIpMemoryStore; private NetworkObserver mObserver; private InterfaceParams mIfParams; @@ -141,6 +147,12 @@ public class IpClientTest { return empty; } + private void verifyNetworkAttributesStored(final String l2Key, + final NetworkAttributes attributes) { + // TODO : when storing is implemented, turn this on + // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any()); + } + @Test public void testNullInterfaceNameMostDefinitelyThrows() throws Exception { setTestInterfaceParams(null); @@ -173,6 +185,7 @@ public class IpClientTest { setTestInterfaceParams(TEST_IFNAME); final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry, mNetworkStackServiceManager, mDependencies); + verifyNoMoreInteractions(mIpMemoryStore); ipc.shutdown(); } @@ -183,6 +196,7 @@ public class IpClientTest { mNetworkStackServiceManager, mDependencies); ipc.startProvisioning(new ProvisioningConfiguration()); verify(mCb, times(1)).onProvisioningFailure(any()); + verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any()); ipc.shutdown(); } @@ -202,6 +216,7 @@ public class IpClientTest { verify(mCb, times(1)).setNeighborDiscoveryOffload(true); verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false); verify(mCb, never()).onProvisioningFailure(any()); + verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any()); ipc.shutdown(); verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false); @@ -214,6 +229,8 @@ public class IpClientTest { public void testProvisioningWithInitialConfiguration() throws Exception { final String iface = TEST_IFNAME; final IpClient ipc = makeIpClient(iface); + final String l2Key = TEST_L2KEY; + final String groupHint = TEST_GROUPHINT; String[] addresses = { "fe80::a4be:f92:e1f7:22d1/64", @@ -232,6 +249,7 @@ public class IpClientTest { verify(mCb, times(1)).setNeighborDiscoveryOffload(true); verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false); verify(mCb, never()).onProvisioningFailure(any()); + ipc.setL2KeyAndGroupHint(l2Key, groupHint); for (String addr : addresses) { String[] parts = addr.split("/"); @@ -253,12 +271,16 @@ public class IpClientTest { LinkProperties want = linkproperties(links(addresses), routes(prefixes)); want.setInterfaceName(iface); verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want); + verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder() + .setGroupHint(groupHint) + .build()); ipc.shutdown(); verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false); verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface); verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)) .onLinkPropertiesChange(makeEmptyLinkProperties(iface)); + verifyNoMoreInteractions(mIpMemoryStore); } @Test diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index 6665aae65d90..9f6c7f89d71a 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -21,7 +21,11 @@ import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL; +import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD; +import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -114,7 +118,6 @@ public class NetworkMonitorTest { private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor; private static final int TEST_NETID = 4242; - private static final String TEST_HTTP_URL = "http://www.google.com/gen_204"; private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204"; private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204"; @@ -593,24 +596,23 @@ public class NetworkMonitorTest { } private void setDataStallEvaluationType(int type) { - when(mDependencies.getSetting(any(), - eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type); + when(mDependencies.getDeviceConfigPropertyInt(any(), + eq(CONFIG_DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type); } private void setMinDataStallEvaluateInterval(int time) { - when(mDependencies.getSetting(any(), - eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time); + when(mDependencies.getDeviceConfigPropertyInt(any(), + eq(CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time); } private void setValidDataStallDnsTimeThreshold(int time) { - when(mDependencies.getSetting(any(), - eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time); + when(mDependencies.getDeviceConfigPropertyInt(any(), + eq(CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time); } private void setConsecutiveDnsTimeoutThreshold(int num) { - when(mDependencies.getSetting(any(), - eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())) - .thenReturn(num); + when(mDependencies.getDeviceConfigPropertyInt(any(), + eq(CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())).thenReturn(num); } private void setFallbackUrl(String url) { 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/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index c6a995cb25f7..8a39b82c0bd9 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -34,6 +34,8 @@ <string name="wifi_security_short_eap" translatable="false">802.1x</string> <!-- Do not translate. Concise terminology for wifi with WPA3 security --> <string name="wifi_security_short_sae" translatable="false">WPA3</string> + <!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 transition security --> + <string name="wifi_security_short_psk_sae" translatable="false">WPA2/WPA3</string> <!-- Do not translate. Concise terminology for wifi with OWE security --> <string name="wifi_security_short_owe" translatable="false">OWE</string> <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B security --> @@ -58,6 +60,8 @@ <string name="wifi_security_passpoint" translatable="false">Passpoint</string> <!-- Do not translate. Terminology for wifi with WPA3 security --> <string name="wifi_security_sae" translatable="false">WPA3-Personal</string> + <!-- Do not translate. Terminology for wifi with WPA2/WPA3 Transition mode security --> + <string name="wifi_security_psk_sae" translatable="false">WPA2/WPA3-Personal</string> <!-- Do not translate. Terminology for wifi with OWE security --> <string name="wifi_security_owe" translatable="false">Enhanced Open</string> <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B security --> 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/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 8a88a4c64d0a..1976ec45bf45 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -184,6 +184,7 @@ public class AccessPoint implements Comparable<AccessPoint> { private static final int PSK_WPA = 1; private static final int PSK_WPA2 = 2; private static final int PSK_WPA_WPA2 = 3; + private static final int PSK_SAE = 4; /** * The number of distinct wifi levels. @@ -764,7 +765,7 @@ public class AccessPoint implements Comparable<AccessPoint> { ssid = bestResult.SSID; bssid = bestResult.BSSID; security = getSecurity(bestResult); - if (security == SECURITY_PSK) { + if (security == SECURITY_PSK || security == SECURITY_SAE) { pskType = getPskType(bestResult); } mIsCarrierAp = bestResult.isCarrierAp; @@ -826,8 +827,13 @@ public class AccessPoint implements Comparable<AccessPoint> { return concise ? context.getString(R.string.wifi_security_short_wep) : context.getString(R.string.wifi_security_wep); case SECURITY_SAE: - return concise ? context.getString(R.string.wifi_security_short_sae) : - context.getString(R.string.wifi_security_sae); + if (pskType == PSK_SAE) { + return concise ? context.getString(R.string.wifi_security_short_psk_sae) : + context.getString(R.string.wifi_security_psk_sae); + } else { + return concise ? context.getString(R.string.wifi_security_short_sae) : + context.getString(R.string.wifi_security_sae); + } case SECURITY_OWE: return concise ? context.getString(R.string.wifi_security_short_owe) : context.getString(R.string.wifi_security_owe); @@ -1460,15 +1466,22 @@ public class AccessPoint implements Comparable<AccessPoint> { private static int getPskType(ScanResult result) { boolean wpa = result.capabilities.contains("WPA-PSK"); - boolean wpa2 = result.capabilities.contains("WPA2-PSK"); - if (wpa2 && wpa) { + boolean wpa2 = result.capabilities.contains("RSN-PSK"); + boolean wpa3TransitionMode = result.capabilities.contains("PSK+SAE"); + boolean wpa3 = result.capabilities.contains("RSN-SAE"); + if (wpa3TransitionMode) { + return PSK_SAE; + } else if (wpa2 && wpa) { return PSK_WPA_WPA2; } else if (wpa2) { return PSK_WPA2; } else if (wpa) { return PSK_WPA; } else { - Log.w(TAG, "Received abnormal flag string: " + result.capabilities); + if (!wpa3) { + // Suppress warning for WPA3 only networks + Log.w(TAG, "Received abnormal flag string: " + result.capabilities); + } return PSK_UNKNOWN; } } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index d1b7c7572361..3a9a99385c28 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -194,6 +194,9 @@ <uses-permission android:name="android.permission.SET_WALLPAPER" /> <uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT" /> + <!-- Permission required to test ContentResolver caching. --> + <uses-permission android:name="android.permission.CACHE_CONTENT" /> + <application android:label="@string/app_label" android:defaultToDeviceProtectedStorage="true" android:directBootAware="true"> 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/config.xml b/packages/SystemUI/res/values/config.xml index ce04638a51e5..a067cd202247 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -316,6 +316,7 @@ <item>com.android.systemui.SliceBroadcastRelayHandler</item> <item>com.android.systemui.SizeCompatModeActivityController</item> <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> + <item>com.android.systemui.theme.ThemeOverlayController</item> </string-array> <!-- SystemUI vender service, used in config_systemUIServiceComponents. --> @@ -486,4 +487,7 @@ <integer name="ongoing_appops_dialog_max_apps">5</integer> + <!-- Launcher package name for overlaying icons. --> + <string name="launcher_overlayable_package" translatable="false">com.android.launcher3</string> + </resources> 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/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/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java index 351627980c08..23e2d277034d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java @@ -197,7 +197,7 @@ public class StatusBarWifiView extends FrameLayout implements DarkReceiver, private boolean updateState(WifiIconState state) { setContentDescription(state.contentDescription); if (mState.resId != state.resId && state.resId >= 0) { - mWifiIcon.setImageDrawable(mContext.getDrawable(mState.resId)); + mWifiIcon.setImageDrawable(mContext.getDrawable(state.resId)); } mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE); 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/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 212666f24b36..3a6756bb677f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -204,6 +204,7 @@ public class EdgeBackGestureHandler implements DisplayListener { if (!mIsEnabled) { WindowManagerWrapper.getInstance().removePinnedStackListener(mImeChangedListener); + mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this); try { WindowManagerGlobal.getWindowManagerService() @@ -215,6 +216,8 @@ public class EdgeBackGestureHandler implements DisplayListener { } else { updateDisplaySize(); + mContext.getSystemService(DisplayManager.class).registerDisplayListener(this, + mContext.getMainThreadHandler()); try { WindowManagerWrapper.getInstance().addPinnedStackListener(mImeChangedListener); @@ -344,7 +347,8 @@ public class EdgeBackGestureHandler implements DisplayListener { private void updateDisplaySize() { mContext.getSystemService(DisplayManager.class) - .getDisplay(mDisplayId).getRealSize(mDisplaySize); + .getDisplay(mDisplayId) + .getRealSize(mDisplaySize); } private void sendEvent(int action, int code) { 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 3d716a18c50a..835db6f532db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -465,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; } 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/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java new file mode 100644 index 000000000000..f318f8f94e50 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -0,0 +1,123 @@ +/* + * 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.systemui.theme; + +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.om.OverlayManager; +import android.content.pm.UserInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.systemui.Dependency; +import com.android.systemui.R; +import com.android.systemui.SystemUI; + +import com.google.android.collect.Sets; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Map; +import java.util.Set; + +/** + * Controls the application of theme overlays across the system for all users. + * This service is responsible for: + * - Observing changes to Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES and applying the + * corresponding overlays across the system + * - Observing user switches, applying the overlays for the current user to user 0 (for systemui) + * - Observing work profile changes and applying overlays from the primary user to their + * associated work profiles + */ +public class ThemeOverlayController extends SystemUI { + private static final String TAG = "ThemeOverlayController"; + private static final boolean DEBUG = false; + + private ThemeOverlayManager mThemeManager; + private UserManager mUserManager; + + @Override + public void start() { + if (DEBUG) Log.d(TAG, "Start"); + mUserManager = mContext.getSystemService(UserManager.class); + mThemeManager = new ThemeOverlayManager( + mContext.getSystemService(OverlayManager.class), + mContext.getString(R.string.launcher_overlayable_package)); + final Handler bgHandler = Dependency.get(Dependency.BG_HANDLER); + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); + mContext.registerReceiverAsUser(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added."); + updateThemeOverlays(); + } + }, UserHandle.ALL, filter, null, bgHandler); + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), + false, + new ContentObserver(bgHandler) { + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId); + if (ActivityManager.getCurrentUser() == userId) { + updateThemeOverlays(); + } + } + }, + UserHandle.USER_ALL); + } + + private void updateThemeOverlays() { + final int currentUser = ActivityManager.getCurrentUser(); + final String overlayPackageJson = Settings.Secure.getStringForUser( + mContext.getContentResolver(), Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, + currentUser); + if (DEBUG) Log.d(TAG, "updateThemeOverlays: " + overlayPackageJson); + final Map<String, String> categoryToPackage = new ArrayMap<>(); + if (!TextUtils.isEmpty(overlayPackageJson)) { + try { + JSONObject object = new JSONObject(overlayPackageJson); + for (String category : ThemeOverlayManager.THEME_CATEGORIES) { + if (object.has(category)) { + categoryToPackage.put(category, object.getString(category)); + } + } + } catch (JSONException e) { + Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e); + } + } + Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser)); + for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) { + if (userInfo.isManagedProfile()) { + userHandles.add(userInfo.getUserHandle()); + } + } + mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java new file mode 100644 index 000000000000..1a9fd5315c32 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java @@ -0,0 +1,161 @@ +/* + * 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.systemui.theme; + +import android.content.om.OverlayInfo; +import android.content.om.OverlayManager; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; + +import com.google.android.collect.Sets; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +class ThemeOverlayManager { + private static final String TAG = "ThemeOverlayManager"; + private static final boolean DEBUG = false; + + @VisibleForTesting + static final String ANDROID_PACKAGE = "android"; + @VisibleForTesting + static final String SETTINGS_PACKAGE = "com.android.settings"; + @VisibleForTesting + static final String SYSUI_PACKAGE = "com.android.systemui"; + + @VisibleForTesting + static final String OVERLAY_CATEGORY_COLOR = "android.theme.customization.accent_color"; + @VisibleForTesting + static final String OVERLAY_CATEGORY_FONT = "android.theme.customization.font"; + @VisibleForTesting + static final String OVERLAY_CATEGORY_SHAPE = + "android.theme.customization.adaptive_icon_shape"; + @VisibleForTesting + static final String OVERLAY_CATEGORY_ICON_ANDROID = + "android.theme.customization.icon_pack.android"; + @VisibleForTesting + static final String OVERLAY_CATEGORY_ICON_SYSUI = + "android.theme.customization.icon_pack.systemui"; + @VisibleForTesting + static final String OVERLAY_CATEGORY_ICON_SETTINGS = + "android.theme.customization.icon_pack.settings"; + @VisibleForTesting + static final String OVERLAY_CATEGORY_ICON_LAUNCHER = + "android.theme.customization.icon_pack.launcher"; + + /* All theme customization categories used by the system. */ + static final Set<String> THEME_CATEGORIES = Sets.newHashSet( + OVERLAY_CATEGORY_COLOR, + OVERLAY_CATEGORY_FONT, + OVERLAY_CATEGORY_SHAPE, + OVERLAY_CATEGORY_ICON_ANDROID, + OVERLAY_CATEGORY_ICON_SYSUI, + OVERLAY_CATEGORY_ICON_SETTINGS, + OVERLAY_CATEGORY_ICON_LAUNCHER); + + /* Categories that need to applied to the current user as well as the system user. */ + @VisibleForTesting + static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet( + OVERLAY_CATEGORY_COLOR, + OVERLAY_CATEGORY_FONT, + OVERLAY_CATEGORY_SHAPE, + OVERLAY_CATEGORY_ICON_ANDROID, + OVERLAY_CATEGORY_ICON_SYSUI); + + /* Allowed overlay categories for each target package. */ + private final Map<String, Set<String>> mTargetPackageToCategories = new ArrayMap<>(); + /* Target package for each overlay category. */ + private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>(); + private final OverlayManager mOverlayManager; + private final String mLauncherPackage; + + ThemeOverlayManager(OverlayManager overlayManager, String launcherPackage) { + mOverlayManager = overlayManager; + mLauncherPackage = launcherPackage; + mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet( + OVERLAY_CATEGORY_COLOR, OVERLAY_CATEGORY_FONT, + OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID)); + mTargetPackageToCategories.put(SYSUI_PACKAGE, + Sets.newHashSet(OVERLAY_CATEGORY_ICON_SYSUI)); + mTargetPackageToCategories.put(SETTINGS_PACKAGE, + Sets.newHashSet(OVERLAY_CATEGORY_ICON_SETTINGS)); + mTargetPackageToCategories.put(mLauncherPackage, + Sets.newHashSet(OVERLAY_CATEGORY_ICON_LAUNCHER)); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_COLOR, ANDROID_PACKAGE); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_FONT, ANDROID_PACKAGE); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_SHAPE, ANDROID_PACKAGE); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SYSUI, SYSUI_PACKAGE); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SETTINGS, SETTINGS_PACKAGE); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_LAUNCHER, mLauncherPackage); + } + + /** + * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that + * affect sysui will also be applied to the system user. + */ + void applyCurrentUserOverlays( + Map<String, String> categoryToPackage, Set<UserHandle> userHandles) { + final Map<Boolean, List<String>> categorySplit = THEME_CATEGORIES.stream().collect( + Collectors.partitioningBy((category) -> categoryToPackage.containsKey(category))); + final List<String> overlayCategoriesToEnable = categorySplit.get(true); + final List<String> overlayCategoriesToDisable = categorySplit.get(false); + + // Disable all overlays that have not been specified in the user setting. + final List<OverlayInfo> overlays = new ArrayList<>(); + overlayCategoriesToDisable.stream() + .map(category -> mCategoryToTargetPackage.get(category)) + .collect(Collectors.toSet()) + .forEach(targetPackage -> overlays.addAll(mOverlayManager + .getOverlayInfosForTarget(targetPackage, UserHandle.SYSTEM))); + overlays.stream() + .filter(o -> + mTargetPackageToCategories.get(o.targetPackageName).contains(o.category)) + .filter(o -> overlayCategoriesToDisable.contains(o.category)) + .filter(o -> o.isEnabled()) + .forEach(o -> setEnabled(o.packageName, o.category, userHandles, false)); + + + // Enable all overlays specified in the user setting. + overlayCategoriesToEnable.forEach((category) -> + setEnabled(categoryToPackage.get(category), category, userHandles, true)); + } + + private void setEnabled( + String packageName, String category, Set<UserHandle> handles, boolean enabled) { + for (UserHandle userHandle : handles) { + setEnabled(packageName, userHandle, enabled); + } + if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) { + setEnabled(packageName, UserHandle.SYSTEM, enabled); + } + } + + private void setEnabled(String pkg, UserHandle userHandle, boolean enabled) { + if (DEBUG) Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled)); + if (enabled) { + mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle); + } else { + mOverlayManager.setEnabled(pkg, false, userHandle); + } + } +} 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/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java new file mode 100644 index 000000000000..da039a403087 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java @@ -0,0 +1,230 @@ +/* + * 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.systemui.theme; + +import static com.android.systemui.theme.ThemeOverlayManager.ANDROID_PACKAGE; +import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_COLOR; +import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_FONT; +import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_ANDROID; +import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_LAUNCHER; +import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SETTINGS; +import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SYSUI; +import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_SHAPE; +import static com.android.systemui.theme.ThemeOverlayManager.SETTINGS_PACKAGE; +import static com.android.systemui.theme.ThemeOverlayManager.SYSTEM_USER_CATEGORIES; +import static com.android.systemui.theme.ThemeOverlayManager.SYSUI_PACKAGE; +import static com.android.systemui.theme.ThemeOverlayManager.THEME_CATEGORIES; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.om.OverlayInfo; +import android.content.om.OverlayManager; +import android.os.UserHandle; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import com.google.android.collect.Maps; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class ThemeOverlayManagerTest extends SysuiTestCase { + private static final String TEST_DISABLED_PREFIX = "com.example."; + private static final String TEST_ENABLED_PREFIX = "com.example.enabled."; + + private static final Map<String, String> ALL_CATEGORIES_MAP = Maps.newArrayMap(); + + static { + for (String category : THEME_CATEGORIES) { + ALL_CATEGORIES_MAP.put(category, TEST_DISABLED_PREFIX + category); + } + } + + private static final String LAUNCHER_PACKAGE = "com.android.launcher3"; + private static final UserHandle TEST_USER = UserHandle.of(5); + private static final Set<UserHandle> TEST_USER_HANDLES = Sets.newHashSet(TEST_USER); + + @Mock + OverlayManager mOverlayManager; + + private ThemeOverlayManager mManager; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + mManager = new ThemeOverlayManager(mOverlayManager, LAUNCHER_PACKAGE); + when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM)) + .thenReturn(Lists.newArrayList( + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_COLOR, + ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, false), + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_FONT, + ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, false), + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SHAPE, + ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, false), + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID, + ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, false), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_COLOR, + ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, true), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_FONT, + ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, true), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SHAPE, + ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, true), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID, + ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, true))); + when(mOverlayManager.getOverlayInfosForTarget(SYSUI_PACKAGE, UserHandle.SYSTEM)) + .thenReturn(Lists.newArrayList( + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_SYSUI, + SYSUI_PACKAGE, OVERLAY_CATEGORY_ICON_SYSUI, false), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SYSUI, + SYSUI_PACKAGE, OVERLAY_CATEGORY_ICON_SYSUI, true))); + when(mOverlayManager.getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM)) + .thenReturn(Lists.newArrayList( + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS, + SETTINGS_PACKAGE, OVERLAY_CATEGORY_ICON_SETTINGS, false), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS, + SETTINGS_PACKAGE, OVERLAY_CATEGORY_ICON_SETTINGS, true))); + when(mOverlayManager.getOverlayInfosForTarget(LAUNCHER_PACKAGE, UserHandle.SYSTEM)) + .thenReturn(Lists.newArrayList( + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_LAUNCHER, + LAUNCHER_PACKAGE, OVERLAY_CATEGORY_ICON_LAUNCHER, false), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_LAUNCHER, + LAUNCHER_PACKAGE, OVERLAY_CATEGORY_ICON_LAUNCHER, true))); + } + + @Test + public void allCategoriesSpecified_allEnabledExclusively() { + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES); + + for (String overlayPackage : ALL_CATEGORIES_MAP.values()) { + verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER); + } + } + + @Test + public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() { + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES); + + for (Map.Entry<String, String> entry : ALL_CATEGORIES_MAP.entrySet()) { + if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) { + verify(mOverlayManager).setEnabledExclusiveInCategory( + entry.getValue(), UserHandle.SYSTEM); + } else { + verify(mOverlayManager, never()).setEnabledExclusiveInCategory( + entry.getValue(), UserHandle.SYSTEM); + } + } + } + + @Test + public void allCategoriesSpecified_enabledForAllUserHandles() { + Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES); + UserHandle newUserHandle = UserHandle.of(10); + userHandles.add(newUserHandle); + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, userHandles); + + for (String overlayPackage : ALL_CATEGORIES_MAP.values()) { + verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER); + verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, newUserHandle); + } + } + + @Test + public void allCategoriesSpecified_overlayManagerNotQueried() { + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES); + + verify(mOverlayManager, never()) + .getOverlayInfosForTarget(anyString(), any(UserHandle.class)); + } + + @Test + public void someCategoriesSpecified_specifiedEnabled_unspecifiedDisabled() { + Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP); + categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS); + categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID); + + mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES); + + for (String overlayPackage : categoryToPackage.values()) { + verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER); + } + verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS, + false, TEST_USER); + verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID, + false, TEST_USER); + } + + @Test + public void zeroCategoriesSpecified_allDisabled() { + mManager.applyCurrentUserOverlays(Maps.newArrayMap(), TEST_USER_HANDLES); + + for (String category : THEME_CATEGORIES) { + verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + category, false, TEST_USER); + } + } + + @Test + public void nonThemeCategorySpecified_ignored() { + Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP); + categoryToPackage.put("blah.category", "com.example.blah.category"); + + mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES); + + verify(mOverlayManager, never()).setEnabled("com.example.blah.category", false, TEST_USER); + verify(mOverlayManager, never()).setEnabledExclusiveInCategory("com.example.blah.category", + TEST_USER); + } + + @Test + public void overlayManagerOnlyQueriedForUnspecifiedPackages() { + Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP); + categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS); + + mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES); + + verify(mOverlayManager).getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM); + verify(mOverlayManager, never()).getOverlayInfosForTarget(ANDROID_PACKAGE, + UserHandle.SYSTEM); + verify(mOverlayManager, never()).getOverlayInfosForTarget(SYSUI_PACKAGE, UserHandle.SYSTEM); + verify(mOverlayManager, never()).getOverlayInfosForTarget(LAUNCHER_PACKAGE, + UserHandle.SYSTEM); + } + + private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName, + String category, boolean enabled) { + return new OverlayInfo(packageName, targetPackageName, null, category, "", + enabled ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED, 0, 0, false); + } +} diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_perm_group_sms.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml index d15cfa3b1e3a..d15cfa3b1e3a 100644 --- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_perm_group_sms.xml +++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml index 87d82e58cd67..87d82e58cd67 100644 --- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml +++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml new file mode 100644 index 000000000000..4e5497a76991 --- /dev/null +++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24" + android:width="24dp" > + <path + android:fillColor="@android:color/white" + android:pathData="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10c5.52,0,10-4.48,10-10S17.52,2,12,2z M12,17v-1.5h7.74 c-0.24,0.53-0.54,1.03-0.88,1.5H12z M12,14v-1.5h8.47c-0.03,0.51-0.1,1.01-0.22,1.5H12z M12,11V9.5h8.12 c0.15,0.48,0.25,0.99,0.31,1.5H12z M12,8V6.5h6.47c0.39,0.46,0.74,0.96,1.03,1.5H12z M16.81,5H12V3.5C13.79,3.5,15.44,4.06,16.81,5 z M3.5,12c0-4.17,3.03-7.65,7-8.36v16.72C6.53,19.65,3.5,16.17,3.5,12z M12,18.5h5.47c-1.48,1.25-3.39,2-5.47,2V18.5z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_perm_group_sms.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml index eef9e62f15b0..eef9e62f15b0 100644 --- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_perm_group_sms.xml +++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml index b4baf231d1b6..b4baf231d1b6 100644 --- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml +++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml new file mode 100644 index 000000000000..6b5903c569c0 --- /dev/null +++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24" + android:width="24dp" > + <path + android:fillColor="@android:color/white" + android:pathData="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M11,19.93C7.06,19.44,4,16.08,4,12 c0-4.08,3.05-7.44,7-7.93V19.93z M13,4.07C14.03,4.2,15,4.52,15.87,5H13V4.07z M13,7h5.24c0.25,0.31,0.48,0.65,0.68,1H13V7z M13,19.93V19h2.87C15,19.48,14.03,19.8,13,19.93z M18.24,17H13v-1h5.92C18.72,16.35,18.49,16.69,18.24,17z M19.74,14H13v-1h6.93 C19.89,13.34,19.82,13.67,19.74,14z M19.93,11H13v-1h6.74C19.82,10.33,19.89,10.66,19.93,11z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_perm_group_sms.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml index b5509d12a059..b5509d12a059 100644 --- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_perm_group_sms.xml +++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml index 5f704f0ed828..5f704f0ed828 100644 --- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_24dp.xml +++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_do_not_disturb_on_24dp.xml diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml new file mode 100644 index 000000000000..308c2ab34563 --- /dev/null +++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_gray_scale_24dp.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24" + android:width="24dp" > + <path + android:fillColor="@android:color/white" + android:pathData="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10c5.52,0,10-4.48,10-10S17.52,2,12,2z M12,12.5h8.47c-0.03,0.51-0.1,1.01-0.22,1.5 H12V12.5z M12,11V9.5h8.12c0.15,0.48,0.25,0.99,0.31,1.5H12z M12,8V6.5h6.47c0.39,0.46,0.74,0.96,1.03,1.5H12z M16.81,5H12V3.5 C13.79,3.5,15.44,4.06,16.81,5z M3.5,12c0-4.17,3.03-7.65,7-8.36v16.72C6.53,19.65,3.5,16.17,3.5,12z M12,18.5h5.47 c-1.48,1.25-3.39,2-5.47,2V18.5z M18.86,17H12v-1.5h7.74C19.5,16.03,19.2,16.53,18.86,17z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml index 2e2ea085f396..2e662684438f 100644 --- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml +++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml @@ -21,5 +21,8 @@ android:width="24dp" > <path android:fillColor="@android:color/white" - android:pathData="M20.49,11.26h-1.03c-0.15-1.51-0.74-2.88-1.65-3.99l0.73-0.73c0.29-0.29,0.29-0.77,0-1.06s-0.77-0.29-1.06,0L16.75,6.2 c-1.11-0.91-2.49-1.51-4-1.66V3.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v1.04c-1.5,0.15-2.88,0.75-3.99,1.65L6.53,5.46 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L6.2,7.25c-0.91,1.11-1.51,2.49-1.66,3.99H3.51c-0.41,0-0.75,0.34-0.75,0.75 s0.34,0.75,0.75,0.75h1.03c0.15,1.51,0.74,2.88,1.65,3.99l-0.73,0.73c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22 s0.38-0.07,0.53-0.22l0.73-0.73c1.11,0.91,2.48,1.51,3.98,1.66v1.02c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-1.02 c1.48-0.14,2.86-0.71,4.01-1.65l0.73,0.73c0.15,0.15,0.34,0.22,0.53,0.22c0.19,0,0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06 l-0.72-0.72c0.94-1.14,1.51-2.52,1.66-4h1.03c0.41,0,0.75-0.34,0.75-0.75S20.9,11.26,20.49,11.26z M12,18c-3.31,0-6-2.69-6-6 s2.69-6,6-6s6,2.69,6,6S15.31,18,12,18z" /> + android:pathData="M21.25,11.25h-2.8A6.46,6.46,0,0,0,17.09,8l2-2A0.75 0.75 ,0,0,0,18,4.93l-2,2a6.46,6.46,0,0,0-3.28-1.36V2.75a0.75 0.75 ,0,0,0-1.5,0v2.8A6.46,6.46,0,0,0,8,6.91l-2-2A0.75 0.75 ,0,0,0,4.93,6l2,2a6.46,6.46,0,0,0-1.36,3.28H2.75a0.75 0.75 ,0,0,0,0,1.5h2.8A6.46,6.46,0,0,0,6.91,16l-2,2A0.75 0.75 ,0,0,0,6,19.07l2-2a6.46,6.46,0,0,0,3.28,1.36v2.8a0.75 0.75 ,0,0,0,1.5,0v-2.8A6.46,6.46,0,0,0,16,17.09l2,2A0.75 0.75 ,0,0,0,19.07,18l-2-2a6.46,6.46,0,0,0,1.36-3.28h2.8a0.75 0.75 ,0,0,0,0-1.5ZM12,17a5,5,0,1,1,5-5A5,5,0,0,1,12,17Z" /> + <path + android:fillColor="@android:color/white" + android:pathData="M12,15.5a3.5,3.5,0,0,0,0-7Z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml index 2e4665e59f1e..697d1c29eac7 100644 --- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml +++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml @@ -20,9 +20,9 @@ android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="?android:attr/colorControlActivated" - android:pathData="M22.46,11.25h-3.02c-0.15-1.51-0.75-2.88-1.66-4l2.17-2.17c0.29-0.29,0.29-0.77,0-1.06s-0.77-0.29-1.06,0l-2.18,2.18 c-1.11-0.91-2.49-1.51-3.99-1.66V1.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v3.04c-1.5,0.15-2.88,0.75-3.99,1.65 L5.06,4.01C4.77,3.71,4.29,3.71,4,4.01S3.71,4.77,4,5.07l2.18,2.18c-0.91,1.11-1.51,2.48-1.66,3.98H1.48 c-0.41,0-0.75,0.34-0.75,0.75s0.34,0.75,0.75,0.75h3.04c0.15,1.51,0.74,2.88,1.65,3.99L3.99,18.9c-0.29,0.29-0.29,0.77,0,1.06 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22l2.17-2.17c1.11,0.91,2.49,1.52,3.99,1.67v3.02c0,0.41,0.34,0.75,0.75,0.75 s0.75-0.34,0.75-0.75v-3.02c1.48-0.14,2.86-0.71,4.01-1.65l2.16,2.16c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22 c0.29-0.29,0.29-0.77,0-1.06l-2.16-2.16c0.94-1.15,1.52-2.53,1.66-4.01h3.02c0.41,0,0.75-0.34,0.75-0.75S22.88,11.25,22.46,11.25z M12,18c-3.31,0-6-2.69-6-6s2.69-6,6-6s6,2.69,6,6S15.31,18,12,18z" /> - <path android:fillColor="?android:attr/colorPrimary" - android:pathData="M 12 6 C 15.313708499 6 18 8.68629150102 18 12 C 18 15.313708499 15.313708499 18 12 18 C 8.68629150102 18 6 15.313708499 6 12 C 6 8.68629150102 8.68629150102 6 12 6 Z" /> + android:pathData="M 12 0 L 12 0 Q 24 0 24 12 L 24 12 Q 24 24 12 24 L 12 24 Q 0 24 0 12 L 0 12 Q 0 0 12 0 Z" /> + <path + android:fillColor="?android:attr/colorControlActivated" + android:pathData="M21.25,11.25h-2.8A6.46,6.46,0,0,0,17.09,8l2-2A0.75 0.75 ,0,0,0,18,4.93l-2,2a6.46,6.46,0,0,0-3.28-1.36V2.75a0.75 0.75 ,0,0,0-1.5,0v2.8A6.46,6.46,0,0,0,8,6.91l-2-2A0.75 0.75 ,0,0,0,4.93,6l2,2a6.46,6.46,0,0,0-1.36,3.28H2.75a0.75 0.75 ,0,0,0,0,1.5h2.8A6.46,6.46,0,0,0,6.91,16l-2,2A0.75 0.75 ,0,0,0,6,19.07l2-2a6.46,6.46,0,0,0,3.28,1.36v2.8a0.75 0.75 ,0,0,0,1.5,0v-2.8A6.46,6.46,0,0,0,16,17.09l2,2A0.75 0.75 ,0,0,0,19.07,18l-2-2a6.46,6.46,0,0,0,1.36-3.28h2.8a0.75 0.75 ,0,0,0,0-1.5ZM12,17a5,5,0,1,1,5-5A5,5,0,0,1,12,17Z" /> </vector>
\ No newline at end of file diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 640525411239..57de67e1a38c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -133,6 +133,7 @@ import android.os.ServiceSpecificException; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -1628,8 +1629,11 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private boolean disallowedBecauseSystemCaller() { // TODO: start throwing a SecurityException when GnssLocationProvider stops calling - // requestRouteToHost. - if (isSystem(Binder.getCallingUid())) { + // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost + // for devices launched with Q and above. However, existing devices upgrading to Q and + // above must continued to be supported for few more releases. + if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt( + "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) { log("This method exists only for app backwards compatibility" + " and must not be called by system services."); return true; @@ -1767,11 +1771,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // caller type. Need to re-factor NetdEventListenerService to allow multiple // NetworkMonitor registrants. if (nai != null && nai.satisfies(mDefaultRequest)) { - try { - nai.networkMonitor().notifyDnsResponse(returnCode); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + Binder.withCleanCallingIdentity(() -> + nai.networkMonitor().notifyDnsResponse(returnCode)); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 126bf6556538..2cfcecca5f99 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -96,9 +96,10 @@ public class IpSecService extends IIpSecService.Stub { new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms - private static final int MAX_PORT_BIND_ATTEMPTS = 10; private static final InetAddress INADDR_ANY; + @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; + static { try { INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); 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/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..3fc2d3712fed 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. diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index da1360d59539..b6946023e870 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -469,7 +469,10 @@ public class PermissionMonitor { */ @VisibleForTesting void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) { - + if (mNetd == null) { + Log.e(TAG, "Failed to get the netd service"); + return; + } ArrayList<Integer> allPermissionAppIds = new ArrayList<>(); ArrayList<Integer> internetPermissionAppIds = new ArrayList<>(); ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>(); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 3010324488b8..3abd0ba29871 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1269,21 +1269,14 @@ public final class DisplayManagerService extends SystemService { return null; } - private boolean screenshotInternal(int displayId, Surface outSurface) { + private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId) { final IBinder token = getDisplayToken(displayId); if (token == null) { - return false; + return null; } - final SurfaceControl.ScreenshotGraphicBuffer gb = - SurfaceControl.screenshotToBufferWithSecureLayersUnsafe( + return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe( token, new Rect(), 0 /* width */, 0 /* height */, false /* useIdentityTransform */, 0 /* rotation */); - try { - outSurface.attachAndQueueBuffer(gb.getGraphicBuffer()); - } catch (RuntimeException e) { - Slog.w(TAG, "Failed to take screenshot - " + e.getMessage()); - } - return true; } @VisibleForTesting @@ -2354,8 +2347,8 @@ public final class DisplayManagerService extends SystemService { } @Override - public boolean screenshot(int displayId, Surface outSurface) { - return screenshotInternal(displayId, outSurface); + public SurfaceControl.ScreenshotGraphicBuffer screenshot(int displayId) { + return screenshotInternal(displayId); } @Override 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/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 647e95284534..6f1929fd464a 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; 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/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 51bf5191247f..898437ddae41 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3051,7 +3051,7 @@ public class PackageManagerService extends IPackageManager.Stub + mSdkVersion + "; regranting permissions for internal storage"); } mPermissionManager.updateAllPermissions( - StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, false, mPackages.values(), + StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(), mPermissionCallback); ver.sdkVersion = mSdkVersion; @@ -5569,7 +5569,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mPackages) { mPermissionManager.updateAllPermissions( - StorageManager.UUID_PRIVATE_INTERNAL, false, false, mPackages.values(), + StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(), mPermissionCallback); for (int userId : UserManagerService.getInstance().getUserIds()) { final int packageCount = mPackages.size(); @@ -21222,8 +21222,8 @@ public class PackageManagerService extends IPackageManager.Stub // try optimizing this. synchronized (mPackages) { mPermissionManager.updateAllPermissions( - StorageManager.UUID_PRIVATE_INTERNAL, false, mIsPreQUpgrade, - mPackages.values(), mPermissionCallback); + StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(), + mPermissionCallback); } // Watch for external volumes that come and go over time @@ -22213,8 +22213,8 @@ public class PackageManagerService extends IPackageManager.Stub logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to " + mSdkVersion + "; regranting permissions for " + volumeUuid); } - mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, false, - mPackages.values(), mPermissionCallback); + mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, mPackages.values(), + mPermissionCallback); // Yay, everything is now upgraded ver.forceCurrent(); @@ -23247,7 +23247,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized(mPackages) { // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG mPermissionManager.updateAllPermissions( - StorageManager.UUID_PRIVATE_INTERNAL, true, false, mPackages.values(), + StorageManager.UUID_PRIVATE_INTERNAL, true, mPackages.values(), mPermissionCallback); } } @@ -24816,11 +24816,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/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 9336c55d4a79..c75a462d5bc1 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -34,10 +34,10 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQU import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; -import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL; import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER; import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM; import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE; +import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL; import static android.content.pm.PackageManager.RESTRICTED_PERMISSIONS_ENABLED; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.os.UserHandle.getAppId; @@ -69,7 +69,6 @@ import android.content.pm.PermissionInfo; import android.metrics.LogMaker; import android.os.Binder; import android.os.Build; -import android.os.Debug; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -82,7 +81,6 @@ import android.os.storage.StorageManagerInternal; import android.permission.PermissionControllerManager; import android.permission.PermissionManager; import android.permission.PermissionManagerInternal; -import android.provider.Settings; import android.permission.PermissionManagerInternal.OnRuntimePermissionStateChangedListener; import android.text.TextUtils; import android.util.ArrayMap; @@ -2458,9 +2456,8 @@ public class PermissionManagerService { } if (updatePermissions) { - // Update app permissions to take into account the new whitelist state. - updatePermissions(pkg.packageName, pkg, getVolumeUuidForPackage(pkg), - 0 /*flags*/, null /*allPackages*/, callback); + // Update permission of this app to take into account the new whitelist state. + restorePermissionState(pkg, false, pkg.packageName, callback); // If this resulted in losing a permission we need to kill the app. if (oldGrantedRestrictedPermissions != null) { @@ -2605,62 +2602,12 @@ public class PermissionManagerService { } private void updateAllPermissions(String volumeUuid, boolean sdkUpdated, - boolean updatePermissionsOnPreQUpdate, Collection<PackageParser.Package> allPackages, - PermissionCallback callback) { + Collection<PackageParser.Package> allPackages, PermissionCallback callback) { final int flags = UPDATE_PERMISSIONS_ALL | (sdkUpdated ? UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL : 0); updatePermissions(null, null, volumeUuid, flags, allPackages, callback); - - if (updatePermissionsOnPreQUpdate) { - final int[] userIds = UserManagerService.getInstance().getUserIds(); - - for (PackageParser.Package pkg : allPackages) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; - if (ps == null) { - return; - } - - final boolean appSupportsRuntimePermissions = - pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; - final PermissionsState permsState = ps.getPermissionsState(); - - for (String permName : new String[]{Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.ACCESS_BACKGROUND_LOCATION}) { - final BasePermission bp = mSettings.getPermissionLocked(permName); - - for (int userId : userIds) { - if (Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE, 0, userId) - != 0) { - continue; - } - - final PermissionState permState = permsState.getRuntimePermissionState( - permName, userId); - - if (permState != null - && (permState.getFlags() & BLOCKING_PERMISSION_FLAGS) == 0) { - if (permState.isGranted()) { - permsState.updatePermissionFlags(bp, userId, - USER_PERMISSION_FLAGS, 0); - } - - if (appSupportsRuntimePermissions) { - permsState.revokeRuntimePermission(bp, userId); - } else { - // Force a review even for apps that were already installed - permsState.updatePermissionFlags(bp, userId, - FLAG_PERMISSION_REVIEW_REQUIRED, - FLAG_PERMISSION_REVIEW_REQUIRED); - } - } - } - } - } - } } private void updatePermissions(String changingPkgName, PackageParser.Package changingPkg, @@ -3150,10 +3097,9 @@ public class PermissionManagerService { } @Override public void updateAllPermissions(String volumeUuid, boolean sdkUpdated, - boolean updatePermissionsOnPreQUpdate, Collection<PackageParser.Package> allPackages, - PermissionCallback callback) { + Collection<PackageParser.Package> allPackages, PermissionCallback callback) { PermissionManagerService.this.updateAllPermissions( - volumeUuid, sdkUpdated, updatePermissionsOnPreQUpdate, allPackages, callback); + volumeUuid, sdkUpdated, allPackages, callback); } @Override public String[] getAppOpPermissionPackages(String permName) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 34f922e11d08..9fb71f44716b 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -93,7 +93,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager @Nullable PackageParser.Package pkg, boolean replaceGrant, @NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback); public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate, - boolean updatePermissionsOnPreQUpdate, @NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback); /** 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 91ec4a083ed9..e08e1ff01348 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -863,7 +863,7 @@ final class ActivityRecord extends ConfigurationContainer { name = intent.getComponent().flattenToShortString(); } - private static ActivityRecord tokenToActivityRecordLocked(Token token) { + private static @Nullable ActivityRecord tokenToActivityRecordLocked(Token token) { if (token == null) { return null; } @@ -891,7 +891,7 @@ final class ActivityRecord extends ConfigurationContainer { } } - static ActivityRecord forTokenLocked(IBinder token) { + static @Nullable ActivityRecord forTokenLocked(IBinder token) { try { return Token.tokenToActivityRecordLocked((Token)token); } catch (ClassCastException e) { @@ -1595,8 +1595,8 @@ final class ActivityRecord extends ConfigurationContainer { try { ArrayList<ReferrerIntent> ar = new ArrayList<>(1); ar.add(rintent); - mAtmService.getLifecycleManager().scheduleTransaction( - app.getThread(), appToken, NewIntentItem.obtain(ar, mState == PAUSED)); + mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, + NewIntentItem.obtain(ar)); unsent = false; } catch (RemoteException e) { Slog.w(TAG, "Exception thrown sending new intent to " + this, e); @@ -2127,10 +2127,13 @@ final class ActivityRecord extends ConfigurationContainer { static void activityResumedLocked(IBinder token) { final ActivityRecord r = ActivityRecord.forTokenLocked(token); if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r); - if (r != null) { - r.icicle = null; - r.haveState = false; + if (r == null) { + // If an app reports resumed after a long delay, the record on server side might have + // been removed (e.g. destroy timeout), so the token could be null. + return; } + r.icicle = null; + r.haveState = false; final ActivityDisplay display = r.getDisplay(); if (display != null) { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 6bc9fc8a9f7c..fad4dbd5613b 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -1804,7 +1804,7 @@ class ActivityStack extends ConfigurationContainer { if (prev.finishing) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev); prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false, - "completedPausedLocked"); + "completePausedLocked"); } else if (prev.hasProcess()) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev + " wasStopping=" + wasStopping + " visible=" + prev.visible); @@ -2962,8 +2962,7 @@ class ActivityStack extends ConfigurationContainer { } if (next.newIntents != null) { - transaction.addCallback(NewIntentItem.obtain(next.newIntents, - false /* andPause */)); + transaction.addCallback(NewIntentItem.obtain(next.newIntents)); } // Well the app will no longer be stopped. 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/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index 2d5c97f9a3a5..b90d60227be4 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -275,7 +275,20 @@ class ScreenRotationAnimation { final int displayId = display.getDisplayId(); final Surface surface = mService.mSurfaceFactory.make(); surface.copyFrom(mSurfaceControl); - if (mService.mDisplayManagerInternal.screenshot(displayId, surface)) { + SurfaceControl.ScreenshotGraphicBuffer gb = + mService.mDisplayManagerInternal.screenshot(displayId); + if (gb != null) { + try { + surface.attachAndQueueBuffer(gb.getGraphicBuffer()); + } catch (RuntimeException e) { + Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage()); + } + // If the screenshot contains secure layers, we have to make sure the + // screenshot surface we display it in also has FLAG_SECURE so that + // the user can not screenshot secure layers via the screenshot surface. + if (gb.containsSecureLayers()) { + t.setSecure(mSurfaceControl, true); + } t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT); t.setAlpha(mSurfaceControl, 0); t.show(mSurfaceControl); diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 4a0831e39100..7714458bb167 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -104,7 +104,8 @@ class TaskPositioner { private int mMinVisibleWidth; private int mMinVisibleHeight; - private Task mTask; + @VisibleForTesting + Task mTask; private boolean mResizing; private boolean mPreserveOrientation; private boolean mStartOrientationWasLandscape; 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/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java index 57311e19bc76..d8ebd84b3e73 100644 --- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java +++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java @@ -98,14 +98,25 @@ public class WindowAnimationSpec implements AnimationSpec { tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y); t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats); t.setAlpha(leash, tmp.transformation.getAlpha()); - if (mStackClipMode == STACK_CLIP_NONE || mStackClipMode == STACK_CLIP_AFTER_ANIM) { - t.setWindowCrop(leash, tmp.transformation.getClipRect()); + + boolean cropSet = false; + if (mStackClipMode == STACK_CLIP_NONE) { + if (tmp.transformation.hasClipRect()) { + t.setWindowCrop(leash, tmp.transformation.getClipRect()); + cropSet = true; + } } else { mTmpRect.set(mStackBounds); - mTmpRect.intersect(tmp.transformation.getClipRect()); + if (tmp.transformation.hasClipRect()) { + mTmpRect.intersect(tmp.transformation.getClipRect()); + } t.setWindowCrop(leash, mTmpRect); + cropSet = true; } - if (mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) { + + // We can only apply rounded corner if a crop is set, as otherwise the value is meaningless, + // since it doesn't have anything it's relative to. + if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) { t.setCornerRadius(leash, mWindowCornerRadius); } } diff --git a/services/net/java/android/net/ip/IIpClient.aidl b/services/net/java/android/net/ip/IIpClient.aidl index b834e45c6852..1e7726472ff6 100644 --- a/services/net/java/android/net/ip/IIpClient.aidl +++ b/services/net/java/android/net/ip/IIpClient.aidl @@ -32,4 +32,5 @@ oneway interface IIpClient { void setMulticastFilter(boolean enabled); void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt); void removeKeepalivePacketFilter(int slot); + void setL2KeyAndGroupHint(in String l2Key, in String groupHint); } 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/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/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java index 2377df406fbc..9cdb465dc445 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java @@ -19,16 +19,14 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.TaskPositioner.MIN_ASPECT; import static com.android.server.wm.WindowManagerService.dipToPixel; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -39,9 +37,9 @@ import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -53,7 +51,6 @@ import org.junit.Test; */ @SmallTest @Presubmit -@FlakyTest public class TaskPositionerTests extends WindowTestsBase { private static final boolean DEBUGGING = false; @@ -66,10 +63,9 @@ public class TaskPositionerTests extends WindowTestsBase { private int mMinVisibleHeight; private TaskPositioner mPositioner; private WindowState mWindow; - private Rect mDimBounds = new Rect(); @Before - public void setUp() throws Exception { + public void setUp() { TaskPositioner.setFactory(null); final Display display = mDisplayContent.getDisplay(); @@ -84,17 +80,16 @@ public class TaskPositionerTests extends WindowTestsBase { mPositioner.register(mDisplayContent); mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); - final Task task = mWindow.getTask(); - spyOn(task); - doAnswer(invocation -> { - final Rect rect = (Rect) invocation.getArguments()[0]; - rect.set(mDimBounds); - return null; - }).when(task).getDimBounds(any(Rect.class)); - + mPositioner.mTask = mWindow.getTask(); mWindow.getStack().setWindowingMode(WINDOWING_MODE_FREEFORM); } + @After + public void tearDown() { + mWindow = null; + mPositioner = null; + } + @Test public void testOverrideFactory() { final boolean[] created = new boolean[1]; @@ -119,11 +114,11 @@ public class TaskPositionerTests extends WindowTestsBase { public void testBasicFreeWindowResizing() { final Rect r = new Rect(100, 220, 700, 520); final int midY = (r.top + r.bottom) / 2; - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); // Start a drag resize starting upper left. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); assertBoundsEquals(r, mPositioner.getWindowDragBounds()); // Drag to a good landscape size. @@ -149,8 +144,8 @@ public class TaskPositionerTests extends WindowTestsBase { mPositioner.getWindowDragBounds()); // Start a drag resize left and see that only the left coord changes.. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY); // Drag to the left. mPositioner.resizeDrag(0.0f, midY); @@ -181,77 +176,77 @@ public class TaskPositionerTests extends WindowTestsBase { final Rect r = new Rect(100, 220, 700, 520); final int midX = (r.left + r.right) / 2; final int midY = (r.top + r.bottom) / 2; - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); // Drag upper left. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); mPositioner.resizeDrag(0.0f, 0.0f); - assertTrue(r.left != mPositioner.getWindowDragBounds().left); + assertNotEquals(r.left, mPositioner.getWindowDragBounds().left); assertEquals(r.right, mPositioner.getWindowDragBounds().right); - assertTrue(r.top != mPositioner.getWindowDragBounds().top); + assertNotEquals(r.top, mPositioner.getWindowDragBounds().top); assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); // Drag upper. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, midX, r.top - MOUSE_DELTA_Y); mPositioner.resizeDrag(0.0f, 0.0f); assertEquals(r.left, mPositioner.getWindowDragBounds().left); assertEquals(r.right, mPositioner.getWindowDragBounds().right); - assertTrue(r.top != mPositioner.getWindowDragBounds().top); + assertNotEquals(r.top, mPositioner.getWindowDragBounds().top); assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); // Drag upper right. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); mPositioner.resizeDrag(r.right + 100, 0.0f); assertEquals(r.left, mPositioner.getWindowDragBounds().left); - assertTrue(r.right != mPositioner.getWindowDragBounds().right); - assertTrue(r.top != mPositioner.getWindowDragBounds().top); + assertNotEquals(r.right, mPositioner.getWindowDragBounds().right); + assertNotEquals(r.top, mPositioner.getWindowDragBounds().top); assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); // Drag right. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, midY); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.right + MOUSE_DELTA_X, midY); mPositioner.resizeDrag(r.right + 100, 0.0f); assertEquals(r.left, mPositioner.getWindowDragBounds().left); - assertTrue(r.right != mPositioner.getWindowDragBounds().right); + assertNotEquals(r.right, mPositioner.getWindowDragBounds().right); assertEquals(r.top, mPositioner.getWindowDragBounds().top); assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); // Drag bottom right. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y); mPositioner.resizeDrag(r.right + 100, r.bottom + 100); assertEquals(r.left, mPositioner.getWindowDragBounds().left); - assertTrue(r.right != mPositioner.getWindowDragBounds().right); + assertNotEquals(r.right, mPositioner.getWindowDragBounds().right); assertEquals(r.top, mPositioner.getWindowDragBounds().top); - assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom); + assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); // Drag bottom. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, midX, r.bottom + MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, midX, r.bottom + MOUSE_DELTA_Y); mPositioner.resizeDrag(r.right + 100, r.bottom + 100); assertEquals(r.left, mPositioner.getWindowDragBounds().left); assertEquals(r.right, mPositioner.getWindowDragBounds().right); assertEquals(r.top, mPositioner.getWindowDragBounds().top); - assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom); + assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); // Drag bottom left. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y); mPositioner.resizeDrag(0.0f, r.bottom + 100); - assertTrue(r.left != mPositioner.getWindowDragBounds().left); + assertNotEquals(r.left, mPositioner.getWindowDragBounds().left); assertEquals(r.right, mPositioner.getWindowDragBounds().right); assertEquals(r.top, mPositioner.getWindowDragBounds().top); - assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom); + assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); // Drag left. - mPositioner.startDrag(mWindow, true /*resizing*/, - false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midX); + mPositioner.startDrag(mWindow, true /* resizing */, + false /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY); mPositioner.resizeDrag(0.0f, r.bottom + 100); - assertTrue(r.left != mPositioner.getWindowDragBounds().left); + assertNotEquals(r.left, mPositioner.getWindowDragBounds().left); assertEquals(r.right, mPositioner.getWindowDragBounds().right); assertEquals(r.top, mPositioner.getWindowDragBounds().top); assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom); @@ -264,10 +259,10 @@ public class TaskPositionerTests extends WindowTestsBase { @Test public void testLandscapePreservedWindowResizingDragTopLeft() { final Rect r = new Rect(100, 220, 700, 520); - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); - mPositioner.startDrag(mWindow, true /*resizing*/, - true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + true /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); assertBoundsEquals(r, mPositioner.getWindowDragBounds()); // Drag to a good landscape size. @@ -303,10 +298,10 @@ public class TaskPositionerTests extends WindowTestsBase { public void testLandscapePreservedWindowResizingDragLeft() { final Rect r = new Rect(100, 220, 700, 520); final int midY = (r.top + r.bottom) / 2; - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); - mPositioner.startDrag(mWindow, true /*resizing*/, - true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY); + mPositioner.startDrag(mWindow, true /* resizing */, + true /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY); // Drag to the left. mPositioner.resizeDrag(0.0f, midY); @@ -344,7 +339,7 @@ public class TaskPositionerTests extends WindowTestsBase { public void testLandscapePreservedWindowResizingDragTop() { final Rect r = new Rect(100, 220, 700, 520); final int midX = (r.left + r.right) / 2; - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); mPositioner.startDrag(mWindow, true /*resizing*/, true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y); @@ -380,7 +375,7 @@ public class TaskPositionerTests extends WindowTestsBase { @Test public void testPortraitPreservedWindowResizingDragTopLeft() { final Rect r = new Rect(330, 100, 630, 600); - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); mPositioner.startDrag(mWindow, true /*resizing*/, true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y); @@ -414,10 +409,10 @@ public class TaskPositionerTests extends WindowTestsBase { public void testPortraitPreservedWindowResizingDragLeft() { final Rect r = new Rect(330, 100, 630, 600); final int midY = (r.top + r.bottom) / 2; - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); - mPositioner.startDrag(mWindow, true /*resizing*/, - true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY); + mPositioner.startDrag(mWindow, true /* resizing */, + true /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY); // Drag to the left. mPositioner.resizeDrag(0.0f, midY); @@ -457,10 +452,10 @@ public class TaskPositionerTests extends WindowTestsBase { public void testPortraitPreservedWindowResizingDragTop() { final Rect r = new Rect(330, 100, 630, 600); final int midX = (r.left + r.right) / 2; - mDimBounds.set(r); + mPositioner.mTask.setBounds(r, true); - mPositioner.startDrag(mWindow, true /*resizing*/, - true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y); + mPositioner.startDrag(mWindow, true /* resizing */, + true /* preserveOrientation */, midX, r.top - MOUSE_DELTA_Y); // Drag to the left (no change). mPositioner.resizeDrag(0.0f, r.top); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java index 897f0a2c6e81..0330de8d2c63 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java @@ -22,6 +22,8 @@ import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; @@ -70,7 +72,8 @@ public class WindowAnimationSpecTest { mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM, true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); - verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty)); + verify(mTransaction).setWindowCrop(eq(mSurfaceControl), + argThat(rect -> rect.equals(mStackBounds))); } @Test @@ -80,7 +83,8 @@ public class WindowAnimationSpecTest { new Point(20, 40), mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM, true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); - verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty)); + verify(mTransaction).setWindowCrop(eq(mSurfaceControl), + argThat(rect -> rect.equals(mStackBounds))); } @Test @@ -121,6 +125,17 @@ public class WindowAnimationSpecTest { } @Test + public void testApply_setCornerRadius_noClip() { + final float windowCornerRadius = 30f; + WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null, + mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE, + true /* isAppAnimation */, windowCornerRadius); + when(mAnimation.hasRoundedCorners()).thenReturn(true); + windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); + verify(mTransaction, never()).setCornerRadius(any(), anyFloat()); + } + + @Test public void testApply_clipBeforeSmallerAnimationClip() { // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 5, 5) Rect windowCrop = new Rect(0, 0, 5, 5); 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/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0f8f873b6847..970bbf89b39e 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2803,6 +2803,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; @@ -3204,6 +3217,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/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/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/tests/net/Android.bp b/tests/net/Android.bp index 70b408949dea..c8ef82ec9acc 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -4,6 +4,7 @@ java_defaults { name: "FrameworksNetTests-jni-defaults", static_libs: [ + "FrameworksNetCommonTests", "frameworks-base-testutils", "framework-protos", "androidx.test.rules", diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp new file mode 100644 index 000000000000..0a1ac75aac80 --- /dev/null +++ b/tests/net/common/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +// Tests in this folder are included both in unit tests and CTS. +// They must be fast and stable, and exercise public or test APIs. +java_library { + name: "FrameworksNetCommonTests", + srcs: ["java/**/*.java"], + static_libs: [ + "androidx.test.rules", + "junit", + ], + libs: [ + "android.test.base.stubs", + ], +}
\ No newline at end of file diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java index abf019afed44..719960d48604 100644 --- a/tests/net/java/android/net/IpPrefixTest.java +++ b/tests/net/common/java/android/net/IpPrefixTest.java @@ -39,7 +39,7 @@ import java.util.Random; @SmallTest public class IpPrefixTest { - private static InetAddress Address(String addr) { + private static InetAddress address(String addr) { return InetAddress.parseNumericAddress(addr); } @@ -58,59 +58,59 @@ public class IpPrefixTest { try { p = new IpPrefix((byte[]) null, 9); fail("Expected NullPointerException: null byte array"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix((InetAddress) null, 10); fail("Expected NullPointerException: null InetAddress"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix((String) null); fail("Expected NullPointerException: null String"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { byte[] b2 = {1, 2, 3, 4, 5}; p = new IpPrefix(b2, 29); fail("Expected IllegalArgumentException: invalid array length"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1.2.3.4"); fail("Expected IllegalArgumentException: no prefix length"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1.2.3.4/"); fail("Expected IllegalArgumentException: empty prefix length"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("foo/32"); fail("Expected IllegalArgumentException: invalid address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1/32"); fail("Expected IllegalArgumentException: deprecated IPv4 format"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1.2.3.256/32"); fail("Expected IllegalArgumentException: invalid IPv4 address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("foo/32"); fail("Expected IllegalArgumentException: non-address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("f00:::/32"); fail("Expected IllegalArgumentException: invalid IPv6 address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } } @Test @@ -132,17 +132,17 @@ public class IpPrefixTest { try { p = new IpPrefix(IPV4_BYTES, 33); fail("Expected IllegalArgumentException: invalid prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix(IPV4_BYTES, 128); fail("Expected IllegalArgumentException: invalid prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix(IPV4_BYTES, -1); fail("Expected IllegalArgumentException: negative prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } p = new IpPrefix(IPV6_BYTES, 128); assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString()); @@ -162,12 +162,12 @@ public class IpPrefixTest { try { p = new IpPrefix(IPV6_BYTES, -1); fail("Expected IllegalArgumentException: negative prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix(IPV6_BYTES, 129); fail("Expected IllegalArgumentException: negative prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } } @@ -226,28 +226,28 @@ public class IpPrefixTest { @Test public void testContainsInetAddress() { IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127"); - assertTrue(p.contains(Address("2001:db8:f00::ace:d00c"))); - assertTrue(p.contains(Address("2001:db8:f00::ace:d00d"))); - assertFalse(p.contains(Address("2001:db8:f00::ace:d00e"))); - assertFalse(p.contains(Address("2001:db8:f00::bad:d00d"))); - assertFalse(p.contains(Address("2001:4868:4860::8888"))); - assertFalse(p.contains(Address("8.8.8.8"))); + assertTrue(p.contains(address("2001:db8:f00::ace:d00c"))); + assertTrue(p.contains(address("2001:db8:f00::ace:d00d"))); + assertFalse(p.contains(address("2001:db8:f00::ace:d00e"))); + assertFalse(p.contains(address("2001:db8:f00::bad:d00d"))); + assertFalse(p.contains(address("2001:4868:4860::8888"))); + assertFalse(p.contains(address("8.8.8.8"))); p = new IpPrefix("192.0.2.0/23"); - assertTrue(p.contains(Address("192.0.2.43"))); - assertTrue(p.contains(Address("192.0.3.21"))); - assertFalse(p.contains(Address("192.0.0.21"))); - assertFalse(p.contains(Address("8.8.8.8"))); - assertFalse(p.contains(Address("2001:4868:4860::8888"))); + assertTrue(p.contains(address("192.0.2.43"))); + assertTrue(p.contains(address("192.0.3.21"))); + assertFalse(p.contains(address("192.0.0.21"))); + assertFalse(p.contains(address("8.8.8.8"))); + assertFalse(p.contains(address("2001:4868:4860::8888"))); IpPrefix ipv6Default = new IpPrefix("::/0"); - assertTrue(ipv6Default.contains(Address("2001:db8::f00"))); - assertFalse(ipv6Default.contains(Address("192.0.2.1"))); + assertTrue(ipv6Default.contains(address("2001:db8::f00"))); + assertFalse(ipv6Default.contains(address("192.0.2.1"))); IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0"); - assertTrue(ipv4Default.contains(Address("255.255.255.255"))); - assertTrue(ipv4Default.contains(Address("192.0.2.1"))); - assertFalse(ipv4Default.contains(Address("2001:db8::f00"))); + assertTrue(ipv4Default.contains(address("255.255.255.255"))); + assertTrue(ipv4Default.contains(address("192.0.2.1"))); + assertFalse(ipv4Default.contains(address("2001:db8::f00"))); } @Test @@ -315,10 +315,10 @@ public class IpPrefixTest { p = new IpPrefix(b, random.nextInt(129)); } if (p.equals(oldP)) { - assertEquals(p.hashCode(), oldP.hashCode()); + assertEquals(p.hashCode(), oldP.hashCode()); } if (p.hashCode() != oldP.hashCode()) { - assertNotEquals(p, oldP); + assertNotEquals(p, oldP); } } } @@ -332,9 +332,9 @@ public class IpPrefixTest { new IpPrefix("0.0.0.0/0"), }; for (int i = 0; i < prefixes.length; i++) { - for (int j = i + 1; j < prefixes.length; j++) { - assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode()); - } + for (int j = i + 1; j < prefixes.length; j++) { + assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode()); + } } } @@ -371,8 +371,8 @@ public class IpPrefixTest { } public void assertParcelingIsLossless(IpPrefix p) { - IpPrefix p2 = passThroughParcel(p); - assertEquals(p, p2); + IpPrefix p2 = passThroughParcel(p); + assertEquals(p, p2); } @Test diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java index b6038aba089c..2adbb06babf1 100644 --- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java +++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java @@ -45,6 +45,7 @@ import androidx.test.runner.AndroidJUnit4; import libcore.util.HexEncoding; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -189,6 +190,7 @@ public class InetDiagSocketTest { udp.close(); } + @Ignore @Test public void testGetConnectionOwnerUid() throws Exception { checkGetConnectionOwnerUid("::", null); diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java index b5c3e9287467..4a35015044ff 100644 --- a/tests/net/java/com/android/server/IpSecServiceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceTest.java @@ -156,10 +156,21 @@ public class IpSecServiceTest { @Test public void testOpenAndCloseUdpEncapsulationSocket() throws Exception { - int localport = findUnusedPort(); + int localport = -1; + IpSecUdpEncapResponse udpEncapResp = null; + + for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) { + localport = findUnusedPort(); + + udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + assertNotNull(udpEncapResp); + if (udpEncapResp.status == IpSecManager.Status.OK) { + break; + } + + // Else retry to reduce possibility for port-bind failures. + } - IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); assertEquals(localport, udpEncapResp.port); @@ -204,12 +215,11 @@ public class IpSecServiceTest { @Test public void testOpenUdpEncapsulationSocketAfterClose() throws Exception { - int localport = findUnusedPort(); IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + mIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); - assertEquals(localport, udpEncapResp.port); + int localport = udpEncapResp.port; mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId); udpEncapResp.fileDescriptor.close(); @@ -226,12 +236,11 @@ public class IpSecServiceTest { */ @Test public void testUdpEncapPortNotReleased() throws Exception { - int localport = findUnusedPort(); IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + mIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); - assertEquals(localport, udpEncapResp.port); + int localport = udpEncapResp.port; udpEncapResp.fileDescriptor.close(); @@ -273,14 +282,11 @@ public class IpSecServiceTest { @Test public void testOpenUdpEncapsulationSocketTwice() throws Exception { - int localport = findUnusedPort(); - IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + mIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); - assertEquals(localport, udpEncapResp.port); - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + int localport = udpEncapResp.port; IpSecUdpEncapResponse testUdpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index a24e0d2f93d0..c0802e60103a 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -138,17 +138,29 @@ static bool MergeEntry(IAaptContext* context, const Source& src, if (src_entry->overlayable_item) { if (dst_entry->overlayable_item) { - // Do not allow a resource with an overlayable declaration to have that overlayable - // declaration redefined - context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable_item.value().source) - << "duplicate overlayable declaration for resource '" - << src_entry->name << "'"); - context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable_item.value().source) - << "previous declaration here"); - return false; - } else { - dst_entry->overlayable_item = std::move(src_entry->overlayable_item); + CHECK(src_entry->overlayable_item.value().overlayable != nullptr); + Overlayable* src_overlayable = src_entry->overlayable_item.value().overlayable.get(); + + CHECK(dst_entry->overlayable_item.value().overlayable != nullptr); + Overlayable* dst_overlayable = dst_entry->overlayable_item.value().overlayable.get(); + + if (src_overlayable->name != dst_overlayable->name + || src_overlayable->actor != dst_overlayable->actor + || src_entry->overlayable_item.value().policies != + dst_entry->overlayable_item.value().policies) { + + // Do not allow a resource with an overlayable declaration to have that overlayable + // declaration redefined. + context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable_item.value().source) + << "duplicate overlayable declaration for resource '" + << src_entry->name << "'"); + context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable_item.value().source) + << "previous declaration here"); + return false; + } } + + dst_entry->overlayable_item = std::move(src_entry->overlayable_item); } return true; diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp index ad3674e16774..9dd31e682937 100644 --- a/tools/aapt2/link/TableMerger_test.cpp +++ b/tools/aapt2/link/TableMerger_test.cpp @@ -521,6 +521,35 @@ TEST_F(TableMergerTest, SameResourceDifferentNameFail) { .Build(); auto overlayable_second = std::make_shared<Overlayable>("ThemeResources", + "overlay://customization"); + OverlayableItem overlayable_item_second(overlayable_second); + overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; + std::unique_ptr<ResourceTable> table_b = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .SetOverlayable("bool/foo", overlayable_item_second) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = true; + TableMerger merger(context_.get(), &final_table, options); + ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); + ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); +} + +TEST_F(TableMergerTest, SameResourceDifferentActorFail) { + auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", + "overlay://customization"); + OverlayableItem overlayable_item_first(overlayable_first); + overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; + std::unique_ptr<ResourceTable> table_a = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .SetOverlayable("bool/foo", overlayable_item_first) + .Build(); + + auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources", "overlay://theme"); OverlayableItem overlayable_item_second(overlayable_second); overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; @@ -538,7 +567,36 @@ TEST_F(TableMergerTest, SameResourceDifferentNameFail) { ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); } -TEST_F(TableMergerTest, SameResourceSameNameFail) { +TEST_F(TableMergerTest, SameResourceDifferentPoliciesFail) { + auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", + "overlay://customization"); + OverlayableItem overlayable_item_first(overlayable_first); + overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; + std::unique_ptr<ResourceTable> table_a = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .SetOverlayable("bool/foo", overlayable_item_first) + .Build(); + + auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources", + "overlay://customization"); + OverlayableItem overlayable_item_second(overlayable_second); + overlayable_item_second.policies |= OverlayableItem::Policy::kSignature; + std::unique_ptr<ResourceTable> table_b = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .SetOverlayable("bool/foo", overlayable_item_second) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = true; + TableMerger merger(context_.get(), &final_table, options); + ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); + ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); +} + +TEST_F(TableMergerTest, SameResourceSameOverlayable) { auto overlayable = std::make_shared<Overlayable>("CustomizableResources", "overlay://customization"); @@ -551,7 +609,7 @@ TEST_F(TableMergerTest, SameResourceSameNameFail) { .Build(); OverlayableItem overlayable_item_second(overlayable); - overlayable_item_second.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -563,7 +621,7 @@ TEST_F(TableMergerTest, SameResourceSameNameFail) { options.auto_add_overlay = true; TableMerger merger(context_.get(), &final_table, options); ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); - ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); + ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); } } // namespace aapt |