diff options
38 files changed, 1071 insertions, 262 deletions
diff --git a/api/current.txt b/api/current.txt index a75bbfa0a800..af9f89e3d9ae 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5291,8 +5291,19 @@ package android.app { method public android.os.Bundle getExtras(); method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); + method public int getSemanticAction(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; + field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5 + field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4 + field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2 + field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3 + field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6 + field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0 + field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1 + field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9 + field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8 + field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7 field public android.app.PendingIntent actionIntent; field public deprecated int icon; field public java.lang.CharSequence title; @@ -5308,6 +5319,7 @@ package android.app { method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method public android.os.Bundle getExtras(); method public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); + method public android.app.Notification.Action.Builder setSemanticAction(int); } public static abstract interface Notification.Action.Extender { @@ -32121,6 +32133,7 @@ package android.os { } public final class PowerManager { + method public int getLocationPowerSaveMode(); method public boolean isDeviceIdleMode(); method public boolean isIgnoringBatteryOptimizations(java.lang.String); method public boolean isInteractive(); @@ -32134,6 +32147,10 @@ package android.os { field public static final java.lang.String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED"; field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED"; field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a + field public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; // 0x2 + field public static final int LOCATION_MODE_FOREGROUND_ONLY = 3; // 0x3 + field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1 + field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0 field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000 field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1 field public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // 0x20 @@ -32421,12 +32438,12 @@ package android.os { method public boolean isUserRunningOrStopping(android.os.UserHandle); method public boolean isUserUnlocked(); method public boolean isUserUnlocked(android.os.UserHandle); + method public boolean requestQuietModeEnabled(boolean, android.os.UserHandle); method public deprecated boolean setRestrictionsChallenge(java.lang.String); method public deprecated void setUserRestriction(java.lang.String, boolean); method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); method public static boolean supportsMultipleUsers(); - method public boolean trySetQuietModeEnabled(boolean, android.os.UserHandle); field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking"; field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; diff --git a/api/removed.txt b/api/removed.txt index 2aab223ed281..77088e5bdab7 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -265,6 +265,7 @@ package android.os { method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int); method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle); method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle); + method public deprecated boolean trySetQuietModeEnabled(boolean, android.os.UserHandle); } } diff --git a/api/system-current.txt b/api/system-current.txt index fbb8335b2a79..4c95beb6778a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -191,10 +191,6 @@ package android { field public static final int isVrOnly = 16844152; // 0x1010578 field public static final int requiredSystemPropertyName = 16844133; // 0x1010565 field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566 - field public static final int searchKeyphrase = 16843871; // 0x101045f - field public static final int searchKeyphraseId = 16843870; // 0x101045e - field public static final int searchKeyphraseRecognitionFlags = 16843942; // 0x10104a6 - field public static final int searchKeyphraseSupportedLocales = 16843872; // 0x1010460 } public static final class R.raw { diff --git a/api/test-current.txt b/api/test-current.txt index b16e700c4768..b15ec4a07603 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -483,6 +483,7 @@ package android.provider { } public static final class Settings.Global extends android.provider.Settings.NameValueTable { + field public static final java.lang.String LOW_POWER_MODE = "low_power"; field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package"; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index a3836048cc7d..75dc57110c93 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1268,10 +1268,67 @@ public class Notification implements Parcelable */ private static final String EXTRA_DATA_ONLY_INPUTS = "android.extra.DATA_ONLY_INPUTS"; + /** + * {@link }: No semantic action defined. + */ + public static final int SEMANTIC_ACTION_NONE = 0; + + /** + * {@code SemanticAction}: Reply to a conversation, chat, group, or wherever replies + * may be appropriate. + */ + public static final int SEMANTIC_ACTION_REPLY = 1; + + /** + * {@code SemanticAction}: Mark content as read. + */ + public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; + + /** + * {@code SemanticAction}: Mark content as unread. + */ + public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; + + /** + * {@code SemanticAction}: Delete the content associated with the notification. This + * could mean deleting an email, message, etc. + */ + public static final int SEMANTIC_ACTION_DELETE = 4; + + /** + * {@code SemanticAction}: Archive the content associated with the notification. This + * could mean archiving an email, message, etc. + */ + public static final int SEMANTIC_ACTION_ARCHIVE = 5; + + /** + * {@code SemanticAction}: Mute the content associated with the notification. This could + * mean silencing a conversation or currently playing media. + */ + public static final int SEMANTIC_ACTION_MUTE = 6; + + /** + * {@code SemanticAction}: Unmute the content associated with the notification. This could + * mean un-silencing a conversation or currently playing media. + */ + public static final int SEMANTIC_ACTION_UNMUTE = 7; + + /** + * {@code SemanticAction}: Mark content with a thumbs up. + */ + public static final int SEMANTIC_ACTION_THUMBS_UP = 8; + + /** + * {@code SemanticAction}: Mark content with a thumbs down. + */ + public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; + + private final Bundle mExtras; private Icon mIcon; private final RemoteInput[] mRemoteInputs; private boolean mAllowGeneratedReplies = true; + private final @SemanticAction int mSemanticAction; /** * Small icon representing the action. @@ -1306,6 +1363,7 @@ public class Notification implements Parcelable mExtras = Bundle.setDefusable(in.readBundle(), true); mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR); mAllowGeneratedReplies = in.readInt() == 1; + mSemanticAction = in.readInt(); } /** @@ -1313,12 +1371,14 @@ public class Notification implements Parcelable */ @Deprecated public Action(int icon, CharSequence title, PendingIntent intent) { - this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true); + this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true, + SEMANTIC_ACTION_NONE); } /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */ private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, - RemoteInput[] remoteInputs, boolean allowGeneratedReplies) { + RemoteInput[] remoteInputs, boolean allowGeneratedReplies, + @SemanticAction int semanticAction) { this.mIcon = icon; if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { this.icon = icon.getResId(); @@ -1328,6 +1388,7 @@ public class Notification implements Parcelable this.mExtras = extras != null ? extras : new Bundle(); this.mRemoteInputs = remoteInputs; this.mAllowGeneratedReplies = allowGeneratedReplies; + this.mSemanticAction = semanticAction; } /** @@ -1366,6 +1427,15 @@ public class Notification implements Parcelable } /** + * Returns the {@code SemanticAction} associated with this {@link Action}. A + * {@code SemanticAction} denotes what an {@link Action}'s {@link PendingIntent} will do + * (eg. reply, mark as read, delete, etc). + */ + public @SemanticAction int getSemanticAction() { + return mSemanticAction; + } + + /** * Get the list of inputs to be collected from the user that ONLY accept data when this * action is sent. These remote inputs are guaranteed to return true on a call to * {@link RemoteInput#isDataOnly}. @@ -1389,6 +1459,7 @@ public class Notification implements Parcelable private boolean mAllowGeneratedReplies = true; private final Bundle mExtras; private ArrayList<RemoteInput> mRemoteInputs; + private @SemanticAction int mSemanticAction; /** * Construct a new builder for {@link Action} object. @@ -1408,7 +1479,7 @@ public class Notification implements Parcelable * @param intent the {@link PendingIntent} to fire when users trigger this action */ public Builder(Icon icon, CharSequence title, PendingIntent intent) { - this(icon, title, intent, new Bundle(), null, true); + this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE); } /** @@ -1419,11 +1490,12 @@ public class Notification implements Parcelable public Builder(Action action) { this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras), action.getRemoteInputs(), - action.getAllowGeneratedReplies()); + action.getAllowGeneratedReplies(), action.getSemanticAction()); } private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, - RemoteInput[] remoteInputs, boolean allowGeneratedReplies) { + RemoteInput[] remoteInputs, boolean allowGeneratedReplies, + @SemanticAction int semanticAction) { mIcon = icon; mTitle = title; mIntent = intent; @@ -1433,6 +1505,7 @@ public class Notification implements Parcelable Collections.addAll(mRemoteInputs, remoteInputs); } mAllowGeneratedReplies = allowGeneratedReplies; + mSemanticAction = semanticAction; } /** @@ -1488,6 +1561,19 @@ public class Notification implements Parcelable } /** + * Sets the {@code SemanticAction} for this {@link Action}. A + * {@code SemanticAction} denotes what an {@link Action}'s + * {@link PendingIntent} will do (eg. reply, mark as read, delete, etc). + * @param semanticAction a SemanticAction defined within {@link Action} with + * {@code SEMANTIC_ACTION_} prefixes + * @return this object for method chaining + */ + public Builder setSemanticAction(@SemanticAction int semanticAction) { + mSemanticAction = semanticAction; + return this; + } + + /** * Apply an extender to this action builder. Extenders may be used to add * metadata or change options on this builder. */ @@ -1528,7 +1614,7 @@ public class Notification implements Parcelable RemoteInput[] textInputsArr = textInputs.isEmpty() ? null : textInputs.toArray(new RemoteInput[textInputs.size()]); return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr, - mAllowGeneratedReplies); + mAllowGeneratedReplies, mSemanticAction); } } @@ -1540,12 +1626,15 @@ public class Notification implements Parcelable actionIntent, // safe to alias mExtras == null ? new Bundle() : new Bundle(mExtras), getRemoteInputs(), - getAllowGeneratedReplies()); + getAllowGeneratedReplies(), + getSemanticAction()); } + @Override public int describeContents() { return 0; } + @Override public void writeToParcel(Parcel out, int flags) { final Icon ic = getIcon(); @@ -1565,7 +1654,9 @@ public class Notification implements Parcelable out.writeBundle(mExtras); out.writeTypedArray(mRemoteInputs, flags); out.writeInt(mAllowGeneratedReplies ? 1 : 0); + out.writeInt(mSemanticAction); } + public static final Parcelable.Creator<Action> CREATOR = new Parcelable.Creator<Action>() { public Action createFromParcel(Parcel in) { @@ -1827,6 +1918,29 @@ public class Notification implements Parcelable return (mFlags & FLAG_HINT_DISPLAY_INLINE) != 0; } } + + /** + * Provides meaning to an {@link Action} that hints at what the associated + * {@link PendingIntent} will do. For example, an {@link Action} with a + * {@link PendingIntent} that replies to a text message notification may have the + * {@link #SEMANTIC_ACTION_REPLY} {@code SemanticAction} set within it. + * + * @hide + */ + @IntDef(prefix = { "SEMANTIC_ACTION_" }, value = { + SEMANTIC_ACTION_NONE, + SEMANTIC_ACTION_REPLY, + SEMANTIC_ACTION_MARK_AS_READ, + SEMANTIC_ACTION_MARK_AS_UNREAD, + SEMANTIC_ACTION_DELETE, + SEMANTIC_ACTION_ARCHIVE, + SEMANTIC_ACTION_MUTE, + SEMANTIC_ACTION_UNMUTE, + SEMANTIC_ACTION_THUMBS_UP, + SEMANTIC_ACTION_THUMBS_DOWN + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SemanticAction {} } /** diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 01d6b022043f..65e9473380ce 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -97,7 +97,7 @@ interface IUserManager { boolean isUserRunning(int userId); boolean isUserNameSet(int userHandle); boolean hasRestrictedProfiles(); - boolean trySetQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target); + boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target); long getUserStartRealtime(); long getUserUnlockRealtime(); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index cd6d41b3f43c..3798a5ec15b5 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -565,6 +565,42 @@ public final class PowerManager { int OPTIONAL_SENSORS = 13; } + /** + * Either the location providers shouldn't be affected by battery saver, + * or battery saver is off. + */ + public static final int LOCATION_MODE_NO_CHANGE = 0; + + /** + * In this mode, the GPS based location provider should be disabled when battery saver is on and + * the device is non-interactive. + */ + public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; + + /** + * All location providers should be disabled when battery saver is on and + * the device is non-interactive. + */ + public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; + + /** + * In this mode, all the location providers will be kept available, but location fixes + * should only be provided to foreground apps. + */ + public static final int LOCATION_MODE_FOREGROUND_ONLY = 3; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"LOCATION_MODE_"}, value = { + LOCATION_MODE_NO_CHANGE, + LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF, + LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, + LOCATION_MODE_FOREGROUND_ONLY, + }) + public @interface LocationPowerSaveMode {} + final Context mContext; final IPowerManager mService; final Handler mHandler; @@ -1143,6 +1179,24 @@ public final class PowerManager { } /** + * Returns how location features should behave when battery saver is on. When battery saver + * is off, this will always return {@link #LOCATION_MODE_NO_CHANGE}. + * + * <p>This API is normally only useful for components that provide location features. + * + * @see #isPowerSaveMode() + * @see #ACTION_POWER_SAVE_MODE_CHANGED + */ + @LocationPowerSaveMode + public int getLocationPowerSaveMode() { + final PowerSaveState powerSaveState = getPowerSaveState(ServiceType.GPS); + if (!powerSaveState.globalBatterySaverEnabled) { + return LOCATION_MODE_NO_CHANGE; + } + return powerSaveState.gpsMode; + } + + /** * Returns true if the device is currently in idle mode. This happens when a device * has been sitting unused and unmoving for a sufficiently long period of time, so that * it decides to go into a lower power-use state. This may involve things like turning diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 4e94c321e0a5..9ececa6be2a2 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -2209,6 +2209,12 @@ public class UserManager { } } + /** @removed */ + @Deprecated + public boolean trySetQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) { + return requestQuietModeEnabled(enableQuietMode, userHandle); + } + /** * Enables or disables quiet mode for a managed profile. If quiet mode is enabled, apps in a * managed profile don't run, generate notifications, or consume data or battery. @@ -2234,22 +2240,22 @@ public class UserManager { * * @see #isQuietModeEnabled(UserHandle) */ - public boolean trySetQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) { - return trySetQuietModeEnabled(enableQuietMode, userHandle, null); + public boolean requestQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) { + return requestQuietModeEnabled(enableQuietMode, userHandle, null); } /** - * Similar to {@link #trySetQuietModeEnabled(boolean, UserHandle)}, except you can specify + * Similar to {@link #requestQuietModeEnabled(boolean, UserHandle)}, except you can specify * a target to start when user is unlocked. If {@code target} is specified, caller must have * the {@link android.Manifest.permission#MANAGE_USERS} permission. * - * @see {@link #trySetQuietModeEnabled(boolean, UserHandle)} + * @see {@link #requestQuietModeEnabled(boolean, UserHandle)} * @hide */ - public boolean trySetQuietModeEnabled( + public boolean requestQuietModeEnabled( boolean enableQuietMode, @NonNull UserHandle userHandle, IntentSender target) { try { - return mService.trySetQuietModeEnabled( + return mService.requestQuietModeEnabled( mContext.getPackageName(), enableQuietMode, userHandle.getIdentifier(), target); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index db32144b9c45..dc9c85781873 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10058,6 +10058,7 @@ public final class Settings { * If 1 low power mode is enabled. * @hide */ + @TestApi public static final String LOW_POWER_MODE = "low_power"; /** diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index 70de9ee49d94..c568b6fbe0c4 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -106,9 +106,12 @@ public class VoicemailContract { /** * Broadcast intent to inform a new visual voicemail SMS has been received. This intent will - * only be delivered to the telephony service. {@link #EXTRA_VOICEMAIL_SMS} will be included. - */ - /** @hide */ + * only be delivered to the telephony service. + * + * @see #EXTRA_VOICEMAIL_SMS + * @see #EXTRA_TARGET_PACKAGE + * + * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_VOICEMAIL_SMS_RECEIVED = "com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED"; @@ -121,6 +124,19 @@ public class VoicemailContract { public static final String EXTRA_VOICEMAIL_SMS = "android.provider.extra.VOICEMAIL_SMS"; /** + * Extra in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} indicating the target package to bind {@link + * android.telephony.VisualVoicemailService}. + * + * <p>This extra should be set to android.telephony.VisualVoicemailSmsFilterSettings#packageName + * while performing filtering. Since the default dialer might change between the filter sending + * it and telephony binding to the service, this ensures the service will not receive SMS + * filtered by the previous app. + * + * @hide + */ + public static final String EXTRA_TARGET_PACKAGE = "android.provider.extra.TARGET_PACAKGE"; + + /** * Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the * receiving package made this change. */ diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java index 2eadaf3a06b0..902c8c1662ea 100644 --- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java +++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java @@ -111,7 +111,7 @@ public class UnlaunchableAppActivity extends Activity @Override public void onClick(DialogInterface dialog, int which) { if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) { - UserManager.get(this).trySetQuietModeEnabled(false, UserHandle.of(mUserId), mTarget); + UserManager.get(this).requestQuietModeEnabled(false, UserHandle.of(mUserId), mTarget); } } diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp index ec03f82b17e0..a0a4be4590be 100644 --- a/core/jni/android/graphics/ImageDecoder.cpp +++ b/core/jni/android/graphics/ImageDecoder.cpp @@ -67,8 +67,8 @@ struct ImageDecoder { kOpaque = -1, }; - std::unique_ptr<SkAndroidCodec> mCodec; NinePatchPeeker mPeeker; + std::unique_ptr<SkAndroidCodec> mCodec; }; static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream) { diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 5e5d59b8aaca..0ef5445afffc 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -72,7 +72,6 @@ static struct { // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref. void DeleteScreenshot(void* addr, void* context) { - SkASSERT(addr == ((ScreenshotClient*) context)->getPixels()); delete ((ScreenshotClient*) context); } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 79c8e04caefa..addbbf5c6ce9 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7760,21 +7760,21 @@ <attr name="settingsActivity" /> </declare-styleable> - <!-- @SystemApi Use <code>trust-agent</code> as the root tag of the XML resource that + <!-- Use <code>trust-agent</code> as the root tag of the XML resource that describes an {@link android.service.trust.TrustAgentService}, which is referenced from its {@link android.service.trust.TrustAgentService#TRUST_AGENT_META_DATA} meta-data entry. Described here are the attributes that can be included in that tag. @hide --> <declare-styleable name="TrustAgent"> - <!-- @SystemApi Component name of an activity that allows the user to modify + <!-- Component name of an activity that allows the user to modify the settings for this trust agent. @hide --> <attr name="settingsActivity" /> - <!-- @SystemApi Title for a preference that allows that user to launch the + <!-- Title for a preference that allows that user to launch the activity to modify trust agent settings. @hide --> <attr name="title" /> - <!-- @SystemApi Summary for the same preference as the title. @hide --> + <!-- Summary for the same preference as the title. @hide --> <attr name="summary" /> - <!-- @SystemApi Whether trust agent can unlock a user profile @hide --> + <!-- Whether trust agent can unlock a user profile @hide --> <attr name="unlockProfile" format="boolean"/> </declare-styleable> @@ -7984,16 +7984,16 @@ by the enrollment application. Described here are the attributes that can be included in that tag. @hide - @SystemApi --> + --> <declare-styleable name="VoiceEnrollmentApplication"> - <!-- A globally unique ID for the keyphrase. @hide @SystemApi --> + <!-- A globally unique ID for the keyphrase. @hide --> <attr name="searchKeyphraseId" format="integer" /> - <!-- The actual keyphrase/hint text, or empty if not keyphrase dependent. @hide @SystemApi --> + <!-- The actual keyphrase/hint text, or empty if not keyphrase dependent. @hide --> <attr name="searchKeyphrase" format="string" /> <!-- A comma separated list of BCP-47 language tag for locales that are supported - for this keyphrase, or empty if not locale dependent. @hide @SystemApi --> + for this keyphrase, or empty if not locale dependent. @hide --> <attr name="searchKeyphraseSupportedLocales" format="string" /> - <!-- Flags for supported recognition modes. @hide @SystemApi --> + <!-- Flags for supported recognition modes. @hide --> <attr name="searchKeyphraseRecognitionFlags"> <flag name="none" value="0" /> <flag name="voiceTrigger" value="0x1" /> diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index b51c677e74ff..9ab7544618ab 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -18,11 +18,13 @@ package android.app; import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; @@ -40,6 +42,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.function.Consumer; + @RunWith(AndroidJUnit4.class) @SmallTest public class NotificationTest { @@ -281,6 +285,40 @@ public class NotificationTest { assertTrue(notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION)); } + @Test + public void action_builder_hasDefault() { + Notification.Action action = makeNotificationAction(null); + assertEquals(Notification.Action.SEMANTIC_ACTION_NONE, action.getSemanticAction()); + } + + @Test + public void action_builder_setSemanticAction() { + Notification.Action action = makeNotificationAction( + builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_REPLY)); + assertEquals(Notification.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction()); + } + + @Test + public void action_parcel() { + Notification.Action action = writeAndReadParcelable( + makeNotificationAction(builder -> { + builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_ARCHIVE); + builder.setAllowGeneratedReplies(true); + })); + + assertEquals(Notification.Action.SEMANTIC_ACTION_ARCHIVE, action.getSemanticAction()); + assertTrue(action.getAllowGeneratedReplies()); + } + + @Test + public void action_clone() { + Notification.Action action = makeNotificationAction( + builder -> builder.setSemanticAction(Notification.Action.SEMANTIC_ACTION_DELETE)); + assertEquals( + Notification.Action.SEMANTIC_ACTION_DELETE, + action.clone().getSemanticAction()); + } + private Notification.Builder getMediaNotification() { MediaSession session = new MediaSession(mContext, "test"); return new Notification.Builder(mContext, "color") @@ -300,4 +338,18 @@ public class NotificationTest { p.setDataPosition(0); return p.readParcelable(/* classLoader */ null); } + + /** + * Creates a Notification.Action by mocking initial dependencies and then applying + * transformations if they're defined. + */ + private Notification.Action makeNotificationAction( + @Nullable Consumer<Notification.Action.Builder> transformation) { + Notification.Action.Builder actionBuilder = + new Notification.Action.Builder(null, "Test Title", null); + if (transformation != null) { + transformation.accept(actionBuilder); + } + return actionBuilder.build(); + } } diff --git a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h b/libs/hwui/pipeline/skia/SkiaVulkanReadback.h new file mode 100644 index 000000000000..65b89d617f7b --- /dev/null +++ b/libs/hwui/pipeline/skia/SkiaVulkanReadback.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +#include "Readback.h" + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +class SkiaVulkanReadback : public Readback { +public: + SkiaVulkanReadback(renderthread::RenderThread& thread) : Readback(thread) {} + + virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, + SkBitmap* bitmap) override { + //TODO: implement Vulkan readback. + return CopyResult::UnknownError; + } + + virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, + SkBitmap* bitmap) override { + //TODO: implement Vulkan readback. + return CopyResult::UnknownError; + } +}; + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 79dc09ffbf1d..8e0546b529af 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -24,6 +24,7 @@ #include "hwui/Bitmap.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaOpenGLReadback.h" +#include "pipeline/skia/SkiaVulkanReadback.h" #include "pipeline/skia/SkiaVulkanPipeline.h" #include "renderstate/RenderState.h" #include "renderthread/OpenGLPipeline.h" @@ -158,12 +159,11 @@ Readback& RenderThread::readback() { mReadback = new OpenGLReadbackImpl(*this); break; case RenderPipelineType::SkiaGL: - case RenderPipelineType::SkiaVulkan: - // It works to use the OpenGL pipeline for Vulkan but this is not - // ideal as it causes us to create an OpenGL context in addition - // to the Vulkan one. mReadback = new skiapipeline::SkiaOpenGLReadback(*this); break; + case RenderPipelineType::SkiaVulkan: + mReadback = new skiapipeline::SkiaVulkanReadback(*this); + break; default: LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index bd46c5f8ad0b..e49e80df7da9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -103,11 +103,12 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public Slice onBindSlice(Uri sliceUri) { - ListBuilder builder = new ListBuilder(mSliceUri) - .addRow(new RowBuilder(mDateUri).setTitle(mLastText)); + ListBuilder builder = new ListBuilder(getContext(), mSliceUri); + builder.addRow(new RowBuilder(builder, mDateUri).setTitle(mLastText)); if (!TextUtils.isEmpty(mNextAlarm)) { Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big); - builder.addRow(new RowBuilder(mAlarmUri).setTitle(mNextAlarm).addEndItem(icon)); + builder.addRow(new RowBuilder(builder, mAlarmUri) + .setTitle(mNextAlarm).addEndItem(icon)); } return builder.build(); diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index c1a36239662c..a351c09f68b7 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -131,10 +131,15 @@ public class PowerUI extends SystemUI { com.android.internal.R.integer.config_criticalBatteryWarningLevel); final ContentResolver resolver = mContext.getContentResolver(); - int defWarnLevel = mContext.getResources().getInteger( + final int defWarnLevel = mContext.getResources().getInteger( com.android.internal.R.integer.config_lowBatteryWarningLevel); - int warnLevel = Settings.Global.getInt(resolver, + final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel); + + // NOTE: Keep the logic in sync with BatteryService. + // TODO: Propagate this value from BatteryService to system UI, really. + int warnLevel = Math.min(defWarnLevel, lowPowerModeTriggerLevel); + if (warnLevel == 0) { warnLevel = defWarnLevel; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java index 7f4deb0372f5..0f8d59b12ddb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java @@ -61,7 +61,7 @@ public class ManagedProfileControllerImpl implements ManagedProfileController { public void setWorkModeEnabled(boolean enableWorkMode) { synchronized (mProfiles) { for (UserInfo ui : mProfiles) { - if (!mUserManager.trySetQuietModeEnabled(!enableWorkMode, UserHandle.of(ui.id))) { + if (!mUserManager.requestQuietModeEnabled(!enableWorkMode, UserHandle.of(ui.id))) { StatusBarManager statusBarManager = (StatusBarManager) mContext .getSystemService(android.app.Service.STATUS_BAR_SERVICE); statusBarManager.collapsePanels(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index be28569ef629..cd409d86a3dc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -33,8 +33,13 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Arrays; + import androidx.app.slice.SliceItem; +import androidx.app.slice.SliceProvider; +import androidx.app.slice.SliceSpecs; import androidx.app.slice.core.SliceQuery; +import androidx.app.slice.widget.SliceLiveData; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -47,6 +52,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { public void setup() { mProvider = new TestableKeyguardSliceProvider(); mProvider.attachInfo(getContext(), null); + SliceProvider.setSpecs(Arrays.asList(SliceSpecs.LIST)); } @Test diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index dcb0fabf0345..af0b66daad50 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -298,6 +298,8 @@ public final class BatteryService extends SystemService { final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel); + // NOTE: Keep the logic in sync with PowerUI.java in systemUI. + // TODO: Propagate this value from BatteryService to system UI, really. mLowBatteryWarningLevel = Math.min(defWarnLevel, lowPowerModeTriggerLevel); if (mLowBatteryWarningLevel == 0) { diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java index d957ca054819..40a93c1c2808 100644 --- a/services/core/java/com/android/server/content/SyncJobService.java +++ b/services/core/java/com/android/server/content/SyncJobService.java @@ -22,10 +22,12 @@ import android.content.Intent; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import android.os.SystemClock; import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; @@ -44,6 +46,9 @@ public class SyncJobService extends JobService { @GuardedBy("mLock") private final SparseBooleanArray mStartedSyncs = new SparseBooleanArray(); + @GuardedBy("mLock") + private final SparseLongArray mJobStartUptimes = new SparseLongArray(); + private final SyncLogger mLogger = SyncLogger.getInstance(); /** @@ -82,7 +87,9 @@ public class SyncJobService extends JobService { synchronized (mLock) { final int jobId = params.getJobId(); mJobParamsMap.put(jobId, params); + mStartedSyncs.delete(jobId); + mJobStartUptimes.put(jobId, SystemClock.uptimeMillis()); } Message m = Message.obtain(); m.what = SyncManager.SyncHandler.MESSAGE_START_SYNC; @@ -113,14 +120,24 @@ public class SyncJobService extends JobService { final int jobId = params.getJobId(); mJobParamsMap.remove(jobId); - if (!mStartedSyncs.get(jobId)) { - final String message = "Job " + jobId + " didn't start: params=" + - jobParametersToString(params); - mLogger.log(message); - Slog.wtf(TAG, message); + final long startUptime = mJobStartUptimes.get(jobId); + final long nowUptime = SystemClock.uptimeMillis(); + if (startUptime == 0) { + wtf("Job " + jobId + " start uptime not found: " + + " params=" + jobParametersToString(params)); + } else if ((nowUptime - startUptime) > 60 * 1000) { + // WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon. + // (1 minute threshold.) + if (!mStartedSyncs.get(jobId)) { + wtf("Job " + jobId + " didn't start: " + + " startUptime=" + startUptime + + " nowUptime=" + nowUptime + + " params=" + jobParametersToString(params)); + } } mStartedSyncs.delete(jobId); + mJobStartUptimes.delete(jobId); } Message m = Message.obtain(); m.what = SyncManager.SyncHandler.MESSAGE_STOP_SYNC; @@ -169,4 +186,9 @@ public class SyncJobService extends JobService { + SyncOperation.maybeCreateFromJobExtras(params.getExtras()); } } + + private void wtf(String message) { + mLogger.log(message); + Slog.wtf(TAG, message); + } } diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index e6de07d209a1..e158819cd89f 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -84,8 +84,6 @@ import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; -import com.android.server.power.BatterySaverPolicy; - import libcore.io.IoUtils; import java.io.File; @@ -579,7 +577,7 @@ public class GnssLocationProvider implements LocationProviderInterface { final PowerSaveState result = mPowerManager.getPowerSaveState(ServiceType.GPS); switch (result.gpsMode) { - case BatterySaverPolicy.GPS_MODE_DISABLED_WHEN_SCREEN_OFF: + case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF: // If we are in battery saver mode and the screen is off, disable GPS. disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive(); break; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 700ccad8527a..b5d284494d20 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -822,21 +822,24 @@ public class ZenModeHelper { @VisibleForTesting protected void applyRestrictions() { - final boolean zen = mZenMode != Global.ZEN_MODE_OFF; + final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + final boolean zenSilence = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; + final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS; // notification restrictions final boolean muteNotifications = (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0; // call restrictions - final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers + final boolean muteCalls = zenAlarmsOnly + || (zenPriorityOnly && !mConfig.allowCalls && !mConfig.allowRepeatCallers) || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0; // alarm restrictions - final boolean muteAlarms = zen && !mConfig.allowAlarms; + final boolean muteAlarms = zenPriorityOnly && !mConfig.allowAlarms; // alarm restrictions - final boolean muteMediaAndSystemSounds = zen && !mConfig.allowMediaSystemOther; + final boolean muteMediaAndSystemSounds = zenPriorityOnly && !mConfig.allowMediaSystemOther; // total silence restrictions - final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS - || areAllBehaviorSoundsMuted(); + final boolean muteEverything = zenSilence + || (zenPriorityOnly && areAllBehaviorSoundsMuted()); for (int usage : AudioAttributes.SDK_USAGES) { final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f7f78b9cfcfe..57c0b4a5fe88 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2697,12 +2697,6 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.getDisabledSystemPkgLPr(ps.name); if (disabledPs.codePath == null || !disabledPs.codePath.exists() || disabledPs.pkg == null) { -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Possibly deleted app: " + ps.dumpState_temp() - + "; path: " + (disabledPs.codePath == null ? "<<NULL>>":disabledPs.codePath) - + "; pkg: " + (disabledPs.pkg==null?"<<NULL>>":disabledPs.pkg.toString())); -} possiblyDeletedUpdatedSystemApps.add(ps.name); } } @@ -2754,10 +2748,6 @@ Slog.e("TODD", for (String deletedAppName : possiblyDeletedUpdatedSystemApps) { PackageParser.Package deletedPkg = mPackages.get(deletedAppName); mSettings.removeDisabledSystemPackageLPw(deletedAppName); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "remove update; name: " + deletedAppName + ", exists? " + (deletedPkg != null)); -} final String msg; if (deletedPkg == null) { // should have found an update, but, we didn't; remove everything @@ -8193,12 +8183,12 @@ Slog.e("TODD", } private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, - final @ParseFlags int parseFlags) throws PackageManagerException { + final @ParseFlags int parseFlags, boolean forceCollect) throws PackageManagerException { // When upgrading from pre-N MR1, verify the package time stamp using the package // directory and not the APK file. final long lastModifiedTime = mIsPreNMR1Upgrade ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg); - if (ps != null + if (ps != null && !forceCollect && ps.codePathString.equals(pkg.codePath) && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(pkg) @@ -8221,7 +8211,8 @@ Slog.e("TODD", Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them."); } else { - Slog.i(TAG, toString() + " changed; collecting certs"); + Slog.i(TAG, pkg.codePath + " changed; collecting certs" + + (forceCollect ? " (forced)" : "")); } try { @@ -8320,8 +8311,6 @@ Slog.e("TODD", return scannedPkg; } - // Temporary to catch potential issues with refactoring - private static boolean REFACTOR_DEBUG = true; /** * Adds a new package to the internal data structures during platform initialization. * <p>After adding, the package is known to the system and available for querying. @@ -8362,10 +8351,6 @@ Slog.e("TODD", synchronized (mPackages) { renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage); final String realPkgName = getRealPackageName(pkg, renamedPkgName); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Add pkg: " + pkg.packageName + (realPkgName==null?"":", realName: " + realPkgName)); -} if (realPkgName != null) { ensurePackageRenamed(pkg, renamedPkgName); } @@ -8380,12 +8365,6 @@ Slog.e("TODD", if (DEBUG_INSTALL && isSystemPkgUpdated) { Slog.d(TAG, "updatedPkg = " + disabledPkgSetting); } -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "SSP? " + scanSystemPartition - + ", exists? " + pkgAlreadyExists + (pkgAlreadyExists?" "+pkgSetting.toString():"") - + ", upgraded? " + isSystemPkgUpdated + (isSystemPkgUpdated?" "+disabledPkgSetting.toString():"")); -} final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null) ? mSettings.getSharedUserLPw(pkg.mSharedUserId, @@ -8397,12 +8376,6 @@ Slog.e("TODD", Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Shared UserID " + pkg.mSharedUserId - + " (uid=" + sharedUserSetting.userId + "):" - + " packages=" + sharedUserSetting.packages); -} } if (scanSystemPartition) { @@ -8411,10 +8384,6 @@ Slog.e("TODD", // version on /data, cycle through all of its children packages and // remove children that are no longer defined. if (isSystemPkgUpdated) { -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Disable child packages"); -} final int scannedChildCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; final int disabledChildCount = disabledPkgSetting.childPackageNames != null @@ -8426,19 +8395,11 @@ Slog.e("TODD", for (int j = 0; j < scannedChildCount; j++) { PackageParser.Package childPkg = pkg.childPackages.get(j); if (childPkg.packageName.equals(disabledChildPackageName)) { -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Ignore " + disabledChildPackageName); -} disabledPackageAvailable = true; break; } } if (!disabledPackageAvailable) { -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Disable " + disabledChildPackageName); -} mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName); } } @@ -8447,44 +8408,17 @@ Slog.e("TODD", disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */, null /* originalPkgSetting */, null, parseFlags, scanFlags, (pkg == mPlatformPackage), user); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Scan disabled system package"); -Slog.e("TODD", - "Pre: " + request.pkgSetting.dumpState_temp()); -} -final ScanResult result = scanPackageOnlyLI(request, mFactoryTest, -1L); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Post: " + (result.success?result.pkgSetting.dumpState_temp():"FAILED scan")); -} } } } final boolean newPkgChangedPaths = pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "paths changed? " + newPkgChangedPaths - + "; old: " + pkg.codePath - + ", new: " + (pkgSetting==null?"<<NULL>>":pkgSetting.codePathString)); -} final boolean newPkgVersionGreater = pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode; -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "version greater? " + newPkgVersionGreater - + "; old: " + pkg.getLongVersionCode() - + ", new: " + (pkgSetting==null?"<<NULL>>":pkgSetting.versionCode)); -} final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated && newPkgChangedPaths && newPkgVersionGreater; -if (REFACTOR_DEBUG) { - Slog.e("TODD", - "system better? " + isSystemPkgBetter); -} if (isSystemPkgBetter) { // The version of the application on /system is greater than the version on // /data. Switch back to the application on /system. @@ -8500,13 +8434,6 @@ if (REFACTOR_DEBUG) { + " name: " + pkgSetting.name + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "System package changed;" - + " name: " + pkgSetting.name - + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); -} final InstallArgs args = createInstallArgsForExisting( packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString, @@ -8518,10 +8445,6 @@ Slog.e("TODD", } if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) { -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "THROW exception; system pkg version not good enough"); -} // The version of the application on the /system partition is less than or // equal to the version on the /data partition. Throw an exception and use // the application already installed on the /data partition. @@ -8530,8 +8453,11 @@ Slog.e("TODD", + " better than this " + pkg.getLongVersionCode()); } - // verify certificates against what was last scanned - collectCertificatesLI(pkgSetting, pkg, parseFlags); + // Verify certificates against what was last scanned. If it is an updated priv app, we will + // force the verification. Full apk verification will happen unless apk verity is set up for + // the file. In that case, only small part of the apk is verified upfront. + collectCertificatesLI(pkgSetting, pkg, parseFlags, + PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting)); boolean shouldHideSystemApp = false; // A new application appeared on /system, but, we already have a copy of @@ -8544,11 +8470,6 @@ Slog.e("TODD", logCriticalInfo(Log.WARN, "System package signature mismatch;" + " name: " + pkgSetting.name); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "System package signature mismatch;" - + " name: " + pkgSetting.name); -} try (PackageFreezer freezer = freezePackage(pkg.packageName, "scanPackageInternalLI")) { deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null); @@ -8563,13 +8484,6 @@ Slog.e("TODD", + " name: " + pkgSetting.name + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "System package enabled;" - + " name: " + pkgSetting.name - + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); -} InstallArgs args = createInstallArgsForExisting( packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString, pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting)); @@ -8586,35 +8500,13 @@ Slog.e("TODD", + " name: " + pkgSetting.name + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode + "; new: " + pkg.codePath + " @ " + pkg.codePath); -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "System package disabled;" - + " name: " + pkgSetting.name - + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode - + "; new: " + pkg.codePath + " @ " + pkg.codePath); -} } } -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Scan package"); -Slog.e("TODD", - "Pre: " + (pkgSetting==null?"<<NONE>>":pkgSetting.dumpState_temp())); -} final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); -if (REFACTOR_DEBUG) { -pkgSetting = mSettings.getPackageLPr(pkg.packageName); -Slog.e("TODD", - "Post: " + (pkgSetting==null?"<<NONE>>":pkgSetting.dumpState_temp())); -} if (shouldHideSystemApp) { -if (REFACTOR_DEBUG) { -Slog.e("TODD", - "Disable package: " + pkg.packageName); -} synchronized (mPackages) { mSettings.disableSystemPackageLPw(pkg.packageName, true); } @@ -9835,6 +9727,7 @@ Slog.e("TODD", final @ScanFlags int scanFlags = request.scanFlags; final PackageSetting oldPkgSetting = request.oldPkgSetting; final PackageSetting originalPkgSetting = request.originalPkgSetting; + final PackageSetting disabledPkgSetting = request.disabledPkgSetting; final UserHandle user = request.user; final String realPkgName = request.realPkgName; final PackageSetting pkgSetting = result.pkgSetting; @@ -9917,7 +9810,7 @@ Slog.e("TODD", try { final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); - final boolean compatMatch = verifySignatures(signatureCheckPs, + final boolean compatMatch = verifySignatures(signatureCheckPs, disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { @@ -16687,8 +16580,9 @@ Slog.e("TODD", try { final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); + // We don't care about disabledPkgSetting on install for now. final boolean compatMatch = verifySignatures( - signatureCheckPs, pkg.mSigningDetails, compareCompat, + signatureCheckPs, null, pkg.mSigningDetails, compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index df836de21a80..7b96ca67d38f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -33,10 +33,12 @@ import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.PackageDexUsage; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppGlobals; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.os.Build; @@ -45,6 +47,7 @@ import android.os.Environment; import android.os.FileUtils; import android.os.Process; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UserHandle; import android.service.pm.PackageServiceDumpProto; import android.system.ErrnoException; @@ -547,13 +550,46 @@ public class PackageManagerServiceUtils { } /** + * Make sure the updated priv app is signed with the same key as the original APK file on the + * /system partition. + * + * <p>The rationale is that {@code disabledPkg} is a PackageSetting backed by xml files in /data + * and is not tamperproof. + */ + private static boolean matchSignatureInSystem(PackageSetting pkgSetting, + PackageSetting disabledPkgSetting) { + try { + PackageParser.collectCertificates(disabledPkgSetting.pkg, + PackageParser.PARSE_IS_SYSTEM_DIR); + if (compareSignatures(pkgSetting.signatures.mSignatures, + disabledPkgSetting.signatures.mSignatures) + != PackageManager.SIGNATURE_MATCH) { + logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " + + pkgSetting.name); + return false; + } + } catch (PackageParserException e) { + logCriticalInfo(Log.ERROR, "Failed to collect cert for " + pkgSetting.name + ": " + + e.getMessage()); + return false; + } + return true; + } + + /** Returns true to force apk verification if the updated package (in /data) is a priv app. */ + static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) { + return disabledPs != null && disabledPs.isPrivileged() && + SystemProperties.getInt("ro.apk_verity.mode", 0) != 0; + } + + /** * Verifies that signatures match. * @returns {@code true} if the compat signatures were matched; otherwise, {@code false}. * @throws PackageManagerException if the signatures did not match. */ public static boolean verifySignatures(PackageSetting pkgSetting, - PackageParser.SigningDetails parsedSignatures, boolean compareCompat, - boolean compareRecover) + PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures, + boolean compareCompat, boolean compareRecover) throws PackageManagerException { final String packageName = pkgSetting.name; boolean compatMatch = false; @@ -572,6 +608,11 @@ public class PackageManagerServiceUtils { packageName, pkgSetting.signatures.mSignatures, parsedSignatures.signatures); } + + if (!match && isApkVerificationForced(disabledPkgSetting)) { + match = matchSignatureInSystem(pkgSetting, disabledPkgSetting); + } + if (!match) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + packageName + diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 0d7ef663fa07..2b91b7d38b4f 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -97,35 +97,6 @@ public final class PackageSetting extends PackageSettingBase { + " " + name + "/" + appId + "}"; } - // Temporary to catch potential issues with refactoring - public String dumpState_temp() { - String flags = ""; - flags += ((pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ? "U" : ""); - flags += ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 ? "S" : ""); - if ("".equals(flags)) { - flags = "-"; - } - String privFlags = ""; - privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0 ? "P" : ""); - privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0 ? "O" : ""); - privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0 ? "V" : ""); - if ("".equals(privFlags)) { - privFlags = "-"; - } - return "PackageSetting{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + name + (realName == null ? "" : "("+realName+")") + "/" + appId + (sharedUser==null?"":" u:" + sharedUser.name+"("+sharedUserId+")") - + ", ver:" + versionCode - + ", path: " + codePath - + ", pABI: " + primaryCpuAbiString - + ", sABI: " + secondaryCpuAbiString - + ", oABI: " + cpuAbiOverrideString - + ", flags: " + flags - + ", privFlags: " + privFlags - + ", pkg: " + (pkg == null ? "<<NULL>>" : "{" + Integer.toHexString(System.identityHashCode(pkg)) + "}") - + "}"; - } - public void copyFrom(PackageSetting orig) { super.copyFrom(orig); doCopy(orig); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 7d575668da94..92fd9041b32d 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -394,7 +394,7 @@ public class UserManagerService extends IUserManager.Stub { /** * Start an {@link IntentSender} when user is unlocked after disabling quiet mode. * - * @see {@link #trySetQuietModeEnabled(String, boolean, int, IntentSender)} + * @see {@link #requestQuietModeEnabled(String, boolean, int, IntentSender)} */ private class DisableQuietModeUserUnlockedCallback extends IProgressListener.Stub { private final IntentSender mTarget; @@ -823,7 +823,7 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public boolean trySetQuietModeEnabled(@NonNull String callingPackage, boolean enableQuietMode, + public boolean requestQuietModeEnabled(@NonNull String callingPackage, boolean enableQuietMode, int userHandle, @Nullable IntentSender target) { Preconditions.checkNotNull(callingPackage); diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index 6f005a35a28c..a538967e501d 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -20,6 +20,7 @@ import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; import android.provider.Settings; @@ -49,21 +50,6 @@ public class BatterySaverPolicy extends ContentObserver { public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE. - /** Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode. */ - public static final int GPS_MODE_NO_CHANGE = 0; - - /** - * Value of batterySaverGpsMode such that GPS is disabled when battery saver mode - * is enabled and the screen is off. - */ - public static final int GPS_MODE_DISABLED_WHEN_SCREEN_OFF = 1; - - /** - * Value of batterySaverGpsMode such that location should be disabled altogether - * when battery saver mode is enabled and the screen is off. - */ - public static final int GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; - // Secure setting for GPS behavior when battery saver mode is on. public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode"; @@ -354,7 +340,7 @@ public class BatterySaverPolicy extends ContentObserver { // Get default value from Settings.Secure final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE, - GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode); // Non-device-specific parameters. diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java index 0af19b6f2c5d..bd8baeb8f778 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java @@ -16,11 +16,11 @@ package com.android.server.power.batterysaver; import android.content.Context; +import android.os.PowerManager; import android.provider.Settings; import android.provider.Settings.Global; import android.util.Slog; -import com.android.server.power.BatterySaverPolicy; import com.android.server.power.batterysaver.BatterySaverController.Plugin; public class BatterySaverLocationPlugin implements Plugin { @@ -53,7 +53,7 @@ public class BatterySaverLocationPlugin implements Plugin { private void updateLocationState(BatterySaverController caller) { final boolean kill = (caller.getBatterySaverPolicy().getGpsMode() - == BatterySaverPolicy.GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) && + == PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) && caller.isEnabled() && !caller.isInteractive(); if (DEBUG) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 0c7397afb879..c532a8a25bda 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -107,6 +107,68 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void testAlarmsOnly_alarmMediaMuteNotApplied() { + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS; + mZenModeHelperSpy.mConfig.allowAlarms = false; + mZenModeHelperSpy.mConfig.allowMediaSystemOther = false; + assertFalse(mZenModeHelperSpy.mConfig.allowAlarms); + assertFalse(mZenModeHelperSpy.mConfig.allowMediaSystemOther); + mZenModeHelperSpy.applyRestrictions(); + + // Alarms only mode will not silence alarms + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_ALARM); + + // Alarms only mode will not silence media + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_MEDIA); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_GAME); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_UNKNOWN); + } + + @Test + public void testAlarmsOnly_callsMuteApplied() { + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS; + mZenModeHelperSpy.mConfig.allowCalls = true; + assertTrue(mZenModeHelperSpy.mConfig.allowCalls); + mZenModeHelperSpy.applyRestrictions(); + + // Alarms only mode will silence calls despite priority-mode config + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_NOTIFICATION_RINGTONE); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); + } + + @Test + public void testAlarmsOnly_allZenConfigToggledCannotBypass_alarmMuteNotApplied() { + // Only audio attributes with SUPPRESIBLE_NEVER can bypass + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS; + mZenModeHelperSpy.mConfig.allowAlarms = false; + mZenModeHelperSpy.mConfig.allowMediaSystemOther = false; + mZenModeHelperSpy.mConfig.allowReminders = false; + mZenModeHelperSpy.mConfig.allowCalls = false; + mZenModeHelperSpy.mConfig.allowMessages = false; + mZenModeHelperSpy.mConfig.allowEvents = false; + mZenModeHelperSpy.mConfig.allowRepeatCallers= false; + assertFalse(mZenModeHelperSpy.mConfig.allowAlarms); + assertFalse(mZenModeHelperSpy.mConfig.allowMediaSystemOther); + assertFalse(mZenModeHelperSpy.mConfig.allowReminders); + assertFalse(mZenModeHelperSpy.mConfig.allowCalls); + assertFalse(mZenModeHelperSpy.mConfig.allowMessages); + assertFalse(mZenModeHelperSpy.mConfig.allowEvents); + assertFalse(mZenModeHelperSpy.mConfig.allowRepeatCallers); + mZenModeHelperSpy.applyRestrictions(); + + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_ALARM); + } + + @Test public void testZenAllCannotBypass() { // Only audio attributes with SUPPRESIBLE_NEVER can bypass mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java index 8ed96a3a4f36..7eeb1ce7991c 100644 --- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java +++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java @@ -15,12 +15,10 @@ */ package android.telephony; -import android.content.Context; import android.os.Parcel; import android.os.Parcelable; - -import android.telecom.PhoneAccountHandle; import android.telephony.VisualVoicemailService.VisualVoicemailTask; + import java.util.Collections; import java.util.List; @@ -75,6 +73,7 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { private String mClientPrefix = DEFAULT_CLIENT_PREFIX; private List<String> mOriginatingNumbers = DEFAULT_ORIGINATING_NUMBERS; private int mDestinationPort = DEFAULT_DESTINATION_PORT; + private String mPackageName; public VisualVoicemailSmsFilterSettings build() { return new VisualVoicemailSmsFilterSettings(this); @@ -116,6 +115,15 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { return this; } + /** + * The package that registered this filter. + * + * @hide + */ + public Builder setPackageName(String packageName) { + mPackageName = packageName; + return this; + } } /** @@ -138,12 +146,20 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { public final int destinationPort; /** + * The package that registered this filter. + * + * @hide + */ + public final String packageName; + + /** * Use {@link Builder} to construct */ private VisualVoicemailSmsFilterSettings(Builder builder) { clientPrefix = builder.mClientPrefix; originatingNumbers = builder.mOriginatingNumbers; destinationPort = builder.mDestinationPort; + packageName = builder.mPackageName; } public static final Creator<VisualVoicemailSmsFilterSettings> CREATOR = @@ -154,7 +170,7 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { builder.setClientPrefix(in.readString()); builder.setOriginatingNumbers(in.createStringArrayList()); builder.setDestinationPort(in.readInt()); - + builder.setPackageName(in.readString()); return builder.build(); } @@ -174,10 +190,11 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable { dest.writeString(clientPrefix); dest.writeStringList(originatingNumbers); dest.writeInt(destinationPort); + dest.writeString(packageName); } @Override - public String toString(){ + public String toString() { return "[VisualVoicemailSmsFilterSettings " + "clientPrefix=" + clientPrefix + ", originatingNumbers=" + originatingNumbers diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java new file mode 100644 index 000000000000..ef3c1ce8cf3b --- /dev/null +++ b/telephony/java/android/telephony/euicc/EuiccNotification.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2018 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.telephony.euicc; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Objects; + +/** + * This represents a signed notification which is defined in SGP.22. It can be either a profile + * installation result or a notification generated for profile operations (e.g., enabling, + * disabling, or deleting). + * + * @hide + * + * TODO(b/35851809): Make this a @SystemApi. + */ +public class EuiccNotification implements Parcelable { + /** Event */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "EVENT_" }, value = { + EVENT_INSTALL, + EVENT_ENABLE, + EVENT_DISABLE, + EVENT_DELETE + }) + public @interface Event {} + + /** A profile is downloaded and installed. */ + public static final int EVENT_INSTALL = 1; + + /** A profile is enabled. */ + public static final int EVENT_ENABLE = 1 << 1; + + /** A profile is disabled. */ + public static final int EVENT_DISABLE = 1 << 2; + + /** A profile is deleted. */ + public static final int EVENT_DELETE = 1 << 3; + + /** Value of the bits of all above events */ + @Event + public static final int ALL_EVENTS = + EVENT_INSTALL | EVENT_ENABLE | EVENT_DISABLE | EVENT_DELETE; + + private final int mSeq; + private final String mTargetAddr; + @Event private final int mEvent; + @Nullable private final byte[] mData; + + /** + * Creates an instance. + * + * @param seq The sequence number of this notification. + * @param targetAddr The target server where to send this notification. + * @param event The event which causes this notification. + * @param data The data which needs to be sent to the target server. This can be null for + * building a list of notification metadata without data. + */ + public EuiccNotification(int seq, String targetAddr, @Event int event, @Nullable byte[] data) { + mSeq = seq; + mTargetAddr = targetAddr; + mEvent = event; + mData = data; + } + + /** @return The sequence number of this notification. */ + public int getSeq() { + return mSeq; + } + + /** @return The target server address where this notification should be sent to. */ + public String getTargetAddr() { + return mTargetAddr; + } + + /** @return The event of this notification. */ + @Event + public int getEvent() { + return mEvent; + } + + /** @return The notification data which needs to be sent to the target server. */ + @Nullable + public byte[] getData() { + return mData; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EuiccNotification that = (EuiccNotification) obj; + return mSeq == that.mSeq + && Objects.equals(mTargetAddr, that.mTargetAddr) + && mEvent == that.mEvent + && Arrays.equals(mData, that.mData); + } + + @Override + public int hashCode() { + int result = 1; + result = 31 * result + mSeq; + result = 31 * result + Objects.hashCode(mTargetAddr); + result = 31 * result + mEvent; + result = 31 * result + Arrays.hashCode(mData); + return result; + } + + @Override + public String toString() { + return "EuiccNotification (seq=" + + mSeq + + ", targetAddr=" + + mTargetAddr + + ", event=" + + mEvent + + ", data=" + + (mData == null ? "null" : "byte[" + mData.length + "]") + + ")"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mSeq); + dest.writeString(mTargetAddr); + dest.writeInt(mEvent); + dest.writeByteArray(mData); + } + + private EuiccNotification(Parcel source) { + mSeq = source.readInt(); + mTargetAddr = source.readString(); + mEvent = source.readInt(); + mData = source.createByteArray(); + } + + public static final Creator<EuiccNotification> CREATOR = + new Creator<EuiccNotification>() { + @Override + public EuiccNotification createFromParcel(Parcel source) { + return new EuiccNotification(source); + } + + @Override + public EuiccNotification[] newArray(int size) { + return new EuiccNotification[size]; + } + }; +} diff --git a/telephony/java/android/telephony/euicc/EuiccRat.java b/telephony/java/android/telephony/euicc/EuiccRat.java new file mode 100644 index 000000000000..6a56503ac380 --- /dev/null +++ b/telephony/java/android/telephony/euicc/EuiccRat.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2018 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.telephony.euicc; + +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; +import android.service.carrier.CarrierIdentifier; +import android.service.euicc.EuiccProfileInfo; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/** + * This represents the RAT (Rules Authorisation Table) stored on eUICC. + * + * @hide + * + * TODO(b/35851809): Make this a @SystemApi. + */ +public final class EuiccRat implements Parcelable { + /** Profile policy rule flags */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = { + POLICY_RULE_FLAG_CONSENT_REQUIRED + }) + public @interface PolicyRuleFlag {} + + /** User consent is required to install the profile. */ + public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; + + private final int[] mPolicyRules; + private final CarrierIdentifier[][] mCarrierIds; + private final int[] mPolicyRuleFlags; + + /** This is used to build new {@link EuiccRat} instance. */ + public static final class Builder { + private int[] mPolicyRules; + private CarrierIdentifier[][] mCarrierIds; + private int[] mPolicyRuleFlags; + private int mPosition; + + /** + * Creates a new builder. + * + * @param ruleNum The number of authorisation rules in the table. + */ + public Builder(int ruleNum) { + mPolicyRules = new int[ruleNum]; + mCarrierIds = new CarrierIdentifier[ruleNum][]; + mPolicyRuleFlags = new int[ruleNum]; + } + + /** + * Builds the RAT instance. This builder should not be used anymore after this method is + * called, otherwise {@link NullPointerException} will be thrown. + */ + public EuiccRat build() { + if (mPosition != mPolicyRules.length) { + throw new IllegalStateException( + "Not enough rules are added, expected: " + + mPolicyRules.length + + ", added: " + + mPosition); + } + return new EuiccRat(mPolicyRules, mCarrierIds, mPolicyRuleFlags); + } + + /** + * Adds an authorisation rule. + * + * @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size + * this table. + */ + public Builder add(int policyRules, CarrierIdentifier[] carrierId, int policyRuleFlags) { + if (mPosition >= mPolicyRules.length) { + throw new ArrayIndexOutOfBoundsException(mPosition); + } + mPolicyRules[mPosition] = policyRules; + mCarrierIds[mPosition] = carrierId; + mPolicyRuleFlags[mPosition] = policyRuleFlags; + mPosition++; + return this; + } + } + + /** + * @param mccRule A 2-character or 3-character string which can be either MCC or MNC. The + * character 'E' is used as a wild char to match any digit. + * @param mcc A 2-character or 3-character string which can be either MCC or MNC. + * @return Whether the {@code mccRule} matches {@code mcc}. + * + * @hide + */ + @VisibleForTesting + public static boolean match(String mccRule, String mcc) { + if (mccRule.length() < mcc.length()) { + return false; + } + for (int i = 0; i < mccRule.length(); i++) { + // 'E' is the wild char to match any digit. + if (mccRule.charAt(i) == 'E' + || (i < mcc.length() && mccRule.charAt(i) == mcc.charAt(i))) { + continue; + } + return false; + } + return true; + } + + private EuiccRat(int[] policyRules, CarrierIdentifier[][] carrierIds, int[] policyRuleFlags) { + mPolicyRules = policyRules; + mCarrierIds = carrierIds; + mPolicyRuleFlags = policyRuleFlags; + } + + /** + * Finds the index of the first authorisation rule matching the given policy and carrier id. If + * the returned index is not negative, the carrier is allowed to apply this policy to its + * profile. + * + * @param policy The policy rule. + * @param carrierId The carrier id. + * @return The index of authorization rule. If no rule is found, -1 will be returned. + */ + public int findIndex(@EuiccProfileInfo.PolicyRule int policy, CarrierIdentifier carrierId) { + for (int i = 0; i < mPolicyRules.length; i++) { + if ((mPolicyRules[i] & policy) == 0) { + continue; + } + CarrierIdentifier[] carrierIds = mCarrierIds[i]; + if (carrierIds == null || carrierIds.length == 0) { + continue; + } + for (int j = 0; j < carrierIds.length; j++) { + CarrierIdentifier ruleCarrierId = carrierIds[j]; + if (!match(ruleCarrierId.getMcc(), carrierId.getMcc()) + || !match(ruleCarrierId.getMnc(), carrierId.getMnc())) { + continue; + } + String gid = ruleCarrierId.getGid1(); + if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid1())) { + continue; + } + gid = ruleCarrierId.getGid2(); + if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid2())) { + continue; + } + return i; + } + } + return -1; + } + + /** + * Tests if the entry in the table has the given policy rule flag. + * + * @param index The index of the entry. + * @param flag The policy rule flag to be tested. + * @throws ArrayIndexOutOfBoundsException If the {@code index} is negative or larger than the + * size of this table. + */ + public boolean hasPolicyRuleFlag(int index, @PolicyRuleFlag int flag) { + if (index < 0 || index >= mPolicyRules.length) { + throw new ArrayIndexOutOfBoundsException(index); + } + return (mPolicyRuleFlags[index] & flag) != 0; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeIntArray(mPolicyRules); + for (CarrierIdentifier[] ids : mCarrierIds) { + dest.writeTypedArray(ids, flags); + } + dest.writeIntArray(mPolicyRuleFlags); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EuiccRat that = (EuiccRat) obj; + if (mCarrierIds.length != that.mCarrierIds.length) { + return false; + } + for (int i = 0; i < mCarrierIds.length; i++) { + CarrierIdentifier[] carrierIds = mCarrierIds[i]; + CarrierIdentifier[] thatCarrierIds = that.mCarrierIds[i]; + if (carrierIds != null && thatCarrierIds != null) { + if (carrierIds.length != thatCarrierIds.length) { + return false; + } + for (int j = 0; j < carrierIds.length; j++) { + if (!carrierIds[j].equals(thatCarrierIds[j])) { + return false; + } + } + continue; + } else if (carrierIds == null && thatCarrierIds == null) { + continue; + } + return false; + } + + return Arrays.equals(mPolicyRules, that.mPolicyRules) + && Arrays.equals(mPolicyRuleFlags, that.mPolicyRuleFlags); + } + + private EuiccRat(Parcel source) { + mPolicyRules = source.createIntArray(); + int len = mPolicyRules.length; + mCarrierIds = new CarrierIdentifier[len][]; + for (int i = 0; i < len; i++) { + mCarrierIds[i] = source.createTypedArray(CarrierIdentifier.CREATOR); + } + mPolicyRuleFlags = source.createIntArray(); + } + + public static final Creator<EuiccRat> CREATOR = + new Creator<EuiccRat>() { + @Override + public EuiccRat createFromParcel(Parcel source) { + return new EuiccRat(source); + } + + @Override + public EuiccRat[] newArray(int size) { + return new EuiccRat[size]; + } + }; +} diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java index 489c208a0d46..693aaff8ce0f 100644 --- a/telephony/java/com/android/ims/ImsCallProfile.java +++ b/telephony/java/com/android/ims/ImsCallProfile.java @@ -351,7 +351,7 @@ public class ImsCallProfile implements Parcelable { mServiceType = in.readInt(); mCallType = in.readInt(); mCallExtras = in.readBundle(); - mMediaProfile = in.readParcelable(null); + mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader()); } public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() { diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 3bec082fc57a..101f74eafaf4 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -772,8 +772,8 @@ int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) { if (*type != ResourceType::kRaw) { if (path_data.extension == "xml") { compile_func = &CompileXml; - } else if (!options.no_png_crunch && - (path_data.extension == "png" || path_data.extension == "9.png")) { + } else if ((!options.no_png_crunch && path_data.extension == "png") || + path_data.extension == "9.png") { compile_func = &CompilePng; } } diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 421e54558df4..399b0c63e113 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -100,9 +100,11 @@ class Method(): self.typ = raw[0] self.name = raw[1] self.args = [] + self.throws = [] + target = self.args for r in raw[2:]: - if r == "throws": break - self.args.append(r) + if r == "throws": target = self.throws + else: target.append(r) # identity for compat purposes ident = self.raw @@ -391,7 +393,7 @@ def verify_actions(clazz): prefix = clazz.pkg.name + ".action" expected = prefix + "." + f.name[7:] if f.value != expected: - error(clazz, f, "C4", "Inconsistent action value; expected %s" % (expected)) + error(clazz, f, "C4", "Inconsistent action value; expected '%s'" % (expected)) def verify_extras(clazz): @@ -421,7 +423,7 @@ def verify_extras(clazz): prefix = clazz.pkg.name + ".extra" expected = prefix + "." + f.name[6:] if f.value != expected: - error(clazz, f, "C4", "Inconsistent extra value; expected %s" % (expected)) + error(clazz, f, "C4", "Inconsistent extra value; expected '%s'" % (expected)) def verify_equals(clazz): @@ -450,6 +452,10 @@ def verify_parcelable(clazz): (" final deprecated class " not in clazz.raw)): error(clazz, None, "FW8", "Parcelable classes must be final") + for c in clazz.ctors: + if c.args == ["android.os.Parcel"]: + error(clazz, c, "FW3", "Parcelable inflation is exposed through CREATOR, not raw constructors") + def verify_protected(clazz): """Verify that no protected methods or fields are allowed.""" @@ -572,7 +578,7 @@ def verify_helper_classes(clazz): if f.name == "SERVICE_INTERFACE": found = True if f.value != clazz.fullname: - error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname)) + error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname)) if "extends android.content.ContentProvider" in clazz.raw: test_methods = True @@ -584,7 +590,7 @@ def verify_helper_classes(clazz): if f.name == "PROVIDER_INTERFACE": found = True if f.value != clazz.fullname: - error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname)) + error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname)) if "extends android.content.BroadcastReceiver" in clazz.raw: test_methods = True @@ -764,15 +770,19 @@ def verify_flags(clazz): def verify_exception(clazz): """Verifies that methods don't throw generic exceptions.""" for m in clazz.methods: - if "throws java.lang.Exception" in m.raw or "throws java.lang.Throwable" in m.raw or "throws java.lang.Error" in m.raw: - error(clazz, m, "S1", "Methods must not throw generic exceptions") + for t in m.throws: + if t in ["java.lang.Exception", "java.lang.Throwable", "java.lang.Error"]: + error(clazz, m, "S1", "Methods must not throw generic exceptions") + + if t in ["android.os.RemoteException"]: + if clazz.name == "android.content.ContentProviderClient": continue + if clazz.name == "android.os.Binder": continue + if clazz.name == "android.os.IBinder": continue - if "throws android.os.RemoteException" in m.raw: - if clazz.name == "android.content.ContentProviderClient": continue - if clazz.name == "android.os.Binder": continue - if clazz.name == "android.os.IBinder": continue + error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException") - error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException") + if len(m.args) == 0 and t in ["java.lang.IllegalArgumentException", "java.lang.NullPointerException"]: + warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException") def verify_google(clazz): @@ -927,7 +937,8 @@ def verify_callback_handlers(clazz): found = {} by_name = collections.defaultdict(list) - for m in clazz.methods: + examine = clazz.ctors + clazz.methods + for m in examine: if m.name.startswith("unregister"): continue if m.name.startswith("remove"): continue if re.match("on[A-Z]+", m.name): continue @@ -971,7 +982,7 @@ def verify_listener_last(clazz): for a in m.args: if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"): found = True - elif found and a != "android.os.Handler" and a != "java.util.concurrent.Executor": + elif found: warn(clazz, m, "M3", "Listeners should always be at end of argument list") @@ -1078,16 +1089,11 @@ def verify_runtime_exceptions(clazz): "java.nio.BufferOverflowException", ] - test = [] - test.extend(clazz.ctors) - test.extend(clazz.methods) - - for t in test: - if " throws " not in t.raw: continue - throws = t.raw[t.raw.index(" throws "):] - for b in banned: - if b in throws: - error(clazz, t, None, "Methods must not mention RuntimeException subclasses in throws clauses") + examine = clazz.ctors + clazz.methods + for m in examine: + for t in m.throws: + if t in banned: + error(clazz, m, None, "Methods must not mention RuntimeException subclasses in throws clauses") def verify_error(clazz): @@ -1233,6 +1239,58 @@ def verify_collections_over_arrays(clazz): warn(clazz, m, None, "Method argument should be Collection<> (or subclass) instead of raw array") +def verify_user_handle(clazz): + """Methods taking UserHandle should be ForUser or AsUser.""" + if clazz.name.endswith("Listener") or clazz.name.endswith("Callback") or clazz.name.endswith("Callbacks"): return + if clazz.fullname == "android.app.admin.DeviceAdminReceiver": return + if clazz.fullname == "android.content.pm.LauncherApps": return + if clazz.fullname == "android.os.UserHandle": return + if clazz.fullname == "android.os.UserManager": return + + for m in clazz.methods: + if m.name.endswith("AsUser") or m.name.endswith("ForUser"): continue + if re.match("on[A-Z]+", m.name): continue + if "android.os.UserHandle" in m.args: + warn(clazz, m, None, "Method taking UserHandle should be named 'doFooAsUser' or 'queryFooForUser'") + + +def verify_params(clazz): + """Parameter classes should be 'Params'.""" + if clazz.name.endswith("Params"): return + if clazz.fullname == "android.app.ActivityOptions": return + if clazz.fullname == "android.app.BroadcastOptions": return + if clazz.fullname == "android.os.Bundle": return + if clazz.fullname == "android.os.BaseBundle": return + if clazz.fullname == "android.os.PersistableBundle": return + + bad = ["Param","Parameter","Parameters","Args","Arg","Argument","Arguments","Options","Bundle"] + for b in bad: + if clazz.name.endswith(b): + error(clazz, None, None, "Classes holding a set of parameters should be called 'FooParams'") + + +def verify_services(clazz): + """Service name should be FOO_BAR_SERVICE = 'foo_bar'.""" + if clazz.fullname != "android.content.Context": return + + for f in clazz.fields: + if f.typ != "java.lang.String": continue + found = re.match(r"([A-Z_]+)_SERVICE", f.name) + if found: + expected = found.group(1).lower() + if f.value != expected: + error(clazz, f, "C4", "Inconsistent service value; expected '%s'" % (expected)) + + +def verify_tense(clazz): + """Verify tenses of method names.""" + if clazz.fullname.startswith("android.opengl"): return + + for m in clazz.methods: + if m.name.endswith("Enable"): + warn(clazz, m, None, "Unexpected tense; probably meant 'enabled'") + + def examine_clazz(clazz): """Find all style issues in the given class.""" @@ -1290,6 +1348,10 @@ def examine_clazz(clazz): verify_member_name_not_kotlin_keyword(clazz) verify_method_name_not_kotlin_operator(clazz) verify_collections_over_arrays(clazz) + verify_user_handle(clazz) + verify_params(clazz) + verify_services(clazz) + verify_tense(clazz) def examine_stream(stream): |