diff options
131 files changed, 2779 insertions, 2671 deletions
diff --git a/api/current.txt b/api/current.txt index 8ec7594773af..f9db63d68bd6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -287,7 +287,6 @@ package android { field public static final int allowBackup = 16843392; // 0x1010280 field public static final int allowClearUserData = 16842757; // 0x1010005 field public static final int allowEmbedded = 16843765; // 0x10103f5 - field public static final int allowExternalStorageSandbox = 16844201; // 0x10105a9 field public static final int allowParallelSyncs = 16843570; // 0x1010332 field public static final int allowSingleTap = 16843353; // 0x1010259 field public static final int allowTaskReparenting = 16843268; // 0x1010204 @@ -1125,6 +1124,7 @@ package android { field public static final int reqKeyboardType = 16843304; // 0x1010228 field public static final int reqNavigation = 16843306; // 0x101022a field public static final int reqTouchScreen = 16843303; // 0x1010227 + field public static final int requestLegacyExternalStorage = 16844201; // 0x10105a9 field public static final int requireDeviceUnlock = 16843756; // 0x10103ec field public static final int required = 16843406; // 0x101028e field public static final int requiredAccountType = 16843734; // 0x10103d6 @@ -11859,6 +11859,7 @@ package android.content.pm { field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR; field public static final int FLAG_COSTS_MONEY = 1; // 0x1 field public static final int FLAG_HARD_RESTRICTED = 4; // 0x4 + field public static final int FLAG_IMMUTABLY_RESTRICTED = 16; // 0x10 field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000 field public static final int FLAG_SOFT_RESTRICTED = 8; // 0x8 field public static final int PROTECTION_DANGEROUS = 1; // 0x1 @@ -39144,7 +39145,7 @@ package android.provider { field public static final String CONTENT_ID = "cid"; field public static final String CONTENT_LOCATION = "cl"; field public static final String CONTENT_TYPE = "ct"; - field public static final android.net.Uri CONTENT_URI; + field @NonNull public static final android.net.Uri CONTENT_URI; field public static final String CT_START = "ctt_s"; field public static final String CT_TYPE = "ctt_t"; field public static final String FILENAME = "fn"; @@ -51509,6 +51510,7 @@ package android.view { method public android.transition.Transition getSharedElementReturnTransition(); method public boolean getSharedElementsUseOverlay(); method @ColorInt public abstract int getStatusBarColor(); + method @NonNull public java.util.List<android.graphics.Rect> getSystemGestureExclusionRects(); method public long getTransitionBackgroundFadeDuration(); method public android.transition.TransitionManager getTransitionManager(); method public abstract int getVolumeControlStream(); @@ -51587,6 +51589,7 @@ package android.view { method public void setSoftInputMode(int); method public abstract void setStatusBarColor(@ColorInt int); method public void setSustainedPerformanceMode(boolean); + method public void setSystemGestureExclusionRects(@NonNull java.util.List<android.graphics.Rect>); method public abstract void setTitle(CharSequence); method @Deprecated public abstract void setTitleColor(@ColorInt int); method public void setTransitionBackgroundFadeDuration(long); @@ -53614,29 +53617,23 @@ package android.view.textclassifier { method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig.Builder setIncludedTypes(@Nullable java.util.Collection<java.lang.String>); } - public final class TextClassifierEvent implements android.os.Parcelable { + public abstract class TextClassifierEvent implements android.os.Parcelable { method public int describeContents(); method @NonNull public int[] getActionIndices(); method @NonNull public String[] getEntityTypes(); method public int getEventCategory(); method @Nullable public android.view.textclassifier.TextClassificationContext getEventContext(); method public int getEventIndex(); - method public long getEventTime(); method public int getEventType(); method @NonNull public android.os.Bundle getExtras(); - method @Nullable public String getLanguage(); - method public int getRelativeSuggestedWordEndIndex(); - method public int getRelativeSuggestedWordStartIndex(); - method public int getRelativeWordEndIndex(); - method public int getRelativeWordStartIndex(); + method @Nullable public String getModelName(); method @Nullable public String getResultId(); - method public float getScore(); + method @NonNull public float[] getScores(); method public void writeToParcel(android.os.Parcel, int); field public static final int CATEGORY_CONVERSATION_ACTIONS = 3; // 0x3 field public static final int CATEGORY_LANGUAGE_DETECTION = 4; // 0x4 field public static final int CATEGORY_LINKIFY = 2; // 0x2 field public static final int CATEGORY_SELECTION = 1; // 0x1 - field public static final int CATEGORY_UNDEFINED = 0; // 0x0 field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent> CREATOR; field public static final int TYPE_ACTIONS_GENERATED = 20; // 0x14 field public static final int TYPE_ACTIONS_SHOWN = 6; // 0x6 @@ -53658,25 +53655,63 @@ package android.view.textclassifier { field public static final int TYPE_SMART_ACTION = 13; // 0xd field public static final int TYPE_SMART_SELECTION_MULTI = 4; // 0x4 field public static final int TYPE_SMART_SELECTION_SINGLE = 3; // 0x3 - field public static final int TYPE_UNDEFINED = 0; // 0x0 - } - - public static final class TextClassifierEvent.Builder { - ctor public TextClassifierEvent.Builder(int, int); - method @NonNull public android.view.textclassifier.TextClassifierEvent build(); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setActionIndices(@NonNull int...); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEntityTypes(@NonNull java.lang.String...); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventContext(@Nullable android.view.textclassifier.TextClassificationContext); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventTime(long); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setExtras(@NonNull android.os.Bundle); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setLanguage(@Nullable String); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordEndIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordStartIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordEndIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordStartIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setResultId(@Nullable String); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setScore(float); + } + + public abstract static class TextClassifierEvent.Builder<T extends android.view.textclassifier.TextClassifierEvent.Builder<T>> { + method @NonNull public T setActionIndices(@NonNull int...); + method @NonNull public T setEntityTypes(@NonNull java.lang.String...); + method @NonNull public T setEventContext(@Nullable android.view.textclassifier.TextClassificationContext); + method @NonNull public T setEventIndex(int); + method @NonNull public T setExtras(@NonNull android.os.Bundle); + method @NonNull public T setModelName(@Nullable String); + method @NonNull public T setResultId(@Nullable String); + method @NonNull public T setScores(@NonNull float...); + } + + public static final class TextClassifierEvent.ConversationActionsEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent> CREATOR; + } + + public static final class TextClassifierEvent.ConversationActionsEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent.Builder> { + ctor public TextClassifierEvent.ConversationActionsEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent build(); + } + + public static final class TextClassifierEvent.LanguageDetectionEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + method @Nullable public android.icu.util.ULocale getLocale(); + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent> CREATOR; + } + + public static final class TextClassifierEvent.LanguageDetectionEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent.Builder> { + ctor public TextClassifierEvent.LanguageDetectionEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent build(); + method @NonNull public android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent.Builder setLocale(@Nullable android.icu.util.ULocale); + } + + public static final class TextClassifierEvent.TextLinkifyEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent> CREATOR; + } + + public static final class TextClassifierEvent.TextLinkifyEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent.Builder> { + ctor public TextClassifierEvent.TextLinkifyEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent build(); + } + + public static final class TextClassifierEvent.TextSelectionEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + method public int getRelativeSuggestedWordEndIndex(); + method public int getRelativeSuggestedWordStartIndex(); + method public int getRelativeWordEndIndex(); + method public int getRelativeWordStartIndex(); + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.TextSelectionEvent> CREATOR; + } + + public static final class TextClassifierEvent.TextSelectionEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder> { + ctor public TextClassifierEvent.TextSelectionEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent build(); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeSuggestedWordEndIndex(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeSuggestedWordStartIndex(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeWordEndIndex(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeWordStartIndex(int); } public final class TextLanguage implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index 209fca77a8ba..b60e850249ef 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1092,11 +1092,14 @@ package android.app.prediction { } public static final class AppTarget.Builder { + ctor @Deprecated public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId); ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull String, @NonNull android.os.UserHandle); ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo); method @NonNull public android.app.prediction.AppTarget build(); method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String); method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index 4bcb8da281f6..f76b3830c461 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -503,6 +503,8 @@ package android.app.prediction { method @NonNull public android.app.prediction.AppTarget build(); method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String); method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { @@ -1104,6 +1106,7 @@ package android.media { method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); + field public static final int SUCCESS = 0; // 0x0 } public static final class AudioRecord.MetricsConstants { @@ -1129,22 +1132,6 @@ package android.media { field public static final String SAMPLE_RATE = "android.media.audiotrack.sampleRate"; } - public final class BufferingParams implements android.os.Parcelable { - method public int describeContents(); - method public int getInitialMarkMs(); - method public int getResumePlaybackMarkMs(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR; - } - - public static class BufferingParams.Builder { - ctor public BufferingParams.Builder(); - ctor public BufferingParams.Builder(android.media.BufferingParams); - method public android.media.BufferingParams build(); - method public android.media.BufferingParams.Builder setInitialMarkMs(int); - method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int); - } - public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint { ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size); ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size); @@ -1241,8 +1228,10 @@ package android.media.audiopolicy { method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>); method public int getFocusDuckingBehavior(); method public int getStatus(); + method public boolean removeUidDeviceAffinity(int); method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void setRegistration(String); + method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>); method public String toLogFriendlyString(); field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0 field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0 diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 5778fa9f6903..d28108ceeb73 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -268,7 +268,8 @@ message Atom { TouchGestureClassified touch_gesture_classified = 177; HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true]; StyleUIChanged style_ui_changed = 179; - PrivacyIndicatorsInteracted privacy_indicators_interacted = 180; + PrivacyIndicatorsInteracted privacy_indicators_interacted = + 180 [(log_from_module) = "permissioncontroller"]; AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181; NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"]; AppMovedStorageReported app_moved_storage_reported = 183; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 5f972c9895b4..6e935e1e56c4 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -127,7 +127,6 @@ import android.view.autofill.AutofillPopupWindow; import android.view.autofill.IAutofillWindowPresenter; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureManager; -import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient; import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; @@ -724,7 +723,7 @@ public class Activity extends ContextThemeWrapper Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback, - AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient { + AutofillManager.AutofillClient { private static final String TAG = "Activity"; private static final boolean DEBUG_LIFECYCLE = false; @@ -1124,12 +1123,6 @@ public class Activity extends ContextThemeWrapper return this; } - /** @hide */ - @Override - public final ContentCaptureClient getContentCaptureClient() { - return this; - } - /** * Register an {@link Application.ActivityLifecycleCallbacks} instance that receives * lifecycle callbacks for only this Activity. @@ -6509,12 +6502,6 @@ public class Activity extends ContextThemeWrapper return getComponentName(); } - /** @hide */ - @Override - public final ComponentName contentCaptureClientGetComponentName() { - return getComponentName(); - } - /** * Retrieve a {@link SharedPreferences} object for accessing preferences * that are private to this activity. This simply calls the underlying diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 6f9224481eba..7243624b855a 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -823,9 +823,11 @@ public class AppOpsManager { public static final int OP_LEGACY_STORAGE = 87; /** @hide Accessing accessibility features */ public static final int OP_ACCESS_ACCESSIBILITY = 88; + /** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */ + public static final int OP_READ_DEVICE_IDENTIFIERS = 89; /** @hide */ @UnsupportedAppUsage - public static final int _NUM_OP = 89; + public static final int _NUM_OP = 90; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1099,6 +1101,8 @@ public class AppOpsManager { /** @hide Interact with accessibility. */ @SystemApi public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; + /** @hide Read device identifiers */ + public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers"; // Warning: If an permission is added here it also has to be added to // com.android.packageinstaller.permission.utils.EventLogger @@ -1259,6 +1263,7 @@ public class AppOpsManager { OP_WRITE_MEDIA_IMAGES, // WRITE_MEDIA_IMAGES OP_LEGACY_STORAGE, // LEGACY_STORAGE OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY + OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS }; /** @@ -1354,6 +1359,7 @@ public class AppOpsManager { OPSTR_WRITE_MEDIA_IMAGES, OPSTR_LEGACY_STORAGE, OPSTR_ACCESS_ACCESSIBILITY, + OPSTR_READ_DEVICE_IDENTIFIERS, }; /** @@ -1450,6 +1456,7 @@ public class AppOpsManager { "WRITE_MEDIA_IMAGES", "LEGACY_STORAGE", "ACCESS_ACCESSIBILITY", + "READ_DEVICE_IDENTIFIERS", }; /** @@ -1547,6 +1554,7 @@ public class AppOpsManager { null, // no permission for OP_WRITE_MEDIA_IMAGES null, // no permission for OP_LEGACY_STORAGE null, // no permission for OP_ACCESS_ACCESSIBILITY + null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS }; /** @@ -1644,6 +1652,7 @@ public class AppOpsManager { null, // WRITE_MEDIA_IMAGES null, // LEGACY_STORAGE null, // ACCESS_ACCESSIBILITY + null, // READ_DEVICE_IDENTIFIERS }; /** @@ -1740,6 +1749,7 @@ public class AppOpsManager { false, // WRITE_MEDIA_IMAGES false, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY + false, // READ_DEVICE_IDENTIFIERS }; /** @@ -1752,21 +1762,21 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // VIBRATE AppOpsManager.MODE_ALLOWED, // READ_CONTACTS AppOpsManager.MODE_ALLOWED, // WRITE_CONTACTS - AppOpsManager.MODE_DEFAULT, // READ_CALL_LOG - AppOpsManager.MODE_DEFAULT, // WRITE_CALL_LOG + AppOpsManager.MODE_ALLOWED, // READ_CALL_LOG + AppOpsManager.MODE_ALLOWED, // WRITE_CALL_LOG AppOpsManager.MODE_ALLOWED, // READ_CALENDAR AppOpsManager.MODE_ALLOWED, // WRITE_CALENDAR AppOpsManager.MODE_ALLOWED, // WIFI_SCAN AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS AppOpsManager.MODE_ALLOWED, // CALL_PHONE - AppOpsManager.MODE_DEFAULT, // READ_SMS + AppOpsManager.MODE_ALLOWED, // READ_SMS AppOpsManager.MODE_IGNORED, // WRITE_SMS - AppOpsManager.MODE_DEFAULT, // RECEIVE_SMS + AppOpsManager.MODE_ALLOWED, // RECEIVE_SMS AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST - AppOpsManager.MODE_DEFAULT, // RECEIVE_MMS - AppOpsManager.MODE_DEFAULT, // RECEIVE_WAP_PUSH - AppOpsManager.MODE_DEFAULT, // SEND_SMS + AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS + AppOpsManager.MODE_ALLOWED, // RECEIVE_WAP_PUSH + AppOpsManager.MODE_ALLOWED, // SEND_SMS AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS @@ -1800,10 +1810,10 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // READ_PHONE_STATE AppOpsManager.MODE_ALLOWED, // ADD_VOICEMAIL AppOpsManager.MODE_ALLOWED, // USE_SIP - AppOpsManager.MODE_DEFAULT, // PROCESS_OUTGOING_CALLS + AppOpsManager.MODE_ALLOWED, // PROCESS_OUTGOING_CALLS AppOpsManager.MODE_ALLOWED, // USE_FINGERPRINT AppOpsManager.MODE_ALLOWED, // BODY_SENSORS - AppOpsManager.MODE_DEFAULT, // READ_CELL_BROADCASTS + AppOpsManager.MODE_ALLOWED, // READ_CELL_BROADCASTS AppOpsManager.MODE_ERRORED, // MOCK_LOCATION AppOpsManager.MODE_ALLOWED, // READ_EXTERNAL_STORAGE AppOpsManager.MODE_ALLOWED, // WRITE_EXTERNAL_STORAGE @@ -1835,6 +1845,7 @@ public class AppOpsManager { AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY + AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS }; /** @@ -1934,6 +1945,7 @@ public class AppOpsManager { false, // WRITE_MEDIA_IMAGES false, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY + false, // READ_DEVICE_IDENTIFIERS }; /** diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java index 4704661c2b24..61e4569c1228 100644 --- a/core/java/android/app/prediction/AppTarget.java +++ b/core/java/android/app/prediction/AppTarget.java @@ -208,6 +208,7 @@ public final class AppTarget implements Parcelable { * @hide */ @Deprecated + @SystemApi public Builder(@NonNull AppTargetId id) { mId = id; } @@ -243,7 +244,6 @@ public final class AppTarget implements Parcelable { /** * @deprecated Use the appropriate constructor. - * @hide */ @NonNull @Deprecated @@ -258,7 +258,6 @@ public final class AppTarget implements Parcelable { /** * @deprecated Use the appropriate constructor. - * @hide */ @NonNull @Deprecated diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java index 027e152ee95f..394a0d64b3e4 100644 --- a/core/java/android/app/role/RoleControllerManager.java +++ b/core/java/android/app/role/RoleControllerManager.java @@ -52,7 +52,10 @@ public class RoleControllerManager { private static final String LOG_TAG = RoleControllerManager.class.getSimpleName(); + private static volatile ComponentName sRemoteServiceComponentName; + private static final Object sRemoteServicesLock = new Object(); + /** * Global remote services (per user) used by all {@link RoleControllerManager managers}. */ @@ -62,18 +65,36 @@ public class RoleControllerManager { @NonNull private final RemoteService mRemoteService; - public RoleControllerManager(@NonNull Context context, @NonNull Handler handler) { + /** + * Initialize the remote service component name once so that we can avoid acquiring the + * PackageManagerService lock in constructor. + * + * @see #createWithInitializedRemoteServiceComponentName(Handler, Context) + */ + public static void initializeRemoteServiceComponentName(@NonNull Context context) { + sRemoteServiceComponentName = getRemoteServiceComponentName(context); + } + + /** + * Create a {@link RoleControllerManager} instance with the initialized remote service component + * name so that we can avoid acquiring the PackageManagerService lock in constructor. + * + * @see #initializeRemoteServiceComponentName(Context) + */ + @NonNull + public static RoleControllerManager createWithInitializedRemoteServiceComponentName( + @NonNull Handler handler, @NonNull Context context) { + return new RoleControllerManager(sRemoteServiceComponentName, handler, context); + } + + private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName, + @NonNull Handler handler, @NonNull Context context) { synchronized (sRemoteServicesLock) { int userId = context.getUserId(); RemoteService remoteService = sRemoteServices.get(userId); if (remoteService == null) { - Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE); - PackageManager packageManager = context.getPackageManager(); - intent.setPackage(packageManager.getPermissionControllerPackageName()); - ResolveInfo resolveInfo = packageManager.resolveService(intent, 0); - remoteService = new RemoteService(context.getApplicationContext(), - resolveInfo.getComponentInfo().getComponentName(), handler, userId); + remoteServiceComponentName, handler, userId); sRemoteServices.put(userId, remoteService); } mRemoteService = remoteService; @@ -81,7 +102,16 @@ public class RoleControllerManager { } public RoleControllerManager(@NonNull Context context) { - this(context, context.getMainThreadHandler()); + this(getRemoteServiceComponentName(context), context.getMainThreadHandler(), context); + } + + @NonNull + private static ComponentName getRemoteServiceComponentName(@NonNull Context context) { + Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE); + PackageManager packageManager = context.getPackageManager(); + intent.setPackage(packageManager.getPermissionControllerPackageName()); + ResolveInfo resolveInfo = packageManager.resolveService(intent, 0); + return resolveInfo.getComponentInfo().getComponentName(); } /** diff --git a/core/java/android/content/AutofillOptions.java b/core/java/android/content/AutofillOptions.java index f59bc9891c86..8fb9501b3319 100644 --- a/core/java/android/content/AutofillOptions.java +++ b/core/java/android/content/AutofillOptions.java @@ -24,7 +24,7 @@ import android.os.Parcelable; import android.util.ArraySet; import android.util.Log; import android.view.autofill.AutofillManager; -import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient; +import android.view.autofill.AutofillManager.AutofillClient; import java.io.PrintWriter; @@ -73,10 +73,10 @@ public final class AutofillOptions implements Parcelable { public boolean isAugmentedAutofillEnabled(@NonNull Context context) { if (!augmentedAutofillEnabled) return false; - final ContentCaptureClient contentCaptureClient = context.getContentCaptureClient(); - if (contentCaptureClient == null) return false; + final AutofillClient autofillClient = context.getAutofillClient(); + if (autofillClient == null) return false; - final ComponentName component = contentCaptureClient.contentCaptureClientGetComponentName(); + final ComponentName component = autofillClient.autofillClientGetComponentName(); return whitelistedActivitiesForAugmentedAutofill == null || whitelistedActivitiesForAugmentedAutofill.contains(component); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5a844aab02f0..0ba457e65c67 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -70,7 +70,6 @@ import android.view.View; import android.view.ViewDebug; import android.view.WindowManager; import android.view.autofill.AutofillManager.AutofillClient; -import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient; import android.view.textclassifier.TextClassificationManager; import java.io.File; @@ -5414,14 +5413,6 @@ public abstract class Context { /** * @hide */ - @Nullable - public ContentCaptureClient getContentCaptureClient() { - return null; - } - - /** - * @hide - */ public final boolean isAutofillCompatibilityEnabled() { final AutofillOptions options = getAutofillOptions(); return options != null && options.compatModeEnabled; diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index deb181f4fd0a..9bc5f8055617 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -679,13 +679,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28; /** - * Value for {@link #privateFlags}: If {@code true} this app allows - * shared/external storage media to be a sandboxed view that only contains - * files owned by the app. + * Value for {@link #privateFlags}: If {@code true} this app requests + * full external storage access. The request may not be honored due to + * policy or other reasons. * * @hide */ - public static final int PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX = 1 << 29; + public static final int PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE = 1 << 29; /** * Value for {@link #privateFlags}: whether this app is pre-installed on the @@ -723,7 +723,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_HAS_FRAGILE_USER_DATA, PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE, - PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX, + PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE, PRIVATE_FLAG_ODM, }) @Retention(RetentionPolicy.SOURCE) @@ -1858,13 +1858,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } /** - * If {@code true} this app allows shared/external storage media to be a - * sandboxed view that only contains files owned by the app. + * If {@code true} this app requested to run in the legacy storage mode. * * @hide */ - public boolean isExternalStorageSandboxAllowed() { - return (privateFlags & PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX) != 0; + public boolean hasRequestedLegacyExternalStorage() { + return (privateFlags & PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0; } private boolean isAllowedToUseHiddenApis() { diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 6ce682843ed5..d2f0fb3cc768 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1505,13 +1505,14 @@ public class PackageInstaller { * allows the app to hold that permission and whitelisting a soft restricted * permission allows the app to hold the permission in its full, unrestricted form. * - * <p>The whitelisted permissions would be applied as the {@link - * PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER installer whitelist}. + * <p> Permissions can also be immutably restricted which means that the whitelist + * state of the permission can be determined only at install time and cannot be + * changed on updated or at a later point via the package manager APIs. * - * @param permissions The restricted permissions to whitelist. Pass - * {@link #RESTRICTED_PERMISSIONS_ALL} to whitelist all permissions and - * <code>null</code> to clear. If you want to whitelist some permissions - * (not all) the list must contain at least one permission. + * <p>The whitelisted non-immutably restricted permissions would be added to + * the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER installer whitelist} + * while the immutably restricted permissions would be added to the {@link + * PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM system whitelist} * * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int) * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int) diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index bdd80e325c4b..0ea5200d202a 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3700,9 +3700,9 @@ public class PackageParser { } if (sa.getBoolean( - R.styleable.AndroidManifestApplication_allowExternalStorageSandbox, - owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q)) { - ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX; + R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, + owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q)) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE; } ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0); diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index f838900d43d7..14340fe788f7 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -341,6 +341,17 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_SOFT_RESTRICTED = 1<<3; /** + * Flag for {@link #flags}, corresponding to <code>immutablyRestricted</code> + * value of {@link android.R.attr#permissionFlags}. + * + * <p>This permission is restricted immutably which means that its + * restriction state may be specified only on the first install of + * the app and will stay in this initial whitelist state until + * the app is uninstalled. + */ + public static final int FLAG_IMMUTABLY_RESTRICTED = 1<<4; + + /** * Flag for {@link #flags}, indicating that this permission has been * installed into the system's globally defined permissions. */ diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index b6c4fe2de4f4..68826cbeb845 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -197,7 +197,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkSend((network != null - ? network.netId : NETID_UNSET), query, query.length, flags); + ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -238,7 +238,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); + ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -346,7 +346,8 @@ public final class DnsResolver { if (queryIpv6) { try { v6fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_AAAA, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -365,7 +366,8 @@ public final class DnsResolver { if (queryIpv4) { try { v4fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_A, flags); } catch (ErrnoException e) { if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); @@ -423,7 +425,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, nsType, flags); + ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index ed5c1b1e2277..dde1e6a7f5f7 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -1148,15 +1148,9 @@ public class Environment { final Context context = AppGlobals.getInitialApplication(); final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); - final boolean hasLegacy = appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, + return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, context.getApplicationInfo().uid, - context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED; - - // STOPSHIP: only use app-op once permission model has fully landed - final boolean requestedLegacy = !AppGlobals.getInitialApplication().getApplicationInfo() - .isExternalStorageSandboxAllowed(); - - return !(hasLegacy || requestedLegacy); + context.getOpPackageName()) != AppOpsManager.MODE_ALLOWED; } static File getDirectory(String variableName, String defaultPath) { diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index b00eb8a0a2e1..656127ad77a9 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -27,6 +27,7 @@ import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.graphics.Rect; +import android.os.Build; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; @@ -67,9 +68,8 @@ public abstract class AugmentedAutofillService extends Service { private static final String TAG = AugmentedAutofillService.class.getSimpleName(); - // TODO(b/123100811): STOPSHIP use dynamic value, or change to false - static final boolean DEBUG = true; - static final boolean VERBOSE = false; + static boolean sDebug = Build.IS_USER ? false : true; + static boolean sVerbose = false; /** * The {@link Intent} that must be declared as handled by the service. @@ -87,9 +87,9 @@ public abstract class AugmentedAutofillService extends Service { private final IAugmentedAutofillService mInterface = new IAugmentedAutofillService.Stub() { @Override - public void onConnected() { + public void onConnected(boolean debug, boolean verbose) { mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnConnected, - AugmentedAutofillService.this)); + AugmentedAutofillService.this, debug, verbose)); } @Override @@ -190,7 +190,12 @@ public abstract class AugmentedAutofillService extends Service { public void onDisconnected() { } - private void handleOnConnected() { + private void handleOnConnected(boolean debug, boolean verbose) { + if (sDebug || debug) { + Log.d(TAG, "handleOnConnected(): debug=" + debug + ", verbose=" + verbose); + } + sDebug = debug; + sVerbose = verbose; onConnected(); } @@ -215,7 +220,7 @@ public abstract class AugmentedAutofillService extends Service { mAutofillProxies.put(sessionId, proxy); } else { // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging - if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId); + if (sDebug) Log.d(TAG, "Reusing proxy for session " + sessionId); proxy.update(focusedId, focusedValue, callback); } @@ -248,11 +253,11 @@ public abstract class AugmentedAutofillService extends Service { private void handleOnUnbind() { if (mAutofillProxies == null) { - if (DEBUG) Log.d(TAG, "onUnbind(): no proxy to destroy"); + if (sDebug) Log.d(TAG, "onUnbind(): no proxy to destroy"); return; } final int size = mAutofillProxies.size(); - if (DEBUG) Log.d(TAG, "onUnbind(): destroying " + size + " proxies"); + if (sDebug) Log.d(TAG, "onUnbind(): destroying " + size + " proxies"); for (int i = 0; i < size; i++) { final AutofillProxy proxy = mAutofillProxies.valueAt(i); try { @@ -373,7 +378,7 @@ public abstract class AugmentedAutofillService extends Service { return null; } if (rect == null) { - if (DEBUG) Log.d(TAG, "getViewCoordinates(" + mFocusedId + ") returned null"); + if (sDebug) Log.d(TAG, "getViewCoordinates(" + mFocusedId + ") returned null"); return null; } mSmartSuggestion = new SystemPopupPresentationParams(this, rect); @@ -410,7 +415,7 @@ public abstract class AugmentedAutofillService extends Service { public void requestShowFillUi(int width, int height, Rect anchorBounds, IAutofillWindowPresenter presenter) throws RemoteException { if (mCancellationSignal.isCanceled()) { - if (VERBOSE) { + if (sVerbose) { Log.v(TAG, "requestShowFillUi() not showing because request is cancelled"); } return; @@ -462,7 +467,7 @@ public abstract class AugmentedAutofillService extends Service { case REPORT_EVENT_ON_SUCCESS: if (mFirstOnSuccessTime == 0) { mFirstOnSuccessTime = SystemClock.elapsedRealtime(); - if (DEBUG) { + if (sDebug) { Slog.d(TAG, "Service responded in " + TimeUtils.formatDuration( mFirstOnSuccessTime - mFirstRequestTime)); } @@ -476,7 +481,7 @@ public abstract class AugmentedAutofillService extends Service { case REPORT_EVENT_UI_SHOWN: if (mUiFirstShownTime == 0) { mUiFirstShownTime = SystemClock.elapsedRealtime(); - if (DEBUG) { + if (sDebug) { Slog.d(TAG, "UI shown in " + TimeUtils.formatDuration( mUiFirstShownTime - mFirstRequestTime)); } @@ -485,7 +490,7 @@ public abstract class AugmentedAutofillService extends Service { case REPORT_EVENT_UI_DESTROYED: if (mUiFirstDestroyedTime == 0) { mUiFirstDestroyedTime = SystemClock.elapsedRealtime(); - if (DEBUG) { + if (sDebug) { Slog.d(TAG, "UI destroyed in " + TimeUtils.formatDuration( mUiFirstDestroyedTime - mFirstRequestTime)); } @@ -541,7 +546,7 @@ public abstract class AugmentedAutofillService extends Service { private void destroy() { synchronized (mLock) { if (mFillWindow != null) { - if (DEBUG) Log.d(TAG, "destroying window"); + if (sDebug) Log.d(TAG, "destroying window"); mFillWindow.destroy(); mFillWindow = null; } diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java index b989dd9cd4eb..33e6a8c25ba4 100644 --- a/core/java/android/service/autofill/augmented/FillCallback.java +++ b/core/java/android/service/autofill/augmented/FillCallback.java @@ -15,7 +15,7 @@ */ package android.service.autofill.augmented; -import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG; +import static android.service.autofill.augmented.AugmentedAutofillService.sDebug; import android.annotation.NonNull; import android.annotation.Nullable; @@ -48,7 +48,7 @@ public final class FillCallback { * could not provide autofill for the request. */ public void onSuccess(@Nullable FillResponse response) { - if (DEBUG) Log.d(TAG, "onSuccess(): " + response); + if (sDebug) Log.d(TAG, "onSuccess(): " + response); mProxy.report(AutofillProxy.REPORT_EVENT_ON_SUCCESS); if (response == null) return; diff --git a/core/java/android/service/autofill/augmented/FillController.java b/core/java/android/service/autofill/augmented/FillController.java index 67f23d599e1d..63ec2d886caf 100644 --- a/core/java/android/service/autofill/augmented/FillController.java +++ b/core/java/android/service/autofill/augmented/FillController.java @@ -15,7 +15,7 @@ */ package android.service.autofill.augmented; -import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG; +import static android.service.autofill.augmented.AugmentedAutofillService.sDebug; import android.annotation.NonNull; import android.annotation.SystemApi; @@ -56,7 +56,7 @@ public final class FillController { public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> values) { Preconditions.checkNotNull(values); - if (DEBUG) { + if (sDebug) { Log.d(TAG, "autofill() with " + values.size() + " values"); } diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java index bd532a32035c..6a29d485b997 100644 --- a/core/java/android/service/autofill/augmented/FillWindow.java +++ b/core/java/android/service/autofill/augmented/FillWindow.java @@ -15,8 +15,8 @@ */ package android.service.autofill.augmented; -import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG; -import static android.service.autofill.augmented.AugmentedAutofillService.VERBOSE; +import static android.service.autofill.augmented.AugmentedAutofillService.sDebug; +import static android.service.autofill.augmented.AugmentedAutofillService.sVerbose; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; @@ -100,7 +100,7 @@ public final class FillWindow implements AutoCloseable { * @throws IllegalArgumentException if the area is not compatible with this window */ public boolean update(@NonNull Area area, @NonNull View rootView, long flags) { - if (DEBUG) { + if (sDebug) { Log.d(TAG, "Updating " + area + " + with " + rootView); } // TODO(b/123100712): add test case for null @@ -141,7 +141,7 @@ public final class FillWindow implements AutoCloseable { mFillView.setOnTouchListener( (view, motionEvent) -> { if (motionEvent.getAction() == MotionEvent.ACTION_OUTSIDE) { - if (VERBOSE) Log.v(TAG, "Outside touch detected, hiding the window"); + if (sVerbose) Log.v(TAG, "Outside touch detected, hiding the window"); hide(); } return false; @@ -149,7 +149,7 @@ public final class FillWindow implements AutoCloseable { ); mShowing = false; mBounds = new Rect(area.getBounds()); - if (DEBUG) { + if (sDebug) { Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView); } mUpdateCalled = true; @@ -162,7 +162,7 @@ public final class FillWindow implements AutoCloseable { /** @hide */ void show() { // TODO(b/123100712): check if updated first / throw exception - if (DEBUG) Log.d(TAG, "show()"); + if (sDebug) Log.d(TAG, "show()"); synchronized (mLock) { checkNotDestroyedLocked(); if (mWm == null || mFillView == null) { @@ -187,7 +187,7 @@ public final class FillWindow implements AutoCloseable { * <p>The window is not destroyed and can be shown again */ private void hide() { - if (DEBUG) Log.d(TAG, "hide()"); + if (sDebug) Log.d(TAG, "hide()"); synchronized (mLock) { checkNotDestroyedLocked(); if (mWm == null || mFillView == null) { @@ -204,7 +204,7 @@ public final class FillWindow implements AutoCloseable { } private void handleShow(WindowManager.LayoutParams p) { - if (DEBUG) Log.d(TAG, "handleShow()"); + if (sDebug) Log.d(TAG, "handleShow()"); synchronized (mLock) { if (mWm != null && mFillView != null) { p.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; @@ -219,7 +219,7 @@ public final class FillWindow implements AutoCloseable { } private void handleHide() { - if (DEBUG) Log.d(TAG, "handleHide()"); + if (sDebug) Log.d(TAG, "handleHide()"); synchronized (mLock) { if (mWm != null && mFillView != null && mShowing) { mWm.removeView(mFillView); @@ -234,7 +234,7 @@ public final class FillWindow implements AutoCloseable { * <p>Once destroyed, this window cannot be used anymore */ public void destroy() { - if (DEBUG) { + if (sDebug) { Log.d(TAG, "destroy(): mDestroyed=" + mDestroyed + " mShowing=" + mShowing + " mFillView=" + mFillView); @@ -296,13 +296,13 @@ public final class FillWindow implements AutoCloseable { @Override public void show(WindowManager.LayoutParams p, Rect transitionEpicenter, boolean fitsSystemWindows, int layoutDirection) { - if (DEBUG) Log.d(TAG, "FillWindowPresenter.show()"); + if (sDebug) Log.d(TAG, "FillWindowPresenter.show()"); mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleShow, FillWindow.this, p)); } @Override public void hide(Rect transitionEpicenter) { - if (DEBUG) Log.d(TAG, "FillWindowPresenter.hide()"); + if (sDebug) Log.d(TAG, "FillWindowPresenter.hide()"); mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleHide, FillWindow.this)); } } diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl index 509681113c1f..103fc4d7dfcf 100644 --- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl +++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl @@ -31,7 +31,7 @@ import java.util.List; * @hide */ oneway interface IAugmentedAutofillService { - void onConnected(); + void onConnected(boolean debug, boolean verbose); void onDisconnected(); void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId, in ComponentName activityComponent, in AutofillId focusedId, diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index feff9db1a63e..f2aaeaddef97 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -63,7 +63,6 @@ public class FeatureFlagUtils { 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/view/GestureExclusionTracker.java b/core/java/android/view/GestureExclusionTracker.java index 8eccc04fa647..6fcdd714f827 100644 --- a/core/java/android/view/GestureExclusionTracker.java +++ b/core/java/android/view/GestureExclusionTracker.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; +import com.android.internal.util.Preconditions; + import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; @@ -31,6 +33,8 @@ import java.util.List; */ class GestureExclusionTracker { private boolean mGestureExclusionViewsChanged = false; + private boolean mRootGestureExclusionRectsChanged = false; + private List<Rect> mRootGestureExclusionRects = Collections.emptyList(); private List<GestureExclusionViewInfo> mGestureExclusionViewInfos = new ArrayList<>(); private List<Rect> mGestureExclusionRects = Collections.emptyList(); @@ -59,9 +63,9 @@ class GestureExclusionTracker { @Nullable public List<Rect> computeChangedRects() { - boolean changed = false; + boolean changed = mRootGestureExclusionRectsChanged; final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator(); - final List<Rect> rects = new ArrayList<>(); + final List<Rect> rects = new ArrayList<>(mRootGestureExclusionRects); while (i.hasNext()) { final GestureExclusionViewInfo info = i.next(); switch (info.update()) { @@ -79,6 +83,7 @@ class GestureExclusionTracker { } if (changed || mGestureExclusionViewsChanged) { mGestureExclusionViewsChanged = false; + mRootGestureExclusionRectsChanged = false; if (!mGestureExclusionRects.equals(rects)) { mGestureExclusionRects = rects; return rects; @@ -87,6 +92,17 @@ class GestureExclusionTracker { return null; } + public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { + Preconditions.checkNotNull(rects, "rects must not be null"); + mRootGestureExclusionRects = rects; + mRootGestureExclusionRectsChanged = true; + } + + @NonNull + public List<Rect> getRootSystemGestureExclusionRects() { + return mRootGestureExclusionRects; + } + private static class GestureExclusionViewInfo { public static final int CHANGED = 0; public static final int UNCHANGED = 1; diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index 2ba1e016e03d..d415387808dd 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -85,6 +85,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { @Override public void onWindowFocusLost() { mHasWindowFocus = false; + getImm().unregisterImeConsumer(this); } /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c3a94655d7d5..096c988c8cf1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -11648,14 +11648,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * When screen readers (one type of accessibility tool) decide what should be read to the - * user, they typically look for input focusable ({@link #isFocusable()}) parents of - * non-focusable text items, and read those focusable parents and their non-focusable children - * as a unit. In some situations, this behavior is desirable for views that should not take - * input focus. Setting an item to be screen reader focusable requests that the view be - * treated as a unit by screen readers without any effect on input focusability. The default - * value of {@code false} lets screen readers use other signals, like focusable, to determine - * how to group items. + * Sets whether this View should be a focusable element for screen readers + * and include non-focusable Views from its subtree when providing feedback. + * <p> + * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, + * but does not impact input focus behavior. * * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader * accessibility tools. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 5ca70ba9a575..7ad118e760d8 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3829,6 +3829,24 @@ public final class ViewRootImpl implements ViewParent, } /** + * Set the root-level system gesture exclusion rects. These are added to those provided by + * the root's view hierarchy. + */ + public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { + mGestureExclusionTracker.setRootSystemGestureExclusionRects(rects); + mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + } + + /** + * Returns the root-level system gesture exclusion rects. These do not include those provided by + * the root's view hierarchy. + */ + @NonNull + public List<Rect> getRootSystemGestureExclusionRects() { + return mGestureExclusionTracker.getRootSystemGestureExclusionRects(); + } + + /** * Requests that the root render node is invalidated next time we perform a draw, such that * {@link WindowCallbacks#onPostDraw} gets called. */ diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index fc9d8c269538..b0ec6210d828 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -48,6 +48,7 @@ import android.transition.Transition; import android.transition.TransitionManager; import android.view.accessibility.AccessibilityEvent; +import java.util.Collections; import java.util.List; /** @@ -2397,6 +2398,53 @@ public abstract class Window { return false; } + /** + * Sets a list of areas within this window's coordinate space where the system should not + * intercept touch or other pointing device gestures. + * + * <p>This method should be used by apps that make use of + * {@link #takeSurface(SurfaceHolder.Callback2)} and do not have a view hierarchy available. + * Apps that do have a view hierarchy should use + * {@link View#setSystemGestureExclusionRects(List)} instead. This method does not modify or + * replace the gesture exclusion rects populated by individual views in this window's view + * hierarchy using {@link View#setSystemGestureExclusionRects(List)}.</p> + * + * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture + * input in order to function correctly in the presence of global system gestures that may + * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures + * to provide system-level navigation functionality, a view such as a navigation drawer + * container can mark the left (or starting) edge of itself as requiring gesture capture + * priority using this API. The system may then choose to relax its own gesture recognition + * to allow the app to consume the user's gesture. It is not necessary for an app to register + * exclusion rects for broadly spanning regions such as the entirety of a + * <code>ScrollView</code> or for simple press and release click targets such as + * <code>Button</code>. Mark an exclusion rect when interacting with a view requires + * a precision touch gesture in a small area in either the X or Y dimension, such as + * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> + * + * <p>Do not modify the provided list after this method is called.</p> + * + * @param rects A list of precision gesture regions that this window needs to function correctly + */ + @SuppressWarnings("unused") + public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { + throw new UnsupportedOperationException("window does not support gesture exclusion rects"); + } + + /** + * Retrieve the list of areas within this window's coordinate space where the system should not + * intercept touch or other pointing device gestures. This is the list as set by + * {@link #setSystemGestureExclusionRects(List)} or an empty list if + * {@link #setSystemGestureExclusionRects(List)} has not been called. It does not include + * exclusion rects set by this window's view hierarchy. + * + * @return a list of system gesture exclusion rects specific to this window + */ + @NonNull + public List<Rect> getSystemGestureExclusionRects() { + return Collections.emptyList(); + } + /** @hide */ public void setTheme(int resId) { } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 7a6e2adfcaa4..26454c055932 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -343,15 +343,6 @@ public final class ContentCaptureManager { private MainContentCaptureSession mMainSession; /** @hide */ - public interface ContentCaptureClient { - /** - * Gets the component name of the client. - */ - @NonNull - ComponentName contentCaptureClientGetComponentName(); - } - - /** @hide */ public ContentCaptureManager(@NonNull Context context, @NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) { mContext = Preconditions.checkNotNull(context, "context cannot be null"); diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 5e00425407ba..fd73856bf79b 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1951,6 +1951,23 @@ public final class InputMethodManager { } /** + * Unregister for IME state callbacks and applying visibility in + * {@link android.view.ImeInsetsSourceConsumer}. + * @hide + */ + public void unregisterImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) { + if (imeInsetsConsumer == null) { + throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null."); + } + + synchronized (mH) { + if (mImeInsetsConsumer == imeInsetsConsumer) { + mImeInsetsConsumer = null; + } + } + } + + /** * Call showSoftInput with currently focused view. * @return {@code true} if IME can be shown. * @hide diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java index 7b236747bae6..11e0e2ca072c 100644 --- a/core/java/android/view/textclassifier/ExtrasUtils.java +++ b/core/java/android/view/textclassifier/ExtrasUtils.java @@ -36,6 +36,7 @@ import java.util.List; // TODO: Make this a TestApi for CTS testing. public final class ExtrasUtils { + // Keys for response objects. private static final String SERIALIZED_ENTITIES_DATA = "serialized-entities-data"; private static final String ENTITIES_EXTRAS = "entities-extras"; private static final String ACTION_INTENT = "action-intent"; @@ -48,6 +49,10 @@ public final class ExtrasUtils { private static final String TEXT_LANGUAGES = "text-languages"; private static final String ENTITIES = "entities"; + // Keys for request objects. + private static final String IS_SERIALIZED_ENTITY_DATA_ENABLED = + "is-serialized-entity-data-enabled"; + private ExtrasUtils() {} /** @@ -308,7 +313,23 @@ public final class ExtrasUtils { /** * Returns a list of entities contained in the {@code extra}. */ + @Nullable public static List<Bundle> getEntities(Bundle container) { return container.getParcelableArrayList(ENTITIES); } + + /** + * Whether the annotator should populate serialized entity data into the result object. + */ + public static boolean isSerializedEntityDataEnabled(TextLinks.Request request) { + return request.getExtras().getBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED); + } + + /** + * To indicate whether the annotator should populate serialized entity data in the result + * object. + */ + public static void putIsSerializedEntityDataEnabled(Bundle bundle, boolean isEnabled) { + bundle.putBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED, isEnabled); + } } diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java index 236f89bf921a..d3d61a7460c7 100644 --- a/core/java/android/view/textclassifier/TextClassifierEvent.java +++ b/core/java/android/view/textclassifier/TextClassifierEvent.java @@ -19,6 +19,7 @@ package android.view.textclassifier; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.icu.util.ULocale; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -30,54 +31,65 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** - * A text classifier event. + * This class represents events that are sent by components to the {@link TextClassifier} to report + * something of note that relates to a feature powered by the TextClassifier. The TextClassifier may + * log these events or use them to improve future responses to queries. + * <p> + * Each categories of the events have their own subclass. Events of each types has an associated + * set of related properties. You can find the specification of them in the subclasses. */ -// TODO: Comprehensive javadoc. -public final class TextClassifierEvent implements Parcelable { +public abstract class TextClassifierEvent implements Parcelable { - public static final @android.annotation.NonNull Creator<TextClassifierEvent> CREATOR = new Creator<TextClassifierEvent>() { - @Override - public TextClassifierEvent createFromParcel(Parcel in) { - return readFromParcel(in); - } - - @Override - public TextClassifierEvent[] newArray(int size) { - return new TextClassifierEvent[size]; - } - }; + private static final int PARCEL_TOKEN_TEXT_SELECTION_EVENT = 1; + private static final int PARCEL_TOKEN_TEXT_LINKIFY_EVENT = 2; + private static final int PARCEL_TOKEN_CONVERSATION_ACTION_EVENT = 3; + private static final int PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT = 4; /** @hide **/ @Retention(RetentionPolicy.SOURCE) - @IntDef({CATEGORY_UNDEFINED, CATEGORY_SELECTION, CATEGORY_LINKIFY, + @IntDef({CATEGORY_SELECTION, CATEGORY_LINKIFY, CATEGORY_CONVERSATION_ACTIONS, CATEGORY_LANGUAGE_DETECTION}) public @interface Category { // For custom event categories, use range 1000+. } - /** Undefined category */ - public static final int CATEGORY_UNDEFINED = 0; - /** Smart selection */ + + /** + * Smart selection + * + * @see TextSelectionEvent + */ public static final int CATEGORY_SELECTION = 1; - /** Linkify */ + /** + * Linkify + * + * @see TextLinkifyEvent + */ public static final int CATEGORY_LINKIFY = 2; - /** Conversation actions */ + /** + * Conversation actions + * + * @see ConversationActionsEvent + */ public static final int CATEGORY_CONVERSATION_ACTIONS = 3; - /** Language detection */ + /** + * Language detection + * + * @see LanguageDetectionEvent + */ public static final int CATEGORY_LANGUAGE_DETECTION = 4; /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef({TYPE_UNDEFINED, TYPE_SELECTION_STARTED, TYPE_SELECTION_MODIFIED, - TYPE_SMART_SELECTION_SINGLE, TYPE_SMART_SELECTION_MULTI, TYPE_AUTO_SELECTION, - TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION, - TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION, - TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL, - TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED}) + @IntDef({TYPE_SELECTION_STARTED, TYPE_SELECTION_MODIFIED, + TYPE_SMART_SELECTION_SINGLE, TYPE_SMART_SELECTION_MULTI, TYPE_AUTO_SELECTION, + TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION, + TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION, + TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL, + TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED}) public @interface Type { // For custom event types, use range 1,000,000+. } - /** User started a new selection. */ - public static final int TYPE_UNDEFINED = 0; + /** User started a new selection. */ public static final int TYPE_SELECTION_STARTED = 1; /** User modified an existing selection. */ @@ -119,63 +131,49 @@ public final class TextClassifierEvent implements Parcelable { /** TextClassifier generated some actions */ public static final int TYPE_ACTIONS_GENERATED = 20; - @Category private final int mEventCategory; - @Type private final int mEventType; - @Nullable private final String[] mEntityTypes; - @Nullable private final TextClassificationContext mEventContext; - @Nullable private final String mResultId; + @Category + private final int mEventCategory; + @Type + private final int mEventType; + @Nullable + private final String[] mEntityTypes; + @Nullable + private final TextClassificationContext mEventContext; + @Nullable + private final String mResultId; private final int mEventIndex; - private final long mEventTime; + private final float[] mScores; + @Nullable + private final String mModelName; + private final int[] mActionIndices; private final Bundle mExtras; - // Smart selection. - private final int mRelativeWordStartIndex; - private final int mRelativeWordEndIndex; - private final int mRelativeSuggestedWordStartIndex; - private final int mRelativeSuggestedWordEndIndex; - - // Smart action. - private final int[] mActionIndices; + private TextClassifierEvent(Builder builder) { + mEventCategory = builder.mEventCategory; + mEventType = builder.mEventType; + mEntityTypes = builder.mEntityTypes; + mEventContext = builder.mEventContext; + mResultId = builder.mResultId; + mEventIndex = builder.mEventIndex; + mScores = builder.mScores; + mModelName = builder.mModelName; + mActionIndices = builder.mActionIndices; + mExtras = builder.mExtras == null ? Bundle.EMPTY : builder.mExtras; + } - // Language detection. - @Nullable private final String mLanguage; - private final float mScore; - - @Nullable private final String mModelName; - - private TextClassifierEvent( - int eventCategory, - int eventType, - String[] entityTypes, - TextClassificationContext eventContext, - String resultId, - int eventIndex, - long eventTime, - Bundle extras, - int relativeWordStartIndex, - int relativeWordEndIndex, - int relativeSuggestedWordStartIndex, - int relativeSuggestedWordEndIndex, - int[] actionIndex, - String language, - float score, - String modelVersion) { - mEventCategory = eventCategory; - mEventType = eventType; - mEntityTypes = entityTypes; - mEventContext = eventContext; - mResultId = resultId; - mEventIndex = eventIndex; - mEventTime = eventTime; - mExtras = extras; - mRelativeWordStartIndex = relativeWordStartIndex; - mRelativeWordEndIndex = relativeWordEndIndex; - mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; - mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; - mActionIndices = actionIndex; - mLanguage = language; - mScore = score; - mModelName = modelVersion; + private TextClassifierEvent(Parcel in) { + mEventCategory = in.readInt(); + mEventType = in.readInt(); + mEntityTypes = in.readStringArray(); + mEventContext = in.readParcelable(null); + mResultId = in.readString(); + mEventIndex = in.readInt(); + int scoresLength = in.readInt(); + mScores = new float[scoresLength]; + in.readFloatArray(mScores); + mModelName = in.readString(); + mActionIndices = in.createIntArray(); + mExtras = in.readBundle(); } @Override @@ -183,44 +181,62 @@ public final class TextClassifierEvent implements Parcelable { return 0; } + @NonNull + public static final Creator<TextClassifierEvent> CREATOR = new Creator<TextClassifierEvent>() { + @Override + public TextClassifierEvent createFromParcel(Parcel in) { + int token = in.readInt(); + if (token == PARCEL_TOKEN_TEXT_SELECTION_EVENT) { + return new TextSelectionEvent(in); + } + if (token == PARCEL_TOKEN_TEXT_LINKIFY_EVENT) { + return new TextLinkifyEvent(in); + } + if (token == PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT) { + return new LanguageDetectionEvent(in); + } + if (token == PARCEL_TOKEN_CONVERSATION_ACTION_EVENT) { + return new ConversationActionsEvent(in); + } + throw new IllegalStateException("Unexpected input event type token in parcel."); + } + + @Override + public TextClassifierEvent[] newArray(int size) { + return new TextClassifierEvent[size]; + } + }; + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(getParcelToken()); dest.writeInt(mEventCategory); dest.writeInt(mEventType); dest.writeStringArray(mEntityTypes); dest.writeParcelable(mEventContext, flags); dest.writeString(mResultId); dest.writeInt(mEventIndex); - dest.writeLong(mEventTime); - dest.writeBundle(mExtras); - dest.writeInt(mRelativeWordStartIndex); - dest.writeInt(mRelativeWordEndIndex); - dest.writeInt(mRelativeSuggestedWordStartIndex); - dest.writeInt(mRelativeSuggestedWordEndIndex); - dest.writeIntArray(mActionIndices); - dest.writeString(mLanguage); - dest.writeFloat(mScore); + dest.writeInt(mScores.length); + dest.writeFloatArray(mScores); dest.writeString(mModelName); + dest.writeIntArray(mActionIndices); + dest.writeBundle(mExtras); } - private static TextClassifierEvent readFromParcel(Parcel in) { - return new TextClassifierEvent( - /* eventCategory= */ in.readInt(), - /* eventType= */ in.readInt(), - /* entityTypes=*/ in.readStringArray(), - /* eventContext= */ in.readParcelable(null), - /* resultId= */ in.readString(), - /* eventIndex= */ in.readInt(), - /* eventTime= */ in.readLong(), - /* extras= */ in.readBundle(), - /* relativeWordStartIndex= */ in.readInt(), - /* relativeWordEndIndex= */ in.readInt(), - /* relativeSuggestedWordStartIndex= */ in.readInt(), - /* relativeSuggestedWordEndIndex= */ in.readInt(), - /* actionIndices= */ in.createIntArray(), - /* language= */ in.readString(), - /* score= */ in.readFloat(), - /* modelVersion= */ in.readString()); + private int getParcelToken() { + if (this instanceof TextSelectionEvent) { + return PARCEL_TOKEN_TEXT_SELECTION_EVENT; + } + if (this instanceof TextLinkifyEvent) { + return PARCEL_TOKEN_TEXT_LINKIFY_EVENT; + } + if (this instanceof LanguageDetectionEvent) { + return PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT; + } + if (this instanceof ConversationActionsEvent) { + return PARCEL_TOKEN_CONVERSATION_ACTION_EVENT; + } + throw new IllegalArgumentException("Unexpected type: " + this.getClass().getSimpleName()); } /** @@ -241,6 +257,8 @@ public final class TextClassifierEvent implements Parcelable { /** * Returns an array of entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}. + * + * @see Builder#setEntityTypes(String...) for supported types. */ @NonNull public String[] getEntityTypes() { @@ -270,52 +288,20 @@ public final class TextClassifierEvent implements Parcelable { return mEventIndex; } - // TODO: Remove this API. /** - * Returns the time this event occurred. This is the number of milliseconds since - * January 1, 1970, 00:00:00 GMT. 0 indicates not set. - */ - public long getEventTime() { - return mEventTime; - } - - /** - * Returns a bundle containing non-structured extra information about this event. - * - * <p><b>NOTE: </b>Do not modify this bundle. + * Returns the scores of the suggestions. */ @NonNull - public Bundle getExtras() { - return mExtras; - } - - /** - * For smart selection. Returns the relative word index of the start of the selection. - */ - public int getRelativeWordStartIndex() { - return mRelativeWordStartIndex; - } - - /** - * For smart selection. Returns the relative word (exclusive) index of the end of the selection. - */ - public int getRelativeWordEndIndex() { - return mRelativeWordEndIndex; - } - - /** - * For smart selection. Returns the relative word index of the start of the smart selection. - */ - public int getRelativeSuggestedWordStartIndex() { - return mRelativeSuggestedWordStartIndex; + public float[] getScores() { + return mScores; } /** - * For smart selection. Returns the relative word (exclusive) index of the end of the - * smart selection. + * Returns the model name. */ - public int getRelativeSuggestedWordEndIndex() { - return mRelativeSuggestedWordEndIndex; + @Nullable + public String getModelName() { + return mModelName; } /** @@ -323,6 +309,8 @@ public final class TextClassifierEvent implements Parcelable { * Actions are usually returned by the text classifier in priority order with the most * preferred action at index 0. This list gives an indication of the position of the actions * that are being reported. + * + * @see Builder#setActionIndices(int...) */ @NonNull public int[] getActionIndices() { @@ -330,110 +318,158 @@ public final class TextClassifierEvent implements Parcelable { } /** - * For language detection. Returns the language tag for the detected locale. - * @see java.util.Locale#forLanguageTag(String). - */ - @Nullable - public String getLanguage() { - return mLanguage; - } - - /** - * Returns the score of the suggestion. + * Returns a bundle containing non-structured extra information about this event. + * + * <p><b>NOTE: </b>Do not modify this bundle. */ - public float getScore() { - return mScore; + @NonNull + public Bundle getExtras() { + return mExtras; } - /** - * Returns the model name. - * @hide - */ - @Nullable - public String getModelName() { - return mModelName; + @Override + public String toString() { + StringBuilder out = new StringBuilder(128); + out.append(this.getClass().getSimpleName()); + out.append("{"); + out.append("mEventCategory=").append(mEventCategory); + out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes)); + out.append(", mEventContext=").append(mEventContext); + out.append(", mResultId=").append(mResultId); + out.append(", mEventIndex=").append(mEventIndex); + out.append(", mExtras=").append(mExtras); + out.append(", mScores=").append(Arrays.toString(mScores)); + out.append(", mModelName=").append(mModelName); + out.append(", mActionIndices=").append(Arrays.toString(mActionIndices)); + out.append("}"); + return out.toString(); } /** * Builder to build a text classifier event. + * + * @param <T> The subclass to be built. */ - public static final class Builder { + public abstract static class Builder<T extends Builder<T>> { private final int mEventCategory; private final int mEventType; private String[] mEntityTypes = new String[0]; - @Nullable private TextClassificationContext mEventContext; - @Nullable private String mResultId; + @Nullable + private TextClassificationContext mEventContext; + @Nullable + private String mResultId; private int mEventIndex; - private long mEventTime; - @Nullable private Bundle mExtras; - private int mRelativeWordStartIndex; - private int mRelativeWordEndIndex; - private int mRelativeSuggestedWordStartIndex; - private int mRelativeSuggestedWordEndIndex; - private int[] mActionIndices = new int[0]; - @Nullable private String mLanguage; - private float mScore; - + private float[] mScores = new float[0]; + @Nullable private String mModelName; + private int[] mActionIndices = new int[0]; + @Nullable + private Bundle mExtras; /** * Creates a builder for building {@link TextClassifierEvent}s. * * @param eventCategory The event category. e.g. {@link #CATEGORY_SELECTION} - * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED} + * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED} */ - public Builder(@Category int eventCategory, @Type int eventType) { + private Builder(@Category int eventCategory, @Type int eventType) { mEventCategory = eventCategory; mEventType = eventType; } /** * Sets the entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}. + * <p> + * Supported types: + * <p>See {@link TextClassifier.EntityType} + * <p>See {@link ConversationAction.ActionType} + * <p>See {@link ULocale#toLanguageTag()} */ @NonNull - public Builder setEntityTypes(@NonNull String... entityTypes) { + public T setEntityTypes(@NonNull String... entityTypes) { + Preconditions.checkNotNull(entityTypes); mEntityTypes = new String[entityTypes.length]; System.arraycopy(entityTypes, 0, mEntityTypes, 0, entityTypes.length); - return this; + return self(); } /** * Sets the event context. */ @NonNull - public Builder setEventContext(@Nullable TextClassificationContext eventContext) { + public T setEventContext(@Nullable TextClassificationContext eventContext) { mEventContext = eventContext; - return this; + return self(); } /** * Sets the id of the text classifier result related to this event. */ @NonNull - public Builder setResultId(@Nullable String resultId) { + public T setResultId(@Nullable String resultId) { mResultId = resultId; - return this; + return self(); } /** - * Sets the index of this events in the series of events it belongs to. + * Sets the index of this event in the series of events it belongs to. */ @NonNull - public Builder setEventIndex(int eventIndex) { + public T setEventIndex(int eventIndex) { mEventIndex = eventIndex; - return this; + return self(); + } + + /** + * Sets the scores of the suggestions. + */ + @NonNull + public T setScores(@NonNull float... scores) { + Preconditions.checkNotNull(scores); + mScores = new float[scores.length]; + System.arraycopy(scores, 0, mScores, 0, scores.length); + return self(); } - // TODO: Remove this API. /** - * Sets the time this event occurred. This is the number of milliseconds since - * January 1, 1970, 00:00:00 GMT. 0 indicates not set. + * Sets the model name string. */ @NonNull - public Builder setEventTime(long eventTime) { - mEventTime = eventTime; - return this; + public T setModelName(@Nullable String modelVersion) { + mModelName = modelVersion; + return self(); + } + + /** + * Sets the indices of the actions involved in this event. Actions are usually returned by + * the text classifier in priority order with the most preferred action at index 0. + * These indices give an indication of the position of the actions that are being reported. + * <p> + * E.g. + * <pre> + * // 3 smart actions are shown at index 0, 1, 2 respectively in response to a link click. + * new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_ACTIONS_SHOWN) + * .setEventIndex(0, 1, 2) + * ... + * .build(); + * + * ... + * + * // Smart action at index 1 is activated. + * new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_SMART_ACTION) + * .setEventIndex(1) + * ... + * .build(); + * </pre> + * + * @see TextClassification#getActions() + */ + @NonNull + public T setActionIndices(@NonNull int... actionIndices) { + mActionIndices = new int[actionIndices.length]; + System.arraycopy(actionIndices, 0, mActionIndices, 0, actionIndices.length); + return self(); } /** @@ -445,136 +481,545 @@ public final class TextClassifierEvent implements Parcelable { * objects in this bundle. */ @NonNull - public Builder setExtras(@NonNull Bundle extras) { + public T setExtras(@NonNull Bundle extras) { mExtras = Preconditions.checkNotNull(extras); - return this; + return self(); + } + + abstract T self(); + } + + /** + * This class represents events that are related to the smart text selection feature. + * <p> + * <pre> + * // User started a selection. e.g. "York" in text "New York City, NY". + * new TextSelectionEvent.Builder(TYPE_SELECTION_STARTED) + * .setEventContext(classificationContext) + * .setEventIndex(0) + * .build(); + * + * // System smart-selects a recognized entity. e.g. "New York City". + * new TextSelectionEvent.Builder(TYPE_SMART_SELECTION_MULTI) + * .setEventContext(classificationContext) + * .setResultId(textSelection.getId()) + * .setRelativeWordStartIndex(-1) // Goes back one word to "New" from "York". + * .setRelativeWordEndIndex(2) // Goes forward 2 words from "York" to start of ",". + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(1) + * .build(); + * + * // User resets the selection to the original selection. i.e. "York". + * new TextSelectionEvent.Builder(TYPE_SELECTION_RESET) + * .setEventContext(classificationContext) + * .setResultId(textSelection.getId()) + * .setRelativeSuggestedWordStartIndex(-1) // Repeated from above. + * .setRelativeSuggestedWordEndIndex(2) // Repeated from above. + * .setRelativeWordStartIndex(0) // Original selection is always at (0, 1]. + * .setRelativeWordEndIndex(1) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(2) + * .build(); + * + * // User modified the selection. e.g. "New". + * new TextSelectionEvent.Builder(TYPE_SELECTION_MODIFIED) + * .setEventContext(classificationContext) + * .setResultId(textSelection.getId()) + * .setRelativeSuggestedWordStartIndex(-1) // Repeated from above. + * .setRelativeSuggestedWordEndIndex(2) // Repeated from above. + * .setRelativeWordStartIndex(-1) // Goes backward one word from "York" to + * "New". + * .setRelativeWordEndIndex(0) // Goes backward one word to exclude "York". + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(3) + * .build(); + * + * // Smart (contextual) actions (at indices, 0, 1, 2) presented to the user. + * // e.g. "Map", "Ride share", "Explore". + * new TextSelectionEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(0, 1, 2) + * .setEventIndex(4) + * .build(); + * + * // User chooses the "Copy" action. + * new TextSelectionEvent.Builder(TYPE_COPY_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(5) + * .build(); + * + * // User chooses smart action at index 1. i.e. "Ride share". + * new TextSelectionEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(1) + * .setEventIndex(5) + * .build(); + * + * // Selection dismissed. + * new TextSelectionEvent.Builder(TYPE_SELECTION_DESTROYED) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(6) + * .build(); + * </pre> + * <p> + */ + public static final class TextSelectionEvent extends TextClassifierEvent implements Parcelable { + + @NonNull + public static final Creator<TextSelectionEvent> CREATOR = + new Creator<TextSelectionEvent>() { + @Override + public TextSelectionEvent createFromParcel(Parcel in) { + in.readInt(); // skip token, we already know this is a TextSelectionEvent + return new TextSelectionEvent(in); + } + + @Override + public TextSelectionEvent[] newArray(int size) { + return new TextSelectionEvent[size]; + } + }; + + final int mRelativeWordStartIndex; + final int mRelativeWordEndIndex; + final int mRelativeSuggestedWordStartIndex; + final int mRelativeSuggestedWordEndIndex; + + private TextSelectionEvent(TextSelectionEvent.Builder builder) { + super(builder); + mRelativeWordStartIndex = builder.mRelativeWordStartIndex; + mRelativeWordEndIndex = builder.mRelativeWordEndIndex; + mRelativeSuggestedWordStartIndex = builder.mRelativeSuggestedWordStartIndex; + mRelativeSuggestedWordEndIndex = builder.mRelativeSuggestedWordEndIndex; + } + + private TextSelectionEvent(Parcel in) { + super(in); + mRelativeWordStartIndex = in.readInt(); + mRelativeWordEndIndex = in.readInt(); + mRelativeSuggestedWordStartIndex = in.readInt(); + mRelativeSuggestedWordEndIndex = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(mRelativeWordStartIndex); + dest.writeInt(mRelativeWordEndIndex); + dest.writeInt(mRelativeSuggestedWordStartIndex); + dest.writeInt(mRelativeSuggestedWordEndIndex); } /** - * For smart selection. Sets the relative word index of the start of the selection. + * Returns the relative word index of the start of the selection. */ - @NonNull - public Builder setRelativeWordStartIndex(int relativeWordStartIndex) { - mRelativeWordStartIndex = relativeWordStartIndex; - return this; + public int getRelativeWordStartIndex() { + return mRelativeWordStartIndex; } /** - * For smart selection. Sets the relative word (exclusive) index of the end of the - * selection. + * Returns the relative word (exclusive) index of the end of the selection. */ - @NonNull - public Builder setRelativeWordEndIndex(int relativeWordEndIndex) { - mRelativeWordEndIndex = relativeWordEndIndex; - return this; + public int getRelativeWordEndIndex() { + return mRelativeWordEndIndex; } /** - * For smart selection. Sets the relative word index of the start of the smart selection. + * Returns the relative word index of the start of the smart selection. */ - @NonNull - public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) { - mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; - return this; + public int getRelativeSuggestedWordStartIndex() { + return mRelativeSuggestedWordStartIndex; } /** - * For smart selection. Sets the relative word (exclusive) index of the end of the + * Returns the relative word (exclusive) index of the end of the * smart selection. */ - @NonNull - public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) { - mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; - return this; + public int getRelativeSuggestedWordEndIndex() { + return mRelativeSuggestedWordEndIndex; } /** - * Sets the indices of the actions involved in this event. Actions are usually returned by - * the text classifier in priority order with the most preferred action at index 0. - * This index gives an indication of the position of the action that is being reported. + * Builder class for {@link TextSelectionEvent}. */ + public static final class Builder extends + TextClassifierEvent.Builder<TextSelectionEvent.Builder> { + int mRelativeWordStartIndex; + int mRelativeWordEndIndex; + int mRelativeSuggestedWordStartIndex; + int mRelativeSuggestedWordEndIndex; + + /** + * Creates a builder for building {@link TextSelectionEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED} + */ + public Builder(@Type int eventType) { + super(CATEGORY_SELECTION, eventType); + } + + /** + * Sets the relative word index of the start of the selection. + */ + @NonNull + public Builder setRelativeWordStartIndex(int relativeWordStartIndex) { + mRelativeWordStartIndex = relativeWordStartIndex; + return this; + } + + /** + * Sets the relative word (exclusive) index of the end of the + * selection. + */ + @NonNull + public Builder setRelativeWordEndIndex(int relativeWordEndIndex) { + mRelativeWordEndIndex = relativeWordEndIndex; + return this; + } + + /** + * Sets the relative word index of the start of the smart + * selection. + */ + @NonNull + public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) { + mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; + return this; + } + + /** + * Sets the relative word (exclusive) index of the end of the + * smart selection. + */ + @NonNull + public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) { + mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; + return this; + } + + @Override + TextSelectionEvent.Builder self() { + return this; + } + + /** + * Builds and returns a {@link TextSelectionEvent}. + */ + @NonNull + public TextSelectionEvent build() { + return new TextSelectionEvent(this); + } + } + } + + /** + * This class represents events that are related to the smart linkify feature. + * <p> + * <pre> + * // User clicked on a link. + * new TextLinkifyEvent.Builder(TYPE_LINK_CLICKED) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(0) + * .build(); + * + * // Smart (contextual) actions presented to the user in response to a link click. + * new TextLinkifyEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(range(textClassification.getActions().size())) + * .setEventIndex(1) + * .build(); + * + * // User chooses smart action at index 0. + * new TextLinkifyEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(0) + * .setEventIndex(2) + * .build(); + * </pre> + */ + public static final class TextLinkifyEvent extends TextClassifierEvent implements Parcelable { + @NonNull - public Builder setActionIndices(@NonNull int... actionIndices) { - mActionIndices = new int[actionIndices.length]; - System.arraycopy(actionIndices, 0, mActionIndices, 0, actionIndices.length); - return this; + public static final Creator<TextLinkifyEvent> CREATOR = + new Creator<TextLinkifyEvent>() { + @Override + public TextLinkifyEvent createFromParcel(Parcel in) { + in.readInt(); // skip token, we already know this is a TextLinkifyEvent + return new TextLinkifyEvent(in); + } + + @Override + public TextLinkifyEvent[] newArray(int size) { + return new TextLinkifyEvent[size]; + } + }; + + private TextLinkifyEvent(Parcel in) { + super(in); + } + + private TextLinkifyEvent(TextLinkifyEvent.Builder builder) { + super(builder); } /** - * For language detection. Sets the language tag for the detected locale. - * @see java.util.Locale#forLanguageTag(String). + * Builder class for {@link TextLinkifyEvent}. */ + public static final class Builder + extends TextClassifierEvent.Builder<TextLinkifyEvent.Builder> { + /** + * Creates a builder for building {@link TextLinkifyEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION} + */ + public Builder(@Type int eventType) { + super(TextClassifierEvent.CATEGORY_LINKIFY, eventType); + } + + @Override + Builder self() { + return this; + } + + /** + * Builds and returns a {@link TextLinkifyEvent}. + */ + @NonNull + public TextLinkifyEvent build() { + return new TextLinkifyEvent(this); + } + } + } + + /** + * This class represents events that are related to the language detection feature. + * <p> + * <pre> + * // Translate action shown for foreign text. + * new LanguageDetectionEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(language) + * .setScore(score) + * .setActionIndices(textClassification.getActions().indexOf(translateAction)) + * .setEventIndex(0) + * .build(); + * + * // Translate action selected. + * new LanguageDetectionEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(language) + * .setScore(score) + * .setActionIndices(textClassification.getActions().indexOf(translateAction)) + * .setEventIndex(1) + * .build(); + */ + public static final class LanguageDetectionEvent extends TextClassifierEvent + implements Parcelable { + @NonNull - public Builder setLanguage(@Nullable String language) { - mLanguage = language; - return this; + public static final Creator<LanguageDetectionEvent> CREATOR = + new Creator<LanguageDetectionEvent>() { + @Override + public LanguageDetectionEvent createFromParcel(Parcel in) { + // skip token, we already know this is a LanguageDetectionEvent. + in.readInt(); + return new LanguageDetectionEvent(in); + } + + @Override + public LanguageDetectionEvent[] newArray(int size) { + return new LanguageDetectionEvent[size]; + } + }; + + @Nullable + private final ULocale mLocale; + + private LanguageDetectionEvent(Parcel in) { + super(in); + final String languageTag = in.readString(); + mLocale = languageTag == null ? null : ULocale.forLanguageTag(languageTag); + } + + private LanguageDetectionEvent(LanguageDetectionEvent.Builder builder) { + super(builder); + mLocale = builder.mLocale; } /** - * Sets the score of the suggestion. + * Returns the detected locale. */ - @NonNull - public Builder setScore(float score) { - mScore = score; - return this; + @Nullable + public ULocale getLocale() { + return mLocale; } /** - * Sets the model name string. - * @hide + * Builder class for {@link LanguageDetectionEvent}. */ - public Builder setModelName(@Nullable String modelVersion) { - mModelName = modelVersion; - return this; + public static final class Builder + extends TextClassifierEvent.Builder<LanguageDetectionEvent.Builder> { + @Nullable + private ULocale mLocale; + + /** + * Creates a builder for building {@link TextSelectionEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION} + */ + public Builder(@Type int eventType) { + super(TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType); + } + + /** + * Sets the detected locale. + */ + @NonNull + public Builder setLocale(@Nullable ULocale locale) { + mLocale = locale; + return this; + } + + @Override + Builder self() { + return this; + } + + /** + * Builds and returns a {@link LanguageDetectionEvent}. + */ + @NonNull + public LanguageDetectionEvent build() { + return new LanguageDetectionEvent(this); + } + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(mLocale == null ? null : mLocale.toLanguageTag()); + } + } + + /** + * This class represents events that are related to the conversation actions feature. + * <p> + * <pre> + * // Conversation (contextual) actions/replies generated. + * new ConversationActionsEvent.Builder(TYPE_ACTIONS_GENERATED) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEntityTypes(getTypes(conversationActions)) + * .setActionIndices(range(conversationActions.getActions().size())) + * .setEventIndex(0) + * .build(); + * + * // Conversation actions/replies presented to user. + * new ConversationActionsEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEntityTypes(getTypes(conversationActions)) + * .setActionIndices(range(conversationActions.getActions().size())) + * .setEventIndex(1) + * .build(); + * + * // User clicked the "Reply" button to compose their custom reply. + * new ConversationActionsEvent.Builder(TYPE_MANUAL_REPLY) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEventIndex(2) + * .build(); + * + * // User selected a smart (contextual) action/reply. + * new ConversationActionsEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEntityTypes(conversationActions.get(1).getType()) + * .setScore(conversationAction.get(1).getConfidenceScore()) + * .setActionIndices(1) + * .setEventIndex(2) + * .build(); + * </pre> + */ + public static final class ConversationActionsEvent extends TextClassifierEvent + implements Parcelable { + + @NonNull + public static final Creator<ConversationActionsEvent> CREATOR = + new Creator<ConversationActionsEvent>() { + @Override + public ConversationActionsEvent createFromParcel(Parcel in) { + // skip token, we already know this is a ConversationActionsEvent. + in.readInt(); + return new ConversationActionsEvent(in); + } + + @Override + public ConversationActionsEvent[] newArray(int size) { + return new ConversationActionsEvent[size]; + } + }; + + private ConversationActionsEvent(Parcel in) { + super(in); + } + + private ConversationActionsEvent(ConversationActionsEvent.Builder builder) { + super(builder); } /** - * Builds and returns a text classifier event. + * Builder class for {@link ConversationActionsEvent}. */ - @NonNull - public TextClassifierEvent build() { - mExtras = mExtras == null ? Bundle.EMPTY : mExtras; - return new TextClassifierEvent( - mEventCategory, - mEventType, - mEntityTypes, - mEventContext, - mResultId, - mEventIndex, - mEventTime, - mExtras, - mRelativeWordStartIndex, - mRelativeWordEndIndex, - mRelativeSuggestedWordStartIndex, - mRelativeSuggestedWordEndIndex, - mActionIndices, - mLanguage, - mScore, - mModelName); - } - // TODO: Add build(boolean validate). - } + public static final class Builder + extends TextClassifierEvent.Builder<ConversationActionsEvent.Builder> { + /** + * Creates a builder for building {@link TextSelectionEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION} + */ + public Builder(@Type int eventType) { + super(TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType); + } - @Override - public String toString() { - StringBuilder out = new StringBuilder(128); - out.append("TextClassifierEvent{"); - out.append("mEventCategory=").append(mEventCategory); - out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes)); - out.append(", mEventContext=").append(mEventContext); - out.append(", mResultId=").append(mResultId); - out.append(", mEventIndex=").append(mEventIndex); - out.append(", mEventTime=").append(mEventTime); - out.append(", mExtras=").append(mExtras); - out.append(", mRelativeWordStartIndex=").append(mRelativeWordStartIndex); - out.append(", mRelativeWordEndIndex=").append(mRelativeWordEndIndex); - out.append(", mRelativeSuggestedWordStartIndex=").append(mRelativeSuggestedWordStartIndex); - out.append(", mRelativeSuggestedWordEndIndex=").append(mRelativeSuggestedWordEndIndex); - out.append(", mActionIndices=").append(Arrays.toString(mActionIndices)); - out.append(", mLanguage=").append(mLanguage); - out.append(", mScore=").append(mScore); - out.append(", mModelName=").append(mModelName); - out.append("}"); - return out.toString(); + @Override + Builder self() { + return this; + } + + /** + * Builds and returns a {@link ConversationActionsEvent}. + */ + @NonNull + public ConversationActionsEvent build() { + return new ConversationActionsEvent(this); + } + } } } diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java index 6a122506d0ac..3e088b8565f2 100644 --- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java +++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java @@ -65,9 +65,10 @@ public final class TextClassifierEventTronLogger { final LogMaker log = new LogMaker(category) .setSubtype(getLogType(event)) .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId()) - .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event)) - .addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScore()); - + .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event)); + if (event.getScores().length >= 1) { + log.addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScores()[0]); + } String[] entityTypes = event.getEntityTypes(); // The old logger does not support a field of list type, and thus workaround by store them // in three separate fields. This is not an issue with the new logger. diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 323bf597ab55..3297523b0da9 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -307,6 +307,8 @@ public final class TextClassifierImpl implements TextClassifier { final String detectLanguageTags = detectLanguageTagsFromText(request.getText()); final AnnotatorModel annotatorImpl = getAnnotatorImpl(request.getDefaultLocales()); + final boolean isSerializedEntityDataEnabled = + ExtrasUtils.isSerializedEntityDataEnabled(request); final AnnotatorModel.AnnotatedSpan[] annotations = annotatorImpl.annotate( textString, @@ -314,7 +316,10 @@ public final class TextClassifierImpl implements TextClassifier { refTime.toInstant().toEpochMilli(), refTime.getZone().getId(), localesString, - detectLanguageTags)); + detectLanguageTags, + entitiesToIdentify, + AnnotatorModel.AnnotationUsecase.SMART.getValue(), + isSerializedEntityDataEnabled)); for (AnnotatorModel.AnnotatedSpan span : annotations) { final AnnotatorModel.ClassificationResult[] results = span.getClassification(); @@ -326,7 +331,11 @@ public final class TextClassifierImpl implements TextClassifier { for (int i = 0; i < results.length; i++) { entityScores.put(results[i].getCollection(), results[i].getScore()); } - builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores); + Bundle extras = new Bundle(); + if (isSerializedEntityDataEnabled) { + ExtrasUtils.putEntities(extras, results); + } + builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores, extras); } final TextLinks links = builder.build(); final long endTimeMs = System.currentTimeMillis(); @@ -451,10 +460,6 @@ public final class TextClassifierImpl implements TextClassifier { Collection<String> expectedTypes = resolveActionTypesFromRequest(request); List<ConversationAction> conversationActions = new ArrayList<>(); for (ActionsSuggestionsModel.ActionSuggestion nativeSuggestion : nativeSuggestions) { - if (request.getMaxSuggestions() >= 0 - && conversationActions.size() == request.getMaxSuggestions()) { - break; - } String actionType = nativeSuggestion.getActionType(); if (!expectedTypes.contains(actionType)) { continue; @@ -484,6 +489,10 @@ public final class TextClassifierImpl implements TextClassifier { } conversationActions = ActionsSuggestionsHelper.removeActionsWithDuplicates(conversationActions); + if (request.getMaxSuggestions() >= 0 + && conversationActions.size() > request.getMaxSuggestions()) { + conversationActions = conversationActions.subList(0, request.getMaxSuggestions()); + } String resultId = ActionsSuggestionsHelper.createResultId( mContext, request.getConversation(), diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 564cfdd20d76..51ca80524090 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -933,12 +933,11 @@ public final class SelectionActionModeHelper { final String language = ExtrasUtils.getEntityType(foreignLanguageExtra); final float score = ExtrasUtils.getScore(foreignLanguageExtra); final String model = ExtrasUtils.getModelName(foreignLanguageExtra); - return new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType) + return new TextClassifierEvent.LanguageDetectionEvent.Builder(eventType) .setEventContext(classificationContext) .setResultId(classification.getId()) .setEntityTypes(language) - .setScore(score) + .setScores(score) .setActionIndices(classification.getActions().indexOf(translateAction)) .setModelName(model) .build(); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index ed851f86889d..54338bf6a176 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -2658,12 +2658,24 @@ public class ChooserActivity extends ResolverActivity { } } + /** + * Need to merge CALLER + ranked STANDARD into a single row. All other types + * are placed into their own row as determined by their target type, and dividers + * are added in the list to separate each type. + */ + int getRowType(int rowPosition) { + int positionType = mChooserListAdapter.getPositionTargetType(rowPosition); + if (positionType == ChooserListAdapter.TARGET_CALLER) { + return ChooserListAdapter.TARGET_STANDARD; + } + + return positionType; + } + void bindViewHolder(int rowPosition, RowViewHolder holder) { final int start = getFirstRowPosition(rowPosition); - final int startType = mChooserListAdapter.getPositionTargetType(start); - - final int lastStartType = mChooserListAdapter.getPositionTargetType( - getFirstRowPosition(rowPosition - 1)); + final int startType = getRowType(start); + final int lastStartType = getRowType(getFirstRowPosition(rowPosition - 1)); final ViewGroup row = holder.getViewGroup(); @@ -2675,7 +2687,7 @@ public class ChooserActivity extends ResolverActivity { int columnCount = holder.getColumnCount(); int end = start + columnCount - 1; - while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) { + while (getRowType(end) != startType && end >= start) { end--; } @@ -2727,14 +2739,15 @@ public class ChooserActivity extends ResolverActivity { return row * getMaxTargetsPerRow(); } - final int callerCount = mChooserListAdapter.getCallerTargetCount(); - final int callerRows = (int) Math.ceil((float) callerCount / getMaxTargetsPerRow()); - if (row < callerRows + serviceRows) { + final int callerAndRankedCount = mChooserListAdapter.getCallerTargetCount() + + mChooserListAdapter.getRankedTargetCount(); + final int callerAndRankedRows = getCallerAndRankedTargetRowCount(); + if (row < callerAndRankedRows + serviceRows) { return serviceCount + (row - serviceRows) * getMaxTargetsPerRow(); } - return callerCount + serviceCount - + (row - callerRows - serviceRows) * getMaxTargetsPerRow(); + return callerAndRankedCount + serviceCount + + (row - callerAndRankedRows - serviceRows) * getMaxTargetsPerRow(); } public void handleScroll(View v, int y, int oldy) { diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index fd75f4fa4567..21f8d87e7e8c 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -45,6 +45,7 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Color; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.session.MediaController; @@ -115,6 +116,7 @@ import com.android.internal.widget.SwipeDismissLayout; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.List; /** * Android-specific Window. @@ -3926,4 +3928,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public WindowInsetsController getInsetsController() { return mDecor.getWindowInsetsController(); } + + @Override + public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { + getViewRootImpl().setRootSystemGestureExclusionRects(rects); + } + + @Override + @NonNull + public List<Rect> getSystemGestureExclusionRects() { + return getViewRootImpl().getRootSystemGestureExclusionRects(); + } } diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp index a62dd7c4048f..1e6d49e49b72 100644 --- a/core/jni/android_nio_utils.cpp +++ b/core/jni/android_nio_utils.cpp @@ -18,51 +18,29 @@ #include "core_jni_helpers.h" -namespace { +namespace android { -void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) { - assert(array); - jint position; - jint limit; - jint elementSizeShift; - jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); +AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) + : fEnv(env), fCommit(commit) { + jlong pointer = jniGetNioBufferPointer(fEnv, nioBuffer); if (pointer != 0L) { - *array = nullptr; - *elements = nullptr; - pointer += position << elementSizeShift; - return reinterpret_cast<void*>(pointer); + // Buffer is backed by a direct buffer. + fArray = nullptr; + fElements = nullptr; + fPointer = reinterpret_cast<void*>(pointer); + } else { + // Buffer is backed by a managed array. + jint byteOffset = jniGetNioBufferBaseArrayOffset(fEnv, nioBuffer); + fArray = jniGetNioBufferBaseArray(fEnv, nioBuffer); + fElements = fEnv->GetPrimitiveArrayCritical(fArray, /* isCopy= */ nullptr); + fPointer = reinterpret_cast<void*>(reinterpret_cast<char*>(fElements) + byteOffset); } - jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer); - *array = jniGetNioBufferBaseArray(_env, buffer); - *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset); } -void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) { - _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT); -} - -} // namespace - -void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { - void* elements; - return getPointer(_env, buffer, array, &elements); -} - -void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { - releasePointer(_env, array, data, commit); -} - -/////////////////////////////////////////////////////////////////////////////// - -android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) { - fEnv = env; - fCommit = commit; - fPointer = getPointer(env, nioBuffer, &fArray, &fElements); -} - -android::AutoBufferPointer::~AutoBufferPointer() { +AutoBufferPointer::~AutoBufferPointer() { if (nullptr != fArray) { - releasePointer(fEnv, fArray, fElements, fCommit); + fEnv->ReleasePrimitiveArrayCritical(fArray, fElements, fCommit ? 0 : JNI_ABORT); } } + +} // namespace android diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h index 7c9acd2638da..aa75dd0c7e32 100644 --- a/core/jni/android_nio_utils.h +++ b/core/jni/android_nio_utils.h @@ -22,51 +22,58 @@ namespace android { /** - * Given an nio.Buffer, return a pointer to it, beginning at its current - * position. The returned pointer is only valid for the current JNI stack-frame. - * For performance, it does not create any global references, so the getPointer - * (and releasePointer if array is returned non-null) must be done in the - * same JNI stack-frame. + * Class providing scoped access to the memory backing a java.nio.Buffer instance. * - * @param env The current JNI env - * @param buffer The nio.Buffer object - * @param array REQUIRED. Output. If on return it is set to non-null, then - * nio_releasePointer must be called with the array - * and the returned pointer when the caller is through with it. - * If on return it is set to null, do not call - * nio_releasePointer. - * @return The pointer to the memory in the buffer object - */ -void* nio_getPointer(JNIEnv *env, jobject buffer, jarray *array); - -/** - * Call this if android_nio_getPointer returned non-null in its array parameter. - * Pass that array and the returned pointer when you are done accessing the - * pointer. If called (i.e. array is non-null), it must be called in the same - * JNI stack-frame as getPointer + * Instances of this class should only be allocated on the stack as heap allocation is not + * supported. * - * @param env The current JNI env - * @param buffer The array returned from android_nio_getPointer (!= null) - * @param pointer The pointer returned by android_nio_getPointer - * @param commit JNI_FALSE if the pointer was just read, and JNI_TRUE if - * the pointer was written to. + * Instances of this class do not create any global references for performance reasons. */ -void nio_releasePointer(JNIEnv *env, jarray array, void *pointer, - jboolean commit); - -class AutoBufferPointer { +class AutoBufferPointer final { public: + /** Constructor for an AutoBufferPointer instance. + * + * @param env The current JNI env + * @param nioBuffer Instance of a java.nio.Buffer whose memory will be accessed. + * @param commit JNI_TRUE if the underlying memory will be updated and should be + * copied back to the managed heap. JNI_FALSE if the data will + * not be modified or the modifications may be discarded. + * + * The commit parameter is only applicable if the buffer is backed by a managed heap + * array and the runtime had to provide a copy of the data rather than the original data. + */ AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit); + + /** Destructor for an AutoBufferPointer instance. + * + * Releases critical managed heap array pointer if acquired. + */ ~AutoBufferPointer(); + /** + * Returns a pointer to the current position of the buffer provided to the constructor. This + * pointer is only valid whilst the AutoBufferPointer instance remains in scope. + */ void* pointer() const { return fPointer; } private: - JNIEnv* fEnv; - void* fPointer; // pointer to current buffer position. - void* fElements; // pointer to array element 0 (may be directly in fArray or a copy). - jarray fArray; // pointer to array on managed heap. - jboolean fCommit; // commit data to source if required (when fElements is a copy of fArray). + JNIEnv* const fEnv; + void* fPointer; // Pointer to current buffer position when constructed. + void* fElements; // Pointer to array element 0 (null if buffer is direct, may be + // within fArray or point to a copy of the array). + jarray fArray; // Pointer to array on managed heap. + const jboolean fCommit; // Flag to commit data to source (when fElements is a copy of fArray). + + // Unsupported constructors and operators. + AutoBufferPointer() = delete; + AutoBufferPointer(AutoBufferPointer&) = delete; + AutoBufferPointer& operator=(AutoBufferPointer&) = delete; + static void* operator new(std::size_t); + static void* operator new[](std::size_t); + static void* operator new(std::size_t, void*); + static void* operator new[](std::size_t, void*); + static void operator delete(void*, std::size_t); + static void operator delete[](void*, std::size_t); }; } /* namespace android */ diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index f599913ce497..e2214d160fdc 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -73,6 +73,7 @@ #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> +#include <bionic_malloc.h> #include <cutils/ashmem.h> #include <cutils/fs.h> #include <cutils/multiuser.h> @@ -499,12 +500,9 @@ static void EnableDebugger() { } } -// The debug malloc library needs to know whether it's the zygote or a child. -extern "C" int gMallocLeakZygoteChild; - static void PreApplicationInit() { // The child process sets this to indicate it's not the zygote. - gMallocLeakZygoteChild = 1; + android_mallopt(M_SET_ZYGOTE_CHILD, nullptr, 0); // Set the jemalloc decay time to 1. mallopt(M_DECAY_TIME, 1); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index cc3b3a4c7ccb..8714bf2505bb 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -828,6 +828,7 @@ android:permissionGroup="android.permission-group.UNDEFINED" android:label="@string/permlab_sdcardRead" android:description="@string/permdesc_sdcardRead" + android:permissionFlags="softRestricted|immutablyRestricted" android:protectionLevel="dangerous" /> <!-- Allows an application to write to external storage. @@ -848,6 +849,7 @@ android:permissionGroup="android.permission-group.UNDEFINED" android:label="@string/permlab_sdcardWrite" android:description="@string/permdesc_sdcardWrite" + android:permissionFlags="softRestricted|immutablyRestricted" android:protectionLevel="dangerous" /> <!-- Allows an application to access any geographic locations persisted in the diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index bfa57e46984b..bbc784a10db3 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -328,6 +328,12 @@ would be granted. The weak grant depends on the permission. --> <flag name="softRestricted" value="0x8" /> + <!-- This permission is restricted immutably which means that its + restriction state may be specified only on the first install of + the app and will stay in this initial whitelist state until + the app is uninstalled. + --> + <flag name="immutablyRestricted" value="0x10" /> </attr> <!-- Specified the name of a group that this permission is associated @@ -1707,17 +1713,18 @@ See {@link android.media.AudioPlaybackCaptureConfiguration} for more detail. --> <attr name="allowAudioPlaybackCapture" format="boolean" /> - <!-- If {@code true} this app allows shared/external storage media to be - a sandboxed view that only contains files owned by the app. - <p> - Sandboxed apps can continue to discover and read media belonging to other - apps via {@code MediaStore}. + <!-- If {@code true} this app would like to run under the legacy storage + model. Note that this may not always be respected due to policy or + backwards compatibility reasons. + + <p>Apps not requesting legacy storage can continue to discover and + read media belonging to other apps via {@code MediaStore}. <p> The default value is: - - {@code true} for apps with targetSdkVersion >= 29 (Q). - - {@code false} for apps with targetSdkVersion < 29. + - {@code false} for apps with targetSdkVersion >= 29 (Q). + - {@code true} for apps with targetSdkVersion < 29. --> - <attr name="allowExternalStorageSandbox" format="boolean" /> + <attr name="requestLegacyExternalStorage" format="boolean" /> </declare-styleable> <!-- The <code>permission</code> tag declares a security permission that can be used to control access from other packages to specific components or diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 526818949b3d..4d6fda980755 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3483,6 +3483,12 @@ <item>com.android.messaging</item> </string-array> + <!-- An array of packages that can make sound on the ringer stream in priority-only DND + mode --> + <string-array translatable="false" name="config_priorityOnlyDndExemptPackages"> + <item>com.android.dialer</item> + </string-array> + <!-- An array of packages which can listen for notifications on low ram devices. --> <string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" /> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index b7d61c8f8d39..a7af144ab9ed 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2942,7 +2942,7 @@ <public name="allowClearUserDataOnFailedRestore"/> <public name="allowAudioPlaybackCapture"/> <public name="secureElementName" /> - <public name="allowExternalStorageSandbox"/> + <public name="requestLegacyExternalStorage"/> <public name="ensuringStatusBarContrastWhenTransparent" /> <public name="ensuringNavigationBarContrastWhenTransparent" /> <public name="identifier" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 94b5da6baa07..924b036813a6 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3188,6 +3188,7 @@ <java-symbol type="array" name="config_convert_to_emergency_number_map" /> <java-symbol type="array" name="config_nonBlockableNotificationPackages" /> + <java-symbol type="array" name="config_priorityOnlyDndExemptPackages" /> <java-symbol type="array" name="config_allowedManagedServicesOnLowRamDevices" /> diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java index 4bee24385cc5..2280cf1cccfa 100644 --- a/core/tests/coretests/src/android/graphics/BitmapTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapTest.java @@ -23,6 +23,8 @@ import androidx.test.filters.SmallTest; import junit.framework.TestCase; import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; public class BitmapTest extends TestCase { @@ -266,10 +268,11 @@ public class BitmapTest extends TestCase { } @SmallTest - public void testCopyWithDirectBuffer() { + public void testCopyWithDirectByteBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; + final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); @@ -277,7 +280,8 @@ public class BitmapTest extends TestCase { // of bitmap. final int pad = 1; final byte padValue = 0x5a; - final int bufferSize = pad + width * height * 2 + pad; + final int bytesPerElement = 1; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); // Write padding @@ -287,7 +291,8 @@ public class BitmapTest extends TestCase { // Copy bitmap directBuffer.position(pad); bm1.copyPixelsToBuffer(directBuffer); - assertEquals(directBuffer.position(), pad + width * height * 2); + assertEquals(directBuffer.position(), + pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(directBuffer.get(0), padValue); @@ -301,10 +306,89 @@ public class BitmapTest extends TestCase { } @SmallTest - public void testCopyWithHeapBuffer() { + public void testCopyWithDirectShortBuffer() { // Initialize Bitmap final int width = 2; final int height = 2; + final int bytesPerPixel = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final short padValue = 0x55aa; + final int bytesPerElement = 2; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + ShortBuffer directBuffer = + ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asShortBuffer(); + + // Write padding + directBuffer.put(0, padValue); + directBuffer.put(directBuffer.limit() - 1, padValue); + + // Copy bitmap + directBuffer.position(pad); + bm1.copyPixelsToBuffer(directBuffer); + assertEquals(directBuffer.position(), + pad + width * height * bytesPerPixel / bytesPerElement); + + // Check padding + assertEquals(directBuffer.get(0), padValue); + assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); + + // Create bitmap from heap buffer and check match. + directBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(directBuffer); + assertTrue(bm2.sameAs(bm1)); + } + + @SmallTest + public void testCopyWithDirectIntBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final int padValue = 0x55aa5a5a; + final int bytesPerElement = 4; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + IntBuffer directBuffer = + ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asIntBuffer(); + + // Write padding + directBuffer.put(0, padValue); + directBuffer.put(directBuffer.limit() - 1, padValue); + + // Copy bitmap + directBuffer.position(pad); + bm1.copyPixelsToBuffer(directBuffer); + assertEquals(directBuffer.position(), + pad + width * height * bytesPerPixel / bytesPerElement); + + // Check padding + assertEquals(directBuffer.get(0), padValue); + assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); + + // Create bitmap from heap buffer and check match. + directBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(directBuffer); + assertTrue(bm2.sameAs(bm1)); + } + + @SmallTest + public void testCopyWithHeapByteBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 2; Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); @@ -312,7 +396,8 @@ public class BitmapTest extends TestCase { // of bitmap. final int pad = 1; final byte padValue = 0x5a; - final int bufferSize = pad + width * height * 2 + pad; + final int bytesPerElement = 1; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); // Write padding @@ -322,7 +407,81 @@ public class BitmapTest extends TestCase { // Copy bitmap heapBuffer.position(pad); bm1.copyPixelsToBuffer(heapBuffer); - assertEquals(heapBuffer.position(), pad + width * height * 2); + assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); + + // Check padding + assertEquals(heapBuffer.get(0), padValue); + assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); + + // Create bitmap from heap buffer and check match. + heapBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(heapBuffer); + assertTrue(bm2.sameAs(bm1)); + } + + @SmallTest + public void testCopyWithHeapShortBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final short padValue = 0x55aa; + final int bytesPerElement = 2; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + ShortBuffer heapBuffer = ShortBuffer.allocate(bufferSize); + + // Write padding + heapBuffer.put(0, padValue); + heapBuffer.put(heapBuffer.limit() - 1, padValue); + + // Copy bitmap + heapBuffer.position(pad); + bm1.copyPixelsToBuffer(heapBuffer); + assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); + + // Check padding + assertEquals(heapBuffer.get(0), padValue); + assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); + + // Create bitmap from heap buffer and check match. + heapBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(heapBuffer); + assertTrue(bm2.sameAs(bm1)); + } + + @SmallTest + public void testCopyWithHeapIntBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final int padValue = 0x55aa5a5a; + final int bytesPerElement = 4; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + IntBuffer heapBuffer = IntBuffer.allocate(bufferSize); + + // Write padding + heapBuffer.put(0, padValue); + heapBuffer.put(heapBuffer.limit() - 1, padValue); + + // Copy bitmap + heapBuffer.position(pad); + bm1.copyPixelsToBuffer(heapBuffer); + assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); // Check padding assertEquals(heapBuffer.get(0), padValue); diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index 433991e86212..aeb8949c6976 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -362,6 +362,38 @@ public class TextClassifierTest { } @Test + public void testGenerateLinks_entityData() { + if (isTextClassifierDisabled()) return; + String text = "The number is +12122537077."; + Bundle extras = new Bundle(); + ExtrasUtils.putIsSerializedEntityDataEnabled(extras, true); + TextLinks.Request request = new TextLinks.Request.Builder(text).setExtras(extras).build(); + + TextLinks textLinks = mClassifier.generateLinks(request); + + Truth.assertThat(textLinks.getLinks()).hasSize(1); + TextLinks.TextLink textLink = textLinks.getLinks().iterator().next(); + List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras()); + Truth.assertThat(entities).hasSize(1); + Bundle entity = entities.get(0); + Truth.assertThat(ExtrasUtils.getEntityType(entity)).isEqualTo(TextClassifier.TYPE_PHONE); + } + + @Test + public void testGenerateLinks_entityData_disabled() { + if (isTextClassifierDisabled()) return; + String text = "The number is +12122537077."; + TextLinks.Request request = new TextLinks.Request.Builder(text).build(); + + TextLinks textLinks = mClassifier.generateLinks(request); + + Truth.assertThat(textLinks.getLinks()).hasSize(1); + TextLinks.TextLink textLink = textLinks.getLinks().iterator().next(); + List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras()); + Truth.assertThat(entities).isNull(); + } + + @Test public void testDetectLanguage() { if (isTextClassifierDisabled()) return; String text = "This is English text"; @@ -380,7 +412,7 @@ public class TextClassifierTest { } @Test - public void testSuggestConversationActions_textReplyOnly_maxThree() { + public void testSuggestConversationActions_textReplyOnly_maxOne() { if (isTextClassifierDisabled()) return; ConversationActions.Message message = new ConversationActions.Message.Builder( @@ -399,12 +431,11 @@ public class TextClassifierTest { .build(); ConversationActions conversationActions = mClassifier.suggestConversationActions(request); - assertTrue(conversationActions.getConversationActions().size() > 0); - for (ConversationAction conversationAction : - conversationActions.getConversationActions()) { - assertThat(conversationAction, - isConversationAction(ConversationAction.TYPE_TEXT_REPLY)); - } + Truth.assertThat(conversationActions.getConversationActions()).hasSize(1); + ConversationAction conversationAction = conversationActions.getConversationActions().get(0); + Truth.assertThat(conversationAction.getType()).isEqualTo( + ConversationAction.TYPE_TEXT_REPLY); + Truth.assertThat(conversationAction.getTextReply()).isNotNull(); } @Test @@ -493,6 +524,24 @@ public class TextClassifierTest { ExtrasUtils.getSerializedEntityData(conversationAction.getExtras())).isNotEmpty(); } + @Test + public void testSuggetsConversationActions_deduplicate() { + if (isTextClassifierDisabled()) return; + ConversationActions.Message message = + new ConversationActions.Message.Builder( + ConversationActions.Message.PERSON_USER_OTHERS) + .setText("a@android.com b@android.com") + .build(); + ConversationActions.Request request = + new ConversationActions.Request.Builder(Collections.singletonList(message)) + .setMaxSuggestions(3) + .build(); + + ConversationActions conversationActions = mClassifier.suggestConversationActions(request); + + Truth.assertThat(conversationActions.getConversationActions()).isEmpty(); + } + private boolean isTextClassifierDisabled() { return mClassifier == null || mClassifier == TextClassifier.NO_OP; } diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java index 1980a604fdd2..2c540e560f6b 100644 --- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java @@ -49,8 +49,6 @@ import org.mockito.MockitoAnnotations; public class TextClassifierEventTronLoggerTest { private static final String WIDGET_TYPE = "notification"; private static final String PACKAGE_NAME = "pkg"; - private static final long EVENT_TIME = System.currentTimeMillis(); - @Mock private MetricsLogger mMetricsLogger; @@ -68,13 +66,11 @@ public class TextClassifierEventTronLoggerTest { TextClassificationContext textClassificationContext = new TextClassificationContext.Builder(PACKAGE_NAME, WIDGET_TYPE) .build(); - TextClassifierEvent textClassifierEvent = - new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, + TextClassifierEvent.ConversationActionsEvent textClassifierEvent = + new TextClassifierEvent.ConversationActionsEvent.Builder( TextClassifierEvent.TYPE_SMART_ACTION) .setEntityTypes(ConversationAction.TYPE_CALL_PHONE) - .setScore(0.5f) - .setEventTime(EVENT_TIME) + .setScores(0.5f) .setEventContext(textClassificationContext) .build(); @@ -83,10 +79,8 @@ public class TextClassifierEventTronLoggerTest { ArgumentCaptor<LogMaker> captor = ArgumentCaptor.forClass(LogMaker.class); Mockito.verify(mMetricsLogger).write(captor.capture()); LogMaker logMaker = captor.getValue(); - assertThat(logMaker.getCategory()).isEqualTo( - CONVERSATION_ACTIONS); - assertThat(logMaker.getSubtype()).isEqualTo( - ACTION_TEXT_SELECTION_SMART_SHARE); + assertThat(logMaker.getCategory()).isEqualTo(CONVERSATION_ACTIONS); + assertThat(logMaker.getSubtype()).isEqualTo(ACTION_TEXT_SELECTION_SMART_SHARE); assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE)) .isEqualTo(ConversationAction.TYPE_CALL_PHONE); assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE)) @@ -101,9 +95,8 @@ public class TextClassifierEventTronLoggerTest { @Test public void testWriteEvent_unsupportedCategory() { - TextClassifierEvent textClassifierEvent = - new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_SELECTION, + TextClassifierEvent.TextSelectionEvent textClassifierEvent = + new TextClassifierEvent.TextSelectionEvent.Builder( TextClassifierEvent.TYPE_SMART_ACTION) .build(); diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 0e957df4dc14..c54208b96031 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -180,6 +180,9 @@ <assign-permission name="android.permission.STATSCOMPANION" uid="statsd" /> <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" /> + <split-permission name="android.permission.ACCESS_FINE_LOCATION"> + <new-permission name="android.permission.ACCESS_COARSE_LOCATION" /> + </split-permission> <split-permission name="android.permission.WRITE_EXTERNAL_STORAGE"> <new-permission name="android.permission.READ_EXTERNAL_STORAGE" /> </split-permission> diff --git a/media/Android.bp b/media/Android.bp index 5b7b26cef27a..70dacb20cde7 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -20,10 +20,6 @@ java_library { ], }, - static_libs: [ - "mediaplayer2-protos", - ], - permitted_packages: [ "android.media", ], @@ -43,7 +39,6 @@ filegroup { name: "updatable-media-srcs", srcs: [ ":mediasession2-srcs", - ":mediaplayer2-srcs", ], } @@ -51,7 +46,6 @@ filegroup { name: "updatable-media-srcs-without-aidls", srcs : [ ":mediasession2-srcs-without-aidls", - ":mediaplayer2-srcs", ], } @@ -109,8 +103,7 @@ metalava_updatable_media_args = " --error UnhiddenSystemApi " + "--hide MissingPermission --hide BroadcastBehavior " + "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " + - "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi " + - " --show-annotation android.annotation.TestApi " + "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi " droidstubs { name: "updatable-media-stubs", diff --git a/media/apex/java/android/media/BufferingParams.java b/media/apex/java/android/media/BufferingParams.java index 83594d474b37..943f14277fc3 100644 --- a/media/apex/java/android/media/BufferingParams.java +++ b/media/apex/java/android/media/BufferingParams.java @@ -17,7 +17,6 @@ package android.media; import android.annotation.IntDef; -import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -64,7 +63,6 @@ import java.lang.annotation.RetentionPolicy; * <p>Users should use {@link Builder} to change {@link BufferingParams}. * @hide */ -@TestApi public final class BufferingParams implements Parcelable { private static final int BUFFERING_NO_MARK = -1; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index d3471378b9d9..f8e43437d244 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -4523,6 +4523,7 @@ public class AudioManager { */ /** @hide */ + @TestApi @SystemApi public static final int SUCCESS = AudioSystem.SUCCESS; /** diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index fefb0d7a55bf..e207721f1918 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -495,15 +495,17 @@ public class RingtoneManager { if (mCursor == null || !mCursor.moveToPosition(position)) { return null; } - - return getUriFromCursor(mCursor); + + return getUriFromCursor(mContext, mCursor); } - private static Uri getUriFromCursor(Cursor cursor) { - return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor - .getLong(ID_COLUMN_INDEX)); + private static Uri getUriFromCursor(Context context, Cursor cursor) { + final Uri uri = ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), + cursor.getLong(ID_COLUMN_INDEX)); + final Uri canonicalized = context.getContentResolver().canonicalize(uri); + return (canonicalized != null) ? canonicalized : uri; } - + /** * Gets the position of a {@link Uri} within this {@link RingtoneManager}. * @@ -569,7 +571,7 @@ public class RingtoneManager { Uri uri = null; if (cursor.moveToFirst()) { - uri = getUriFromCursor(cursor); + uri = getUriFromCursor(context, cursor); } cursor.close(); diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 1cd60f78886e..39474e13a2d0 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -416,6 +416,7 @@ public class AudioPolicy { * @param devices list of devices to which the audio stream of the application may be routed. * @return true if the change was successful, false otherwise. */ + @TestApi @SystemApi public boolean setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) { if (devices == null) { @@ -457,6 +458,7 @@ public class AudioPolicy { * @param uid UID of the application affected. * @return true if the change was successful, false otherwise. */ + @TestApi @SystemApi public boolean removeUidDeviceAffinity(int uid) { synchronized (mLock) { diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 6361fd81d2af..4ac6d35e351f 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -36,6 +36,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.util.Log; +import android.util.SparseArray; import android.view.Display; import android.view.WindowManager; @@ -69,8 +70,6 @@ public class MtpDatabase implements AutoCloseable { private final Context mContext; private final ContentProviderClient mMediaProvider; - private final String mVolumeName; - private final Uri mObjectsUri; private final AtomicBoolean mClosed = new AtomicBoolean(); private final CloseGuard mCloseGuard = CloseGuard.get(); @@ -78,10 +77,10 @@ public class MtpDatabase implements AutoCloseable { private final HashMap<String, MtpStorage> mStorageMap = new HashMap<>(); // cached property groups for single properties - private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByProperty = new HashMap<>(); + private final SparseArray<MtpPropertyGroup> mPropertyGroupsByProperty = new SparseArray<>(); // cached property groups for all properties for a given format - private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByFormat = new HashMap<>(); + private final SparseArray<MtpPropertyGroup> mPropertyGroupsByFormat = new SparseArray<>(); // SharedPreferences for writable MTP device properties private SharedPreferences mDeviceProperties; @@ -271,14 +270,11 @@ public class MtpDatabase implements AutoCloseable { } }; - public MtpDatabase(Context context, String volumeName, - String[] subDirectories) { + public MtpDatabase(Context context, String[] subDirectories) { native_setup(); mContext = Objects.requireNonNull(context); mMediaProvider = context.getContentResolver() .acquireContentProviderClient(MediaStore.AUTHORITY); - mVolumeName = volumeName; - mObjectsUri = Files.getMtpObjectsUri(volumeName); mManager = new MtpStorageManager(new MtpStorageManager.MtpNotifier() { @Override public void sendObjectAdded(int id) { @@ -526,8 +522,7 @@ public class MtpDatabase implements AutoCloseable { propertyGroup = mPropertyGroupsByFormat.get(format); if (propertyGroup == null) { final int[] propertyList = getSupportedObjectProperties(format); - propertyGroup = new MtpPropertyGroup(mMediaProvider, mVolumeName, - propertyList); + propertyGroup = new MtpPropertyGroup(propertyList); mPropertyGroupsByFormat.put(format, propertyGroup); } } else { @@ -535,12 +530,11 @@ public class MtpDatabase implements AutoCloseable { propertyGroup = mPropertyGroupsByProperty.get(property); if (propertyGroup == null) { final int[] propertyList = new int[]{property}; - propertyGroup = new MtpPropertyGroup(mMediaProvider, mVolumeName, - propertyList); + propertyGroup = new MtpPropertyGroup(propertyList); mPropertyGroupsByProperty.put(property, propertyGroup); } } - int err = propertyGroup.getPropertyList(obj, ret); + int err = propertyGroup.getPropertyList(mMediaProvider, obj.getVolumeName(), obj, ret); if (err != MtpConstants.RESPONSE_OK) { return new MtpPropertyList(err); } @@ -581,7 +575,8 @@ public class MtpDatabase implements AutoCloseable { try { // note - we are relying on a special case in MediaProvider.update() to update // the paths for all children in the case where this is a directory. - mMediaProvider.update(mObjectsUri, values, PATH_WHERE, whereArgs); + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); + mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs); } catch (RemoteException e) { Log.e(TAG, "RemoteException in mMediaProvider.update", e); } @@ -640,12 +635,12 @@ public class MtpDatabase implements AutoCloseable { if (obj.getParent().isRoot()) { values.put(Files.FileColumns.PARENT, 0); } else { - int parentId = findInMedia(path.getParent()); + int parentId = findInMedia(newParentObj, path.getParent()); if (parentId != -1) { values.put(Files.FileColumns.PARENT, parentId); } else { // The new parent isn't in MediaProvider, so delete the object instead - deleteFromMedia(oldPath, obj.isDir()); + deleteFromMedia(obj, oldPath, obj.isDir()); return; } } @@ -655,13 +650,14 @@ public class MtpDatabase implements AutoCloseable { try { int parentId = -1; if (!oldParentObj.isRoot()) { - parentId = findInMedia(oldPath.getParent()); + parentId = findInMedia(oldParentObj, oldPath.getParent()); } if (oldParentObj.isRoot() || parentId != -1) { // Old parent exists in MediaProvider - perform a move // note - we are relying on a special case in MediaProvider.update() to update // the paths for all children in the case where this is a directory. - mMediaProvider.update(mObjectsUri, values, PATH_WHERE, whereArgs); + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); + mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs); } else { // Old parent doesn't exist - add the object MediaStore.scanFile(mContext, path.toFile()); @@ -823,14 +819,16 @@ public class MtpDatabase implements AutoCloseable { if (!mManager.endRemoveObject(obj, success)) Log.e(TAG, "Failed to end remove object"); if (success) - deleteFromMedia(obj.getPath(), obj.isDir()); + deleteFromMedia(obj, obj.getPath(), obj.isDir()); } - private int findInMedia(Path path) { + private int findInMedia(MtpStorageManager.MtpObject obj, Path path) { + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); + int ret = -1; Cursor c = null; try { - c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE, + c = mMediaProvider.query(objectsUri, ID_PROJECTION, PATH_WHERE, new String[]{path.toString()}, null, null); if (c != null && c.moveToNext()) { ret = c.getInt(0); @@ -844,12 +842,13 @@ public class MtpDatabase implements AutoCloseable { return ret; } - private void deleteFromMedia(Path path, boolean isDir) { + private void deleteFromMedia(MtpStorageManager.MtpObject obj, Path path, boolean isDir) { + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); try { // Delete the object(s) from MediaProvider, but ignore errors. if (isDir) { // recursive case - delete all children first - mMediaProvider.delete(mObjectsUri, + mMediaProvider.delete(objectsUri, // the 'like' makes it use the index, the 'lower()' makes it correct // when the path contains sqlite wildcard characters "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)", @@ -858,7 +857,7 @@ public class MtpDatabase implements AutoCloseable { } String[] whereArgs = new String[]{path.toString()}; - if (mMediaProvider.delete(mObjectsUri, PATH_WHERE, whereArgs) > 0) { + if (mMediaProvider.delete(objectsUri, PATH_WHERE, whereArgs) > 0) { if (!isDir && path.toString().toLowerCase(Locale.US).endsWith(NO_MEDIA)) { MediaStore.scanFile(mContext, path.getParent().toFile()); } @@ -876,10 +875,10 @@ public class MtpDatabase implements AutoCloseable { if (obj == null) return null; // Translate this handle to the MediaProvider Handle - handle = findInMedia(obj.getPath()); + handle = findInMedia(obj, obj.getPath()); if (handle == -1) return null; - Uri uri = Files.getMtpReferencesUri(mVolumeName, handle); + Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle); Cursor c = null; try { c = mMediaProvider.query(uri, PATH_PROJECTION, null, null, null, null); @@ -912,17 +911,17 @@ public class MtpDatabase implements AutoCloseable { if (obj == null) return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE; // Translate this handle to the MediaProvider Handle - handle = findInMedia(obj.getPath()); + handle = findInMedia(obj, obj.getPath()); if (handle == -1) return MtpConstants.RESPONSE_GENERAL_ERROR; - Uri uri = Files.getMtpReferencesUri(mVolumeName, handle); + Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle); ArrayList<ContentValues> valuesList = new ArrayList<>(); for (int id : references) { // Translate each reference id to the MediaProvider Id MtpStorageManager.MtpObject refObj = mManager.getObject(id); if (refObj == null) continue; - int refHandle = findInMedia(refObj.getPath()); + int refHandle = findInMedia(refObj, refObj.getPath()); if (refHandle == -1) continue; ContentValues values = new ContentValues(); diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java index 6d5be8ef6985..5bb0c1b4ef27 100644 --- a/media/java/android/mtp/MtpPropertyGroup.java +++ b/media/java/android/mtp/MtpPropertyGroup.java @@ -46,9 +46,6 @@ class MtpPropertyGroup { } } - private final ContentProviderClient mProvider; - private final String mVolumeName; - // list of all properties in this group private final Property[] mProperties; @@ -58,10 +55,7 @@ class MtpPropertyGroup { private static final String PATH_WHERE = Files.FileColumns.DATA + "=?"; // constructs a property group for a list of properties - public MtpPropertyGroup(ContentProviderClient provider, String volumeName, int[] properties) { - mProvider = provider; - mVolumeName = volumeName; - + public MtpPropertyGroup(int[] properties) { int count = properties.length; ArrayList<String> columns = new ArrayList<>(count); columns.add(Files.FileColumns._ID); @@ -175,7 +169,8 @@ class MtpPropertyGroup { * object and adds them to the given property list. * @return Response_OK if the operation succeeded. */ - public int getPropertyList(MtpStorageManager.MtpObject object, MtpPropertyList list) { + public int getPropertyList(ContentProviderClient provider, String volumeName, + MtpStorageManager.MtpObject object, MtpPropertyList list) { Cursor c = null; int id = object.getId(); String path = object.getPath().toString(); @@ -184,8 +179,8 @@ class MtpPropertyGroup { try { // Look up the entry in MediaProvider only if one of those properties is needed. final Uri uri = MtpDatabase.getObjectPropertiesUri(object.getFormat(), - mVolumeName); - c = mProvider.query(uri, mColumns, + volumeName); + c = provider.query(uri, mColumns, PATH_WHERE, new String[] {path}, null, null); if (c != null && !c.moveToNext()) { c.close(); diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java index c714b3cad296..65d0fef74b25 100644 --- a/media/java/android/mtp/MtpStorage.java +++ b/media/java/android/mtp/MtpStorage.java @@ -18,6 +18,7 @@ package android.mtp; import android.annotation.UnsupportedAppUsage; import android.os.storage.StorageVolume; +import android.provider.MediaStore; /** * This class represents a storage unit on an MTP device. @@ -27,12 +28,12 @@ import android.os.storage.StorageVolume; * @hide */ public class MtpStorage { - private final int mStorageId; private final String mPath; private final String mDescription; private final boolean mRemovable; private final long mMaxFileSize; + private final String mVolumeName; public MtpStorage(StorageVolume volume, int storageId) { mStorageId = storageId; @@ -40,6 +41,11 @@ public class MtpStorage { mDescription = volume.getDescription(null); mRemovable = volume.isRemovable(); mMaxFileSize = volume.getMaxFileSize(); + if (volume.isPrimary()) { + mVolumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY; + } else { + mVolumeName = volume.getNormalizedUuid(); + } } /** @@ -88,4 +94,8 @@ public class MtpStorage { public long getMaxFileSize() { return mMaxFileSize; } + + public String getVolumeName() { + return mVolumeName; + } } diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java index f14e7d704ea1..e783788d0158 100644 --- a/media/java/android/mtp/MtpStorageManager.java +++ b/media/java/android/mtp/MtpStorageManager.java @@ -21,6 +21,8 @@ import android.os.FileObserver; import android.os.storage.StorageVolume; import android.util.Log; +import com.android.internal.util.Preconditions; + import java.io.IOException; import java.nio.file.DirectoryIteratorException; import java.nio.file.DirectoryStream; @@ -131,6 +133,7 @@ public class MtpStorageManager { /** MtpObject represents either a file or directory in an associated storage. **/ public static class MtpObject { + private MtpStorage mStorage; // null for root objects private MtpObject mParent; @@ -147,9 +150,10 @@ public class MtpStorageManager { // null if not both a directory and visited private FileObserver mObserver; - MtpObject(String name, int id, MtpObject parent, boolean isDir) { + MtpObject(String name, int id, MtpStorage storage, MtpObject parent, boolean isDir) { mId = id; mName = name; + mStorage = Preconditions.checkNotNull(storage); mParent = parent; mObserver = null; mVisited = false; @@ -206,6 +210,10 @@ public class MtpStorageManager { return mParent == null; } + public String getVolumeName() { + return mStorage.getVolumeName(); + } + /** For MtpStorageManager only **/ private void setName(String name) { @@ -278,7 +286,7 @@ public class MtpStorageManager { } private MtpObject copy(boolean recursive) { - MtpObject copy = new MtpObject(mName, mId, mParent, mIsDir); + MtpObject copy = new MtpObject(mName, mId, mStorage, mParent, mIsDir); copy.mIsDir = mIsDir; copy.mVisited = mVisited; copy.mState = mState; @@ -408,7 +416,7 @@ public class MtpStorageManager { public synchronized MtpStorage addMtpStorage(StorageVolume volume) { int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1; MtpStorage storage = new MtpStorage(volume, storageId); - MtpObject root = new MtpObject(storage.getPath(), storageId, null, true); + MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true); mRoots.put(storageId, root); return storage; } @@ -608,7 +616,7 @@ public class MtpStorageManager { return null; } - MtpObject obj = new MtpObject(newName, getNextObjectId(), parent, isDir); + MtpObject obj = new MtpObject(newName, getNextObjectId(), parent.mStorage, parent, isDir); mObjects.put(obj.getId(), obj); parent.addChild(obj); return obj; diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index b2baff5db75b..7860f36e7d95 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -238,7 +238,7 @@ public class Assistant extends NotificationAssistantService { } mSingleThreadExecutor.submit(() -> { NotificationEntry entry = - new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper); + new NotificationEntry(mPackageManager, sbn.cloneLight(), channel, mSmsHelper); SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry); if (DEBUG) { Log.d(TAG, String.format( @@ -296,7 +296,7 @@ public class Assistant extends NotificationAssistantService { Ranking ranking = getRanking(sbn.getKey(), rankingMap); if (ranking != null && ranking.getChannel() != null) { NotificationEntry entry = new NotificationEntry(mPackageManager, - sbn, ranking.getChannel(), mSmsHelper); + sbn.cloneLight(), ranking.getChannel(), mSmsHelper); String key = getKey( sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId()); ChannelImpressions ci = mkeyToImpressions.getOrDefault(key, diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java index 0d687d41260d..10360a34546c 100644 --- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java +++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java @@ -338,7 +338,7 @@ public class SmartActionsHelper { createTextClassifierEventBuilder( TextClassifierEvent.TYPE_SMART_ACTION, session.resultId) .setEntityTypes(ConversationAction.TYPE_TEXT_REPLY) - .setScore(session.repliesScores.getOrDefault(reply, 0f)) + .setScores(session.repliesScores.getOrDefault(reply, 0f)) .build(); mTextClassifier.onTextClassifierEvent(textClassifierEvent); } @@ -381,11 +381,9 @@ public class SmartActionsHelper { .build(); } - private TextClassifierEvent.Builder createTextClassifierEventBuilder( + private TextClassifierEvent.ConversationActionsEvent.Builder createTextClassifierEventBuilder( int eventType, String resultId) { - return new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType) - .setEventTime(System.currentTimeMillis()) + return new TextClassifierEvent.ConversationActionsEvent.Builder(eventType) .setEventContext( new TextClassificationContext.Builder( mContext.getPackageName(), TextClassifier.WIDGET_TYPE_NOTIFICATION) diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java index ebcaee87d6d8..dfa1ea0aac90 100644 --- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java +++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java @@ -330,7 +330,9 @@ public class SmartActionsHelperTest { List<TextClassifierEvent> events = argumentCaptor.getAllValues(); assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED); assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_SMART_ACTION); - assertThat(events.get(1).getScore()).isEqualTo(SCORE); + float[] scores = events.get(1).getScores(); + assertThat(scores).hasLength(1); + assertThat(scores[0]).isEqualTo(SCORE); } @Test diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt index eff02d24431e..257943e16149 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt +++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt @@ -83,6 +83,8 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) // Dual tone implies that battery level is a clipped overlay over top of the whole shape private var dualTone = false + private var batteryLevel = 0 + private val invalidateRunnable: () -> Unit = { invalidateSelf() } @@ -177,9 +179,9 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) unifiedPath.reset() levelPath.reset() levelRect.set(fillRect) - val fillFraction = level / 100f + val fillFraction = batteryLevel / 100f val fillTop = - if (level >= 95) + if (batteryLevel >= 95) fillRect.top else fillRect.top + (fillRect.height() * (1 - fillFraction)) @@ -223,7 +225,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) fillPaint.color = levelColor // Show colorError below this level - if (level <= Companion.CRITICAL_LEVEL && !charging) { + if (batteryLevel <= Companion.CRITICAL_LEVEL && !charging) { c.save() c.clipPath(scaledFill) c.drawPath(levelPath, fillPaint) @@ -310,13 +312,13 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) */ public open fun setBatteryLevel(l: Int) { invertFillIcon = if (l >= 67) true else if (l <= 33) false else invertFillIcon - level = l - levelColor = batteryColorForLevel(level) + batteryLevel = l + levelColor = batteryColorForLevel(batteryLevel) invalidateSelf() } public fun getBatteryLevel(): Int { - return level + return batteryLevel } override fun onBoundsChange(bounds: Rect?) { @@ -343,7 +345,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) dualToneBackgroundFill.color = bgColor // Also update the level color, since fillColor may have changed - levelColor = batteryColorForLevel(level) + levelColor = batteryColorForLevel(batteryLevel) invalidateSelf() } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 1976ec45bf45..d1e4fdf472c0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -337,6 +337,7 @@ public class AccessPoint implements Comparable<AccessPoint> { mContext = context; networkId = config.networkId; mConfig = config; + mFqdn = config.FQDN; setScanResultsPasspoint(homeScans, roamingScans); updateKey(); } @@ -673,6 +674,13 @@ public class AccessPoint implements Comparable<AccessPoint> { return mKey; } + /** + * Determines if the other AccessPoint represents the same network as this AccessPoint + */ + public boolean matches(AccessPoint other) { + return getKey().equals(other.getKey()); + } + public boolean matches(WifiConfiguration config) { if (config.isPasspoint()) { return (isPasspoint() && config.FQDN.equals(mConfig.FQDN)); diff --git a/packages/SystemUI/res/layout/global_actions_grid_item.xml b/packages/SystemUI/res/layout/global_actions_grid_item.xml index e92ec0f75fc1..3cefce071a1e 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_item.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_item.xml @@ -20,44 +20,50 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/global_actions_grid_item_width" android:layout_height="@dimen/global_actions_grid_item_height" - android:gravity="top|center_horizontal" - android:orientation="vertical" + android:gravity="center" android:layout_marginTop="@dimen/global_actions_grid_item_vertical_margin" android:layout_marginBottom="@dimen/global_actions_grid_item_vertical_margin" android:layout_marginLeft="@dimen/global_actions_grid_item_side_margin" android:layout_marginRight="@dimen/global_actions_grid_item_side_margin" > - <ImageView - android:id="@*android:id/icon" - android:layout_width="@dimen/global_actions_grid_item_icon_width" - android:layout_height="@dimen/global_actions_grid_item_icon_height" - android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin" - android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin" - android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin" - android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin" - android:scaleType="centerInside" - android:alpha="?android:attr/primaryContentAlpha" - /> + <LinearLayout + android:layout_width="@dimen/global_actions_grid_item_width" + android:layout_height="@dimen/global_actions_grid_item_height" + android:gravity="top|center_horizontal" + android:orientation="vertical" + > + <ImageView + android:id="@*android:id/icon" + android:layout_width="@dimen/global_actions_grid_item_icon_width" + android:layout_height="@dimen/global_actions_grid_item_icon_height" + android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin" + android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin" + android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin" + android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin" + android:scaleType="centerInside" + android:alpha="?android:attr/primaryContentAlpha" + /> - <TextView - android:id="@*android:id/message" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:ellipsize="marquee" - android:marqueeRepeatLimit="marquee_forever" - android:singleLine="true" - android:gravity="center" - android:textSize="12dp" - android:textAppearance="?android:attr/textAppearanceSmall" - /> + <TextView + android:id="@*android:id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:marqueeRepeatLimit="marquee_forever" + android:singleLine="true" + android:gravity="center" + android:textSize="12dp" + android:textAppearance="?android:attr/textAppearanceSmall" + /> - <TextView - android:visibility="gone" - android:id="@*android:id/status" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:textColor="?android:attr/textColorTertiary" - android:textAppearance="?android:attr/textAppearanceSmall" - /> + <TextView + android:visibility="gone" + android:id="@*android:id/status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:textColor="?android:attr/textColorTertiary" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 444cabfcc50e..f121c8ec5de0 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1331,6 +1331,14 @@ <!-- Content description for accessibility: Clear the odi caption tool tip. [CHAR LIMIT=NONE] --> <string name="accessibility_volume_close_odi_captions_tip">Close captions tip</string> + <!-- Content description for accessibility: Captions button. [CHAR LIMIT=NONE] --> + <string name="volume_odi_captions_content_description">Captions overlay</string> + + <!-- Content description for accessibility: Hint if click will enable. [CHAR LIMIT=NONE] --> + <string name="volume_odi_captions_hint_enable">enable</string> + <!-- Content description for accessibility: Hint if click will disable. [CHAR LIMIT=NONE] --> + <string name="volume_odi_captions_hint_disable">disable</string> + <!-- content description for audio output chooser [CHAR LIMIT=NONE]--> <string name="accessibility_output_chooser">Switch output device</string> diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index baaa3fdb16ba..eca39262dfb5 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -16,14 +16,22 @@ package com.android.keyguard; +import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; + +import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; + import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; +import android.telephony.CarrierConfigManager; +import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; @@ -36,6 +44,7 @@ import com.android.settingslib.WirelessUtils; import com.android.systemui.Dependency; import com.android.systemui.keyguard.WakefulnessLifecycle; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -113,6 +122,17 @@ public class CarrierTextController { } }; + private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveMobileDataSubscription = subId; + if (mKeyguardUpdateMonitor != null) { + updateCarrierText(); + } + } + }; + /** * The status of this lock screen. Primarily used for widgets on LockScreen. */ @@ -200,6 +220,8 @@ public class CarrierTextController { * @param callback Callback to provide text updates */ public void setListening(CarrierTextCallback callback) { + TelephonyManager telephonyManager = ((TelephonyManager) mContext + .getSystemService(Context.TELEPHONY_SERVICE)); if (callback != null) { mCarrierTextCallback = callback; if (ConnectivityManager.from(mContext).isNetworkSupported( @@ -207,6 +229,8 @@ public class CarrierTextController { mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); mKeyguardUpdateMonitor.registerCallback(mCallback); mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + telephonyManager.listen(mPhoneStateListener, + LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); } else { // Don't listen and clear out the text when the device isn't a phone. mKeyguardUpdateMonitor = null; @@ -218,6 +242,35 @@ public class CarrierTextController { mKeyguardUpdateMonitor.removeCallback(mCallback); mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); } + telephonyManager.listen(mPhoneStateListener, LISTEN_NONE); + } + } + + /** + * STOPSHIP(b/130246708) remove when no longer needed for testing purpose. + * @param subscriptions + */ + private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) { + if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) { + SubscriptionInfo info1 = subscriptions.get(0); + SubscriptionInfo info2 = subscriptions.get(1); + if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { + // If both subscriptions are primary, show both. + if (!info1.isOpportunistic() && !info2.isOpportunistic()) return; + + // If carrier required, always show signal bar of primary subscription. + // Otherwise, show whichever subscription is currently active for Internet. + boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig() + .getBoolean(CarrierConfigManager + .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN); + if (alwaysShowPrimary) { + subscriptions.remove(info1.isOpportunistic() ? info1 : info2); + } else { + subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription + ? info2 : info1); + } + + } } } @@ -226,7 +279,17 @@ public class CarrierTextController { boolean anySimReadyAndInService = false; CharSequence displayText = null; - List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); + // STOPSHIP(b/130246708) revert to mKeyguardUpdateMonitor.getSubscriptionInfo(false). + SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE)); + List<SubscriptionInfo> subs = subscriptionManager.getActiveSubscriptionInfoList(false); + + if (subs == null) { + subs = new ArrayList<>(); + } else { + filterMobileSubscriptionInSameGroup(subs); + } + final int numSubs = subs.size(); final int[] subsIds = new int[numSubs]; // This array will contain in position i, the index of subscription in slot ID i. diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index acdcfb2ea688..6d0141be1721 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -34,6 +34,7 @@ import android.app.INotificationManager; import android.app.Notification; import android.content.Context; import android.content.pm.ParceledListSlice; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; import android.os.ServiceManager; @@ -134,6 +135,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // Used for determining view rect for touch interaction private Rect mTempRect = new Rect(); + /** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */ + private int mOrientation = Configuration.ORIENTATION_UNDEFINED; + /** * Listener to be notified when some states of the bubbles change. */ @@ -256,6 +260,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } + @Override + public void onConfigChanged(Configuration newConfig) { + if (mStackView != null && newConfig != null && newConfig.orientation != mOrientation) { + mStackView.onOrientationChanged(); + mOrientation = newConfig.orientation; + } + } + /** * Set a listener to be notified when some states of the bubbles change. */ diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 18b2e37e31ec..a4a0fe18f5cb 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -134,6 +134,16 @@ public class BubbleStackView extends FrameLayout { private Runnable mHideFlyout = () -> mFlyout.animate().alpha(0f).withEndAction(() -> mFlyout.setVisibility(GONE)); + /** Layout change listener that moves the stack to the nearest valid position on rotation. */ + private OnLayoutChangeListener mMoveStackToValidPositionOnLayoutListener; + /** Whether the stack was on the left side of the screen prior to rotation. */ + private boolean mWasOnLeftBeforeRotation = false; + /** + * How far down the screen the stack was before rotation, in terms of percentage of the way down + * the allowable region. Defaults to -1 if not set. + */ + private float mVerticalPosPercentBeforeRotation = -1; + private int mBubbleSize; private int mBubblePadding; private int mExpandedAnimateXDistance; @@ -300,6 +310,15 @@ public class BubbleStackView extends FrameLayout { return view.onApplyWindowInsets(insets); }); + mMoveStackToValidPositionOnLayoutListener = + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + if (mVerticalPosPercentBeforeRotation >= 0) { + mStackAnimationController.moveStackToSimilarPositionAfterRotation( + mWasOnLeftBeforeRotation, mVerticalPosPercentBeforeRotation); + } + removeOnLayoutChangeListener(mMoveStackToValidPositionOnLayoutListener); + }; + // This must be a separate OnDrawListener since it should be called for every draw. getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater); } @@ -314,6 +333,18 @@ public class BubbleStackView extends FrameLayout { } } + /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */ + public void onOrientationChanged() { + final RectF allowablePos = mStackAnimationController.getAllowableStackPositionRegion(); + mWasOnLeftBeforeRotation = mStackAnimationController.isStackOnLeftSide(); + mVerticalPosPercentBeforeRotation = + (mStackAnimationController.getStackPosition().y - allowablePos.top) + / (allowablePos.bottom - allowablePos.top); + addOnLayoutChangeListener(mMoveStackToValidPositionOnLayoutListener); + + hideFlyoutImmediate(); + } + @Override public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { getBoundsOnScreen(outRect); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index b953f270f337..74a6b6005450 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -252,6 +252,21 @@ public class StackAnimationController extends } /** + * Moves the stack in response to rotation. We keep it in the most similar position by keeping + * it on the same side, and positioning it the same percentage of the way down the screen + * (taking status bar/nav bar into account by using the allowable region's height). + */ + public void moveStackToSimilarPositionAfterRotation(boolean wasOnLeft, float verticalPercent) { + final RectF allowablePos = getAllowableStackPositionRegion(); + final float allowableRegionHeight = allowablePos.bottom - allowablePos.top; + + final float x = wasOnLeft ? allowablePos.left : allowablePos.right; + final float y = (allowableRegionHeight * verticalPercent) + allowablePos.top; + + setStackPosition(new PointF(x, y)); + } + + /** * Flings the first bubble along the given property's axis, using the provided configuration * values. When the animation ends - either by hitting the min/max, or by friction sufficiently * reducing momentum - a SpringAnimation takes over to snap the bubble to the given final diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java index f8825690056e..e7878c69873c 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java @@ -119,6 +119,17 @@ public class GlobalActionsGridLayout extends MultiListLayout { } } updateSnapPosition(); + updateSeparatedButtonSize(); + } + + private void updateSeparatedButtonSize() { + ViewGroup separated = getSeparatedView(); + if (separated.getChildCount() == 1) { + View onlyChild = separated.getChildAt(0); + ViewGroup.LayoutParams childParams = onlyChild.getLayoutParams(); + childParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + childParams.height = ViewGroup.LayoutParams.MATCH_PARENT; + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java index 45fc7563a5c3..1862ed3a4de8 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java +++ b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java @@ -22,6 +22,9 @@ import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; +import androidx.core.view.ViewCompat; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; + import com.android.keyguard.AlphaOptimizedImageButton; import com.android.systemui.R; @@ -31,7 +34,7 @@ public class CaptionsToggleImageButton extends AlphaOptimizedImageButton { private static final int[] OPTED_OUT_STATE = new int[] { R.attr.optedOut }; private ConfirmedTapListener mConfirmedTapListener; - private boolean mComponentEnabled = false; + private boolean mCaptionsEnabled = false; private boolean mOptedOut = false; private GestureDetector mGestureDetector; @@ -39,16 +42,14 @@ public class CaptionsToggleImageButton extends AlphaOptimizedImageButton { new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { - if (mConfirmedTapListener != null) { - mConfirmedTapListener.onConfirmedTap(); - return true; - } - return false; + return tryToSendTapConfirmedEvent(); } }; public CaptionsToggleImageButton(Context context, AttributeSet attrs) { super(context, attrs); + this.setContentDescription( + getContext().getString(R.string.volume_odi_captions_content_description)); } @Override @@ -66,16 +67,32 @@ public class CaptionsToggleImageButton extends AlphaOptimizedImageButton { return state; } - Runnable setComponentEnabled(boolean isComponentEnabled) { - this.mComponentEnabled = isComponentEnabled; + Runnable setCaptionsEnabled(boolean areCaptionsEnabled) { + this.mCaptionsEnabled = areCaptionsEnabled; + + ViewCompat.replaceAccessibilityAction( + this, + AccessibilityActionCompat.ACTION_CLICK, + mCaptionsEnabled + ? getContext().getString(R.string.volume_odi_captions_hint_disable) + : getContext().getString(R.string.volume_odi_captions_hint_enable), + (view, commandArguments) -> tryToSendTapConfirmedEvent()); - return this.setImageResourceAsync(this.mComponentEnabled + return this.setImageResourceAsync(mCaptionsEnabled ? R.drawable.ic_volume_odi_captions : R.drawable.ic_volume_odi_captions_disabled); } - boolean getComponentEnabled() { - return this.mComponentEnabled; + private boolean tryToSendTapConfirmedEvent() { + if (mConfirmedTapListener != null) { + mConfirmedTapListener.onConfirmedTap(); + return true; + } + return false; + } + + boolean getCaptionsEnabled() { + return this.mCaptionsEnabled; } /** Sets whether or not the current stream has opted out of captions */ diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 509537089bf8..8d9c5a3740b2 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -596,9 +596,9 @@ public class VolumeDialogImpl implements VolumeDialog, } private void updateCaptionsIcon() { - boolean componentEnabled = mController.areCaptionsEnabled(); - if (mODICaptionsIcon.getComponentEnabled() != componentEnabled) { - mHandler.post(mODICaptionsIcon.setComponentEnabled(componentEnabled)); + boolean captionsEnabled = mController.areCaptionsEnabled(); + if (mODICaptionsIcon.getCaptionsEnabled() != captionsEnabled) { + mHandler.post(mODICaptionsIcon.setCaptionsEnabled(captionsEnabled)); } boolean isOptedOut = mController.isCaptionStreamOptedOut(); @@ -878,7 +878,6 @@ public class VolumeDialogImpl implements VolumeDialog, } view.setContentDescription(mContext.getString(currStateResId)); - view.setAccessibilityDelegate(new AccessibilityDelegate() { public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(host, info); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index 8e061cc84396..df534d79f730 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -37,6 +37,7 @@ import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -81,6 +82,8 @@ public class CarrierTextControllerTest extends SysuiTestCase { private ConnectivityManager mConnectivityManager; @Mock private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionManager mSubscriptionManager; private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo; private CarrierTextController mCarrierTextController; @@ -94,6 +97,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { mContext.addMockSystemService(WifiManager.class, mWifiManager); mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager); mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); + mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); mDependency.injectMockDependency(WakefulnessLifecycle.class); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, new Handler(mTestableLooper.getLooper())); @@ -169,6 +173,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -192,6 +197,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION_ROAMING); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index adf582925489..609904b32230 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -17,6 +17,7 @@ package com.android.server.autofill; import static com.android.server.autofill.Helper.sDebug; +import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.annotation.Nullable; @@ -99,7 +100,7 @@ final class RemoteAugmentedAutofillService } try { if (state) { - mService.onConnected(); + mService.onConnected(sDebug, sVerbose); } else { mService.onDisconnected(); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index fdc01e0c1093..9e73684d5f93 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -265,7 +265,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // main reason being the cases where user tap HOME. // Right now it's completely destroying the UI, but we need to decide whether / how to // properly recover it later (for example, if the user switches back to the activity, - // should it be restored? Right not it kind of is, because Autofill's Session trigger a + // should it be restored? Right now it kind of is, because Autofill's Session trigger a // new FillRequest, which in turn triggers the Augmented Autofill request again) @GuardedBy("mLock") @Nullable @@ -2755,9 +2755,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState viewState.setState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL); final AutofillValue currentValue = viewState.getCurrentValue(); - // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize - // further AFM -> AFMS calls. - if (mAugmentedRequestsLogs == null) { mAugmentedRequestsLogs = new ArrayList<>(); } diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 447bd8c237dd..03f21498766d 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -566,10 +566,6 @@ public class UserBackupManagerService { // require frequent starting and stopping. mConstants.start(); - // Set up the various sorts of package tracking we do - mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); - initPackageTracking(); - // Build our mapping of uid to backup client services. This implicitly // schedules a backup pass on the Package Manager metadata the first // time anything needs to be backed up. @@ -589,6 +585,10 @@ public class UserBackupManagerService { // Power management mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId); + + // Set up the various sorts of package tracking we do + mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); + initPackageTracking(); } void initializeBackupEnableState() { @@ -744,6 +744,11 @@ public class UserBackupManagerService { return mDataDir; } + @VisibleForTesting + BroadcastReceiver getPackageTrackingReceiver() { + return mBroadcastReceiver; + } + @Nullable public DataChangedJournal getJournal() { return mJournal; diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java index 593bb2c41587..35dfccf32924 100644 --- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java @@ -23,22 +23,20 @@ import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_A import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.Nullable; -import android.app.AppGlobals; import android.app.backup.BackupTransport; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.content.pm.SigningInfo; -import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.backup.IBackupTransport; import com.android.internal.util.ArrayUtils; +import com.android.server.LocalServices; import com.android.server.backup.transport.TransportClient; import com.google.android.collect.Sets; @@ -67,12 +65,13 @@ public class AppBackupUtils { * </ol> */ public static boolean appIsEligibleForBackup(ApplicationInfo app, int userId) { - return appIsEligibleForBackup(app, AppGlobals.getPackageManager(), userId); + return appIsEligibleForBackup( + app, LocalServices.getService(PackageManagerInternal.class), userId); } @VisibleForTesting - static boolean appIsEligibleForBackup(ApplicationInfo app, - IPackageManager packageManager, int userId) { + static boolean appIsEligibleForBackup( + ApplicationInfo app, PackageManagerInternal packageManager, int userId) { // 1. their manifest states android:allowBackup="false" if ((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { return false; @@ -108,9 +107,9 @@ public class AppBackupUtils { /** * Returns whether an app is eligible for backup at runtime. That is, the app has to: * <ol> - * <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, PackageManager)} + * <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, int)} * <li>Return false for {@link #appIsStopped(ApplicationInfo)} - * <li>Return false for {@link #appIsDisabled(ApplicationInfo, PackageManager)} + * <li>Return false for {@link #appIsDisabled(ApplicationInfo, int)} * <li>Be eligible for the transport via * {@link BackupTransport#isAppEligibleForBackup(PackageInfo, boolean)} * </ol> @@ -149,19 +148,13 @@ public class AppBackupUtils { /** Avoid backups of 'disabled' apps. */ static boolean appIsDisabled(ApplicationInfo app, int userId) { - return appIsDisabled(app, AppGlobals.getPackageManager(), userId); + return appIsDisabled(app, LocalServices.getService(PackageManagerInternal.class), userId); } @VisibleForTesting - static boolean appIsDisabled(ApplicationInfo app, - IPackageManager packageManager, int userId) { - int enabledSetting; - try { - enabledSetting = packageManager.getApplicationEnabledSetting(app.packageName, userId); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to get application enabled setting: " + e); - return false; - } + static boolean appIsDisabled( + ApplicationInfo app, PackageManagerInternal packageManager, int userId) { + int enabledSetting = packageManager.getApplicationEnabledState(app.packageName, userId); switch (enabledSetting) { case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 82bba779e69b..053e68625a47 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -293,7 +293,6 @@ class StorageManagerService extends IStorageManager.Stub private static final String TAG_VOLUMES = "volumes"; private static final String ATTR_VERSION = "version"; private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid"; - private static final String ATTR_ISOLATED_STORAGE = "isolatedStorage"; private static final String TAG_VOLUME = "volume"; private static final String ATTR_TYPE = "type"; private static final String ATTR_FS_UUID = "fsUuid"; @@ -349,10 +348,6 @@ class StorageManagerService extends IStorageManager.Stub @GuardedBy("mLock") private String mPrimaryStorageUuid; - /** Flag indicating isolated storage state of last boot */ - @GuardedBy("mLock") - private boolean mLastIsolatedStorage = false; - /** Map from disk ID to latches */ @GuardedBy("mLock") private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>(); @@ -1074,6 +1069,15 @@ class StorageManagerService extends IStorageManager.Stub mVold.onUserStarted(userId, packages, appIds, sandboxIds); } + private boolean supportsBlockCheckpoint() throws RemoteException { + // Only the system process is permitted to start checkpoints + if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { + throw new SecurityException("no permission to check block based checkpoint support"); + } + + return mVold.supportsBlockCheckpoint(); + } + @Override public void onAwakeStateChanged(boolean isAwake) { // Ignored @@ -1681,63 +1685,6 @@ class StorageManagerService extends IStorageManager.Stub mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback); } catch (RemoteException e) { } - - synchronized (mLock) { - final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage(); - if (mLastIsolatedStorage != thisIsolatedStorage) { - if (thisIsolatedStorage) { - // This boot enables isolated storage; apply legacy behavior - applyLegacyStorage(); - } - - // Always remember the new state we just booted with - writeSettingsLocked(); - } - } - } - - /** - * If we're enabling isolated storage, we need to remember which existing - * apps have already been using shared storage, and grant them legacy access - * to keep them running smoothly. - * - * @see com.android.server.pm.permission.PermissionManagerService - * #applyLegacyStoragePermissionModel - */ - private void applyLegacyStorage() { - final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); - final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); - for (int userId : um.getUserIds()) { - final UserHandle user = UserHandle.of(userId); - final PackageManager pm; - try { - pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, - user).getPackageManager(); - } catch (PackageManager.NameNotFoundException e) { - throw new RuntimeException(e); - } - - final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions( - ALL_STORAGE_PERMISSIONS, - MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE - | GET_PERMISSIONS); - for (PackageInfo pkg : pkgs) { - final int uid = pkg.applicationInfo.uid; - final String packageName = pkg.applicationInfo.packageName; - - final long lastAccess = getLastAccessTime(appOps, uid, packageName, new int[] { - AppOpsManager.OP_READ_EXTERNAL_STORAGE, - AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, - }); - - Log.d(TAG, "Found " + uid + " " + packageName - + " with granted storage access, last accessed " + lastAccess); - if (lastAccess > 0) { - appOps.setUidMode(AppOpsManager.OP_LEGACY_STORAGE, uid, - AppOpsManager.MODE_ALLOWED); - } - } - } } private static long getLastAccessTime(AppOpsManager manager, @@ -1783,7 +1730,6 @@ class StorageManagerService extends IStorageManager.Stub private void readSettingsLocked() { mRecords.clear(); mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); - mLastIsolatedStorage = false; FileInputStream fis = null; try { @@ -1805,9 +1751,6 @@ class StorageManagerService extends IStorageManager.Stub mPrimaryStorageUuid = readStringAttribute(in, ATTR_PRIMARY_STORAGE_UUID); } - mLastIsolatedStorage = readBooleanAttribute(in, - ATTR_ISOLATED_STORAGE, false); - } else if (TAG_VOLUME.equals(tag)) { final VolumeRecord rec = readVolumeRecord(in); mRecords.put(rec.fsUuid, rec); @@ -1837,7 +1780,6 @@ class StorageManagerService extends IStorageManager.Stub out.startTag(null, TAG_VOLUMES); writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY); writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid); - writeBooleanAttribute(out, ATTR_ISOLATED_STORAGE, StorageManager.hasIsolatedStorage()); final int size = mRecords.size(); for (int i = 0; i < size; i++) { final VolumeRecord rec = mRecords.valueAt(i); @@ -2116,37 +2058,45 @@ class StorageManagerService extends IStorageManager.Stub enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); try { - mVold.fstrim(flags, new IVoldTaskListener.Stub() { - @Override - public void onStatus(int status, PersistableBundle extras) { - dispatchOnStatus(listener, status, extras); + // Block based checkpoint process runs fstrim. So, if checkpoint is in progress + // (first boot after OTA), We skip idle maintenance and make sure the last + // fstrim time is still updated. If file based checkpoints are used, we run + // idle maintenance (GC + fstrim) regardless of checkpoint status. + if (!needsCheckpoint() || !supportsBlockCheckpoint()) { + mVold.fstrim(flags, new IVoldTaskListener.Stub() { + @Override + public void onStatus(int status, PersistableBundle extras) { + dispatchOnStatus(listener, status, extras); - // Ignore trim failures - if (status != 0) return; + // Ignore trim failures + if (status != 0) return; - final String path = extras.getString("path"); - final long bytes = extras.getLong("bytes"); - final long time = extras.getLong("time"); + final String path = extras.getString("path"); + final long bytes = extras.getLong("bytes"); + final long time = extras.getLong("time"); - final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class); - dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time); + final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class); + dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time); - synchronized (mLock) { - final VolumeRecord rec = findRecordForPath(path); - if (rec != null) { - rec.lastTrimMillis = System.currentTimeMillis(); - writeSettingsLocked(); + synchronized (mLock) { + final VolumeRecord rec = findRecordForPath(path); + if (rec != null) { + rec.lastTrimMillis = System.currentTimeMillis(); + writeSettingsLocked(); + } } } - } - @Override - public void onFinished(int status, PersistableBundle extras) { - dispatchOnFinished(listener, status, extras); + @Override + public void onFinished(int status, PersistableBundle extras) { + dispatchOnFinished(listener, status, extras); - // TODO: benchmark when desired - } - }); + // TODO: benchmark when desired + } + }); + } else { + Slog.i(TAG, "Skipping fstrim - block based checkpoint in progress"); + } } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -2156,18 +2106,26 @@ class StorageManagerService extends IStorageManager.Stub enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); try { - mVold.runIdleMaint(new IVoldTaskListener.Stub() { - @Override - public void onStatus(int status, PersistableBundle extras) { - // Not currently used - } - @Override - public void onFinished(int status, PersistableBundle extras) { - if (callback != null) { - BackgroundThread.getHandler().post(callback); + // Block based checkpoint process runs fstrim. So, if checkpoint is in progress + // (first boot after OTA), We skip idle maintenance and make sure the last + // fstrim time is still updated. If file based checkpoints are used, we run + // idle maintenance (GC + fstrim) regardless of checkpoint status. + if (!needsCheckpoint() || !supportsBlockCheckpoint()) { + mVold.runIdleMaint(new IVoldTaskListener.Stub() { + @Override + public void onStatus(int status, PersistableBundle extras) { + // Not currently used } - } - }); + @Override + public void onFinished(int status, PersistableBundle extras) { + if (callback != null) { + BackgroundThread.getHandler().post(callback); + } + } + }); + } else { + Slog.i(TAG, "Skipping idle maintenance - block based checkpoint in progress"); + } } catch (Exception e) { Slog.wtf(TAG, e); } @@ -3800,11 +3758,7 @@ class StorageManagerService extends IStorageManager.Stub // they hold the runtime permission final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid, packageName) == MODE_ALLOWED; - // STOPSHIP: only use app-op once permission model has fully landed - final boolean requestedLegacy = !mIPackageManager - .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid)) - .isExternalStorageSandboxAllowed(); - if ((hasLegacy || requestedLegacy) && hasStorage) { + if (hasLegacy && hasStorage) { return Zygote.MOUNT_EXTERNAL_LEGACY; } else { return Zygote.MOUNT_EXTERNAL_WRITE; diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java index 6bb3200f7cc1..1ce655618028 100644 --- a/services/core/java/com/android/server/SystemServerInitThreadPool.java +++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java @@ -120,7 +120,7 @@ public class SystemServerInitThreadPool { private static void dumpStackTraces() { final ArrayList<Integer> pids = new ArrayList<>(); pids.add(Process.myPid()); - ActivityManagerService.dumpStackTraces( - pids, null, null, null); + ActivityManagerService.dumpStackTraces(pids, null, null, + Watchdog.getInterestingNativePids()); } } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index afcf954371cc..cc3b43adcacd 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -101,17 +101,18 @@ public class Watchdog extends Thread { }; public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList( - "android.hardware.audio@2.0::IDevicesFactory", - "android.hardware.audio@4.0::IDevicesFactory", - "android.hardware.bluetooth@1.0::IBluetoothHci", - "android.hardware.camera.provider@2.4::ICameraProvider", - "android.hardware.graphics.allocator@2.0::IAllocator", - "android.hardware.graphics.composer@2.1::IComposer", - "android.hardware.health@2.0::IHealth", - "android.hardware.media.omx@1.0::IOmx", - "android.hardware.media.omx@1.0::IOmxStore", - "android.hardware.sensors@1.0::ISensors", - "android.hardware.vr@1.0::IVr" + "android.hardware.audio@2.0::IDevicesFactory", + "android.hardware.audio@4.0::IDevicesFactory", + "android.hardware.bluetooth@1.0::IBluetoothHci", + "android.hardware.camera.provider@2.4::ICameraProvider", + "android.hardware.graphics.allocator@2.0::IAllocator", + "android.hardware.graphics.composer@2.1::IComposer", + "android.hardware.health@2.0::IHealth", + "android.hardware.media.omx@1.0::IOmx", + "android.hardware.media.omx@1.0::IOmxStore", + "android.hardware.sensors@1.0::ISensors", + "android.hardware.vr@1.0::IVr", + "android.hardware.biometrics.face@1.0::IBiometricsFace" ); static Watchdog sWatchdog; @@ -396,7 +397,7 @@ public class Watchdog extends Thread { return builder.toString(); } - private ArrayList<Integer> getInterestingHalPids() { + private static ArrayList<Integer> getInterestingHalPids() { try { IServiceManager serviceManager = IServiceManager.getService(); ArrayList<IServiceManager.InstanceDebugInfo> dump = @@ -419,7 +420,7 @@ public class Watchdog extends Thread { } } - private ArrayList<Integer> getInterestingNativePids() { + static ArrayList<Integer> getInterestingNativePids() { ArrayList<Integer> pids = getInterestingHalPids(); int[] nativePids = Process.getPidsForCommands(NATIVE_STACKS_OF_INTEREST); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 4ec90ba5b803..0271354b3fff 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1806,7 +1806,7 @@ public final class ActiveServices { || (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0), b.client); - mAm.updateOomAdjLocked(); + mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE); } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b @@ -1957,11 +1957,12 @@ public final class ActiveServices { r.binding.service.app.hasClientActivities() || r.binding.service.app.treatLikeActivity, null); } - mAm.updateOomAdjLocked(r.binding.service.app, false); + mAm.updateOomAdjLocked(r.binding.service.app, false, + OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); } } - mAm.updateOomAdjLocked(); + mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); } finally { Binder.restoreCallingIdentity(origId); @@ -2676,7 +2677,7 @@ public final class ActiveServices { bumpServiceExecutingLocked(r, execInFg, "create"); mAm.updateLruProcessLocked(app, false, null); updateServiceForegroundLocked(r.app, /* oomAdj= */ false); - mAm.updateOomAdjLocked(); + mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); boolean created = false; try { @@ -2797,7 +2798,7 @@ public final class ActiveServices { bumpServiceExecutingLocked(r, execInFg, "start"); if (!oomAdjusted) { oomAdjusted = true; - mAm.updateOomAdjLocked(r.app, true); + mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE); } if (r.fgRequired && !r.fgWaiting) { if (!r.isForeground) { @@ -2923,7 +2924,8 @@ public final class ActiveServices { if (ibr.hasBound) { try { bumpServiceExecutingLocked(r, false, "bring down unbind"); - mAm.updateOomAdjLocked(r.app, true); + mAm.updateOomAdjLocked(r.app, true, + OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); ibr.hasBound = false; ibr.requested = false; r.app.thread.scheduleUnbindService(r, @@ -3038,7 +3040,8 @@ public final class ActiveServices { bumpServiceExecutingLocked(r, false, "destroy"); mDestroyingServices.add(r); r.destroying = true; - mAm.updateOomAdjLocked(r.app, true); + mAm.updateOomAdjLocked(r.app, true, + OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); r.app.thread.scheduleStopService(r); } catch (Exception e) { Slog.w(TAG, "Exception when destroying service " @@ -3143,7 +3146,8 @@ public final class ActiveServices { // it to go down there and we want it to start out near the top. mAm.updateLruProcessLocked(s.app, false, null); } - mAm.updateOomAdjLocked(s.app, true); + mAm.updateOomAdjLocked(s.app, true, + OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); b.intent.hasBound = false; // Assume the client doesn't want to know about a rebind; // we will deal with that later if it asks for one. @@ -3296,7 +3300,7 @@ public final class ActiveServices { mDestroyingServices.remove(r); r.bindings.clear(); } - mAm.updateOomAdjLocked(r.app, true); + mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); } r.executeFg = false; if (r.tracker != null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3b6b404170c5..cdcd9e1ad58c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1972,7 +1972,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); mPidsSelfLocked.put(app.pid, app); mProcessList.updateLruProcessLocked(app, false, null); - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( @@ -2456,7 +2456,7 @@ public class ActivityManagerService extends IActivityManager.Stub // bind background threads to little cores // this is expected to fail inside of framework tests because apps can't touch cpusets directly // make sure we've already adjusted system_server's internal view of itself first - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); try { Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(), Process.THREAD_GROUP_SYSTEM); @@ -3634,7 +3634,7 @@ public class ActivityManagerService extends IActivityManager.Stub handleAppDiedLocked(app, false, true); if (doOomAdj) { - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); } if (doLowMem) { doLowMemReportIfNeededLocked(app); @@ -5002,7 +5002,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (!didSomething) { - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked"); } @@ -5485,7 +5485,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { mConstants.setOverrideMaxCachedProcesses(max); } - trimApplications(); + trimApplications(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); } @Override @@ -5511,7 +5511,7 @@ public class ActivityManagerService extends IActivityManager.Stub pr.forcingToImportant = null; updateProcessForegroundLocked(pr, false, 0, false); } - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -5557,7 +5557,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (changed) { - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } } @@ -6714,7 +6714,8 @@ public class ActivityManagerService extends IActivityManager.Stub checkTime(startTime, "getContentProviderImpl: before updateOomAdj"); final int verifiedAdj = cpr.proc.verifiedAdj; - boolean success = updateOomAdjLocked(cpr.proc, true); + boolean success = updateOomAdjLocked(cpr.proc, true, + OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); // XXX things have changed so updateOomAdjLocked doesn't actually tell us // if the process has been successfully adjusted. So to reduce races with // it, we will check whether the process still exists. Note that this doesn't @@ -7147,7 +7148,7 @@ public class ActivityManagerService extends IActivityManager.Stub throw new NullPointerException("connection is null"); } if (decProviderCountLocked(conn, null, null, stable)) { - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER); } } } finally { @@ -7188,7 +7189,7 @@ public class ActivityManagerService extends IActivityManager.Stub ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId); if (localCpr.hasExternalProcessHandles()) { if (localCpr.removeExternalProcessHandleLocked(token)) { - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER); } else { Slog.e(TAG, "Attmpt to remove content provider " + localCpr + " with no external reference for token: " @@ -7255,7 +7256,7 @@ public class ActivityManagerService extends IActivityManager.Stub dst.setProcess(r); dst.notifyAll(); } - updateOomAdjLocked(r, true); + updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority); } @@ -7645,7 +7646,7 @@ public class ActivityManagerService extends IActivityManager.Stub new HostingRecord("added application", customProcess != null ? customProcess : info.processName)); mProcessList.updateLruProcessLocked(app, false, null); - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); } // This package really, really can not be stopped. @@ -7740,7 +7741,7 @@ public class ActivityManagerService extends IActivityManager.Stub mActivityTaskManager.onScreenAwakeChanged(isAwake); mOomAdjProfiler.onWakefulnessChanged(wakefulness); } - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -8320,7 +8321,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (changed) { - updateOomAdjLocked(pr, true); + updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } } finally { @@ -8350,7 +8351,7 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation + " for pid=" + pid); } - updateOomAdjLocked(pr, true); + updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -13984,7 +13985,7 @@ public class ActivityManagerService extends IActivityManager.Stub mBackupTargets.put(targetUserId, r); // Try not to kill the process during backup - updateOomAdjLocked(proc, true); + updateOomAdjLocked(proc, true, OomAdjuster.OOM_ADJ_REASON_NONE); // If the process is already attached, schedule the creation of the backup agent now. // If it is not yet live, this will be done when it attaches to the framework. @@ -14099,7 +14100,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Not backing this app up any more; reset its OOM adjustment final ProcessRecord proc = backupTarget.app; - updateOomAdjLocked(proc, true); + updateOomAdjLocked(proc, true, OomAdjuster.OOM_ADJ_REASON_NONE); proc.inFullBackup = false; oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1; @@ -14388,7 +14389,7 @@ public class ActivityManagerService extends IActivityManager.Stub // If we actually concluded any broadcasts, we might now be able // to trim the recipients' apps from our working set if (doTrim) { - trimApplications(); + trimApplications(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER); return; } @@ -15463,7 +15464,7 @@ public class ActivityManagerService extends IActivityManager.Stub r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true); } // updateOomAdjLocked() will be done here - trimApplicationsLocked(); + trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER); } } finally { @@ -16448,7 +16449,7 @@ public class ActivityManagerService extends IActivityManager.Stub item.foregroundServiceTypes = fgServiceTypes; if (oomAdj) { - updateOomAdjLocked(); + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } } @@ -16496,11 +16497,13 @@ public class ActivityManagerService extends IActivityManager.Stub * @param app The process to update * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps * if necessary, or skip. + * @param oomAdjReason * @return whether updateOomAdjLocked(app) was successful. */ @GuardedBy("this") - final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) { - return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll); + final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll, + String oomAdjReason) { + return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll, oomAdjReason); } static final class ProcStatsRunnable implements Runnable { @@ -16693,8 +16696,8 @@ public class ActivityManagerService extends IActivityManager.Stub } @GuardedBy("this") - final void updateOomAdjLocked() { - mOomAdjuster.updateOomAdjLocked(); + final void updateOomAdjLocked(String oomAdjReason) { + mOomAdjuster.updateOomAdjLocked(oomAdjReason); } @Override @@ -16979,14 +16982,14 @@ public class ActivityManagerService extends IActivityManager.Stub mOomAdjuster.setUidTempWhitelistStateLocked(uid, onWhitelist); } - final void trimApplications() { + final void trimApplications(String oomAdjReason) { synchronized (this) { - trimApplicationsLocked(); + trimApplicationsLocked(oomAdjReason); } } @GuardedBy("this") - final void trimApplicationsLocked() { + final void trimApplicationsLocked(String oomAdjReason) { // First remove any unused application processes whose package // has been removed. for (int i = mProcessList.mRemovedProcesses.size() - 1; i >= 0; i--) { @@ -17018,7 +17021,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Now update the oom adj for all processes. Don't skip this, since other callers // might be depending on it. - updateOomAdjLocked(); + updateOomAdjLocked(oomAdjReason); } /** This method sends the specified signal to each of the persistent apps */ @@ -17627,7 +17630,7 @@ public class ActivityManagerService extends IActivityManager.Stub } pr.setHasOverlayUi(hasOverlayUi); //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid); - updateOomAdjLocked(pr, true); + updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -17784,7 +17787,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void trimApplications() { - ActivityManagerService.this.trimApplications(); + ActivityManagerService.this.trimApplications(OomAdjuster.OOM_ADJ_REASON_ACTIVITY); } public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) { @@ -17836,7 +17839,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void updateOomAdj() { synchronized (ActivityManagerService.this) { - ActivityManagerService.this.updateOomAdjLocked(); + ActivityManagerService.this.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 3c57c3bcb7d6..ee9b5614584f 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -309,7 +309,7 @@ public final class BroadcastQueue { app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); mService.mProcessList.updateLruProcessLocked(app, false, null); if (!skipOomAdj) { - mService.updateOomAdjLocked(); + mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); } // Tell the application to launch this receiver. @@ -791,7 +791,8 @@ public final class BroadcastQueue { // are already core system stuff so don't matter for this. r.curApp = filter.receiverList.app; filter.receiverList.app.curReceivers.add(r); - mService.updateOomAdjLocked(r.curApp, true); + mService.updateOomAdjLocked(r.curApp, true, + OomAdjuster.OOM_ADJ_REASON_START_RECEIVER); } } try { @@ -1028,7 +1029,7 @@ public final class BroadcastQueue { // If we had finished the last ordered broadcast, then // make sure all processes have correct oom and sched // adjustments. - mService.updateOomAdjLocked(); + mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER); } // when we have no more ordered broadcast on this queue, stop logging diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 44d435f2b539..8ae7c7d3e0c8 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -90,6 +90,21 @@ import java.util.Arrays; public final class OomAdjuster { private static final String TAG = "OomAdjuster"; + static final String OOM_ADJ_REASON_METHOD = "updateOomAdj"; + static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh"; + static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange"; + static final String OOM_ADJ_REASON_FINISH_RECEIVER = OOM_ADJ_REASON_METHOD + "_finishReceiver"; + static final String OOM_ADJ_REASON_START_RECEIVER = OOM_ADJ_REASON_METHOD + "_startReceiver"; + static final String OOM_ADJ_REASON_BIND_SERVICE = OOM_ADJ_REASON_METHOD + "_bindService"; + static final String OOM_ADJ_REASON_UNBIND_SERVICE = OOM_ADJ_REASON_METHOD + "_unbindService"; + static final String OOM_ADJ_REASON_START_SERVICE = OOM_ADJ_REASON_METHOD + "_startService"; + static final String OOM_ADJ_REASON_GET_PROVIDER = OOM_ADJ_REASON_METHOD + "_getProvider"; + static final String OOM_ADJ_REASON_REMOVE_PROVIDER = OOM_ADJ_REASON_METHOD + "_removeProvider"; + static final String OOM_ADJ_REASON_UI_VISIBILITY = OOM_ADJ_REASON_METHOD + "_uiVisibility"; + static final String OOM_ADJ_REASON_WHITELIST = OOM_ADJ_REASON_METHOD + "_whitelistChange"; + static final String OOM_ADJ_REASON_PROCESS_BEGIN = OOM_ADJ_REASON_METHOD + "_processBegin"; + static final String OOM_ADJ_REASON_PROCESS_END = OOM_ADJ_REASON_METHOD + "_processEnd"; + /** * For some direct access we need to power manager. */ @@ -156,10 +171,12 @@ public final class OomAdjuster { * @param app The process to update * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps * if necessary, or skip. + * @param oomAdjReason * @return whether updateOomAdjLocked(app) was successful. */ @GuardedBy("mService") - final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) { + boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll, + String oomAdjReason) { final ProcessRecord TOP_APP = mService.getTopAppLocked(); final boolean wasCached = app.cached; @@ -177,7 +194,7 @@ public final class OomAdjuster { && (wasCached != app.cached || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) { // Changed to/from cached state, so apps after it in the LRU // list may also be changed. - updateOomAdjLocked(); + updateOomAdjLocked(oomAdjReason); } return success; } @@ -195,8 +212,8 @@ public final class OomAdjuster { } @GuardedBy("mService") - final void updateOomAdjLocked() { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "updateOomAdj"); + void updateOomAdjLocked(String oomAdjReason) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason); mService.mOomAdjProfiler.oomAdjStarted(); final ProcessRecord TOP_APP = mService.getTopAppLocked(); final long now = SystemClock.uptimeMillis(); @@ -2009,7 +2026,7 @@ public final class OomAdjuster { } } if (changed) { - updateOomAdjLocked(); + updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST); } } @@ -2019,7 +2036,7 @@ public final class OomAdjuster { final UidRecord uidRec = mActiveUids.get(uid); if (uidRec != null && uidRec.curWhitelist != onWhitelist) { uidRec.curWhitelist = onWhitelist; - updateOomAdjLocked(); + updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST); } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 0a926f9a801a..316368a52ce2 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2227,9 +2227,10 @@ public final class ProcessList { for (AppZygote appZygote : zygotesToKill) { killAppZygoteIfNeededLocked(appZygote); } - mService.updateOomAdjLocked(); + mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); return N > 0; } + @GuardedBy("mService") boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart, boolean allowRestart, String reason) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 933f41c47167..49930c1f4d62 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1301,7 +1301,7 @@ class ProcessRecord implements WindowProcessListener { } mService.mProcessList.updateLruProcessLocked(this, activityChange, null /* client */); if (updateOomAdj) { - mService.updateOomAdjLocked(); + mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_ACTIVITY); } } } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 873cadb5a9d9..cd8167ae4653 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -3097,6 +3097,7 @@ public class AppOpsService extends IAppOpsService.Stub { int nonpackageUid; final static Binder sBinder = new Binder(); IBinder mToken; + boolean targetsUid; Shell(IAppOpsService iface, AppOpsService internal) { mInterface = iface; @@ -3190,6 +3191,8 @@ public class AppOpsService extends IAppOpsService.Stub { for (String argument; (argument = getNextArg()) != null;) { if ("--user".equals(argument)) { userId = UserHandle.parseUserArg(getNextArgRequired()); + } else if ("--uid".equals(argument)) { + targetsUid = true; } else { if (packageName == null) { packageName = argument; @@ -3288,7 +3291,7 @@ public class AppOpsService extends IAppOpsService.Stub { pw.println(" Starts a given operation for a particular application."); pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> "); pw.println(" Stops a given operation for a particular application."); - pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>"); + pw.println(" set [--user <USER_ID>] <--uid PACKAGE | PACKAGE | UID> <OP> <MODE>"); pw.println(" Set the mode for a particular application and operation."); pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]"); pw.println(" Return the mode for a particular application and optional operation."); @@ -3306,6 +3309,7 @@ public class AppOpsService extends IAppOpsService.Stub { pw.println(" <MODE> one of allow, ignore, deny, or default"); pw.println(" <USER_ID> the user id under which the package is installed. If --user is not"); pw.println(" specified, the current user is assumed."); + pw.println(" --uid PACKAGE refer to the UID of the package"); } static int onShellCommand(Shell shell, String cmd) { @@ -3332,9 +3336,17 @@ public class AppOpsService extends IAppOpsService.Stub { return -1; } - if (shell.packageName != null) { + if (!shell.targetsUid && shell.packageName != null) { shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode); + } else if (shell.targetsUid && shell.packageName != null) { + try { + final int uid = shell.mInternal.mContext.getPackageManager() + .getPackageUid(shell.packageName, shell.userId); + shell.mInterface.setUidMode(shell.op, uid, mode); + } catch (PackageManager.NameNotFoundException e) { + return -1; + } } else { shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode); } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 44c1715cfed5..c573332235d8 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -114,8 +114,10 @@ import java.util.ArrayList; // All post* methods are asynchronous /*package*/ void onSystemReady() { - synchronized (mDeviceStateLock) { - mBtHelper.onSystemReady(); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.onSystemReady(); + } } } @@ -151,8 +153,10 @@ import java.util.ArrayList; * @param intent */ /*package*/ void receiveBtEvent(@NonNull Intent intent) { - synchronized (mDeviceStateLock) { - mBtHelper.receiveBtEvent(intent); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.receiveBtEvent(intent); + } } } @@ -350,13 +354,19 @@ import java.util.ArrayList; sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device); } + @GuardedBy("mSetModeLock") /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode, @NonNull String eventSource) { - mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource); + synchronized (mDeviceStateLock) { + mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource); + } } + @GuardedBy("mSetModeLock") /*package*/ void stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource) { - mBtHelper.stopBluetoothScoForClient(cb, eventSource); + synchronized (mDeviceStateLock) { + mBtHelper.stopBluetoothScoForClient(cb, eventSource); + } } //--------------------------------------------------------------------- @@ -479,6 +489,10 @@ import java.util.ArrayList; hearingAidProfile); } + /*package*/ void postScoClientDied(Object obj) { + sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj); + } + //--------------------------------------------------------------------- // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) // only call from a "handle"* method or "on"* method @@ -708,8 +722,10 @@ import java.util.ArrayList; } break; case MSG_BT_HEADSET_CNCT_FAILED: - synchronized (mDeviceStateLock) { - mBtHelper.resetBluetoothSco(); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.resetBluetoothSco(); + } } break; case MSG_IL_BTA2DP_DOCK_TIMEOUT: @@ -742,8 +758,17 @@ import java.util.ArrayList; } break; case MSG_I_DISCONNECT_BT_SCO: - synchronized (mDeviceStateLock) { - mBtHelper.disconnectBluetoothSco(msg.arg1); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.disconnectBluetoothSco(msg.arg1); + } + } + break; + case MSG_L_SCOCLIENT_DIED: + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.scoClientDied(msg.arg1); + } } break; case MSG_TOGGLE_HDMI: @@ -774,8 +799,10 @@ import java.util.ArrayList; } break; case MSG_DISCONNECT_BT_HEADSET: - synchronized (mDeviceStateLock) { - mBtHelper.disconnectHeadset(); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.disconnectHeadset(); + } } break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: @@ -794,8 +821,10 @@ import java.util.ArrayList; } break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: - synchronized (mDeviceStateLock) { - mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + } } break; case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: { @@ -892,6 +921,8 @@ import java.util.ArrayList; private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28; // process external command to (dis)connect or change active A2DP device private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT = 29; + // a ScoClient died in BtHelper + private static final int MSG_L_SCOCLIENT_DIED = 30; private static boolean isMessageHandledUnderWakelock(int msgId) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index aee08bb09401..d30a9d2b158e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3484,7 +3484,9 @@ public class AudioService extends IAudioService.Stub !mSystemReady) { return; } - mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource); + synchronized (mDeviceBroker.mSetModeLock) { + mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource); + } } /** @see AudioManager#stopBluetoothSco() */ @@ -3496,7 +3498,9 @@ public class AudioService extends IAudioService.Stub final String eventSource = new StringBuilder("stopBluetoothSco()") .append(") from u/pid:").append(Binder.getCallingUid()).append("/") .append(Binder.getCallingPid()).toString(); - mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource); + synchronized (mDeviceBroker.mSetModeLock) { + mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource); + } } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 2d9156b8782e..332ff362392a 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -36,6 +36,8 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; @@ -163,6 +165,8 @@ public class BtHelper { //---------------------------------------------------------------------- // Interface for AudioDeviceBroker + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onSystemReady() { mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR; resetBluetoothSco(); @@ -231,6 +235,8 @@ public class BtHelper { return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType()); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void receiveBtEvent(Intent intent) { final String action = intent.getAction(); if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) { @@ -317,6 +323,8 @@ public class BtHelper { * * @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept */ + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void disconnectBluetoothSco(int exceptPid) { checkScoAudioState(); if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) { @@ -325,6 +333,8 @@ public class BtHelper { clearAllScoClients(exceptPid, true); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void startBluetoothScoForClient(IBinder cb, int scoAudioMode, @NonNull String eventSource) { ScoClient client = getScoClient(cb, true); @@ -344,6 +354,8 @@ public class BtHelper { Binder.restoreCallingIdentity(ident); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void stopBluetoothScoForClient(IBinder cb, @NonNull String eventSource) { ScoClient client = getScoClient(cb, false); @@ -401,6 +413,8 @@ public class BtHelper { mDeviceBroker.postDisconnectHearingAid(); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void resetBluetoothSco() { clearAllScoClients(0, false); mScoAudioState = SCO_STATE_INACTIVE; @@ -409,6 +423,8 @@ public class BtHelper { mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco"); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void disconnectHeadset() { setBtScoActiveDevice(null); mBluetoothHeadset = null; @@ -454,6 +470,8 @@ public class BtHelper { /*eventSource*/ "mBluetoothProfileServiceListener"); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) { // Discard timeout message mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); @@ -540,6 +558,9 @@ public class BtHelper { return result; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") private void setBtScoActiveDevice(BluetoothDevice btDevice) { Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice); final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice; @@ -621,6 +642,20 @@ public class BtHelper { }; //---------------------------------------------------------------------- + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + /*package*/ synchronized void scoClientDied(Object obj) { + final ScoClient client = (ScoClient) obj; + Log.w(TAG, "SCO client died"); + int index = mScoClients.indexOf(client); + if (index < 0) { + Log.w(TAG, "unregistered SCO client died"); + } else { + client.clearCount(true); + mScoClients.remove(client); + } + } + private class ScoClient implements IBinder.DeathRecipient { private IBinder mCb; // To be notified of client's death private int mCreatorPid; @@ -634,21 +669,14 @@ public class BtHelper { @Override public void binderDied() { - // this is the only place the implementation of ScoClient needs to be synchronized - // on the instance, as all other methods are directly or indirectly called from - // package-private methods, which are synchronized - synchronized (BtHelper.this) { - Log.w(TAG, "SCO client died"); - int index = mScoClients.indexOf(this); - if (index < 0) { - Log.w(TAG, "unregistered SCO client died"); - } else { - clearCount(true); - mScoClients.remove(this); - } - } + // process this from DeviceBroker's message queue to take the right locks since + // this event can impact SCO mode and requires querying audio mode stack + mDeviceBroker.postScoClientDied(this); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") void incCount(int scoAudioMode) { requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode); if (mStartcount == 0) { @@ -663,6 +691,9 @@ public class BtHelper { mStartcount++; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") void decCount() { if (mStartcount == 0) { Log.w(TAG, "ScoClient.decCount() already 0"); @@ -679,6 +710,9 @@ public class BtHelper { } } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") void clearCount(boolean stopSco) { if (mStartcount != 0) { try { @@ -714,6 +748,9 @@ public class BtHelper { return count; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") private void requestScoState(int state, int scoAudioMode) { checkScoAudioState(); int clientCount = totalCount(); @@ -728,74 +765,71 @@ public class BtHelper { broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); // Accept SCO audio activation only in NORMAL audio mode or if the mode is // currently controlled by the same client process. - // TODO do not sync that way, see b/123769055 - synchronized (mDeviceBroker.mSetModeLock) { - int modeOwnerPid = mDeviceBroker.getSetModeDeathHandlers().isEmpty() - ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid(); - if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) { - Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid " - + modeOwnerPid + " != creatorPid " + mCreatorPid); - broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - return; - } - switch (mScoAudioState) { - case SCO_STATE_INACTIVE: - mScoAudioMode = scoAudioMode; - if (scoAudioMode == SCO_MODE_UNDEFINED) { - mScoAudioMode = SCO_MODE_VIRTUAL_CALL; - if (mBluetoothHeadsetDevice != null) { - mScoAudioMode = Settings.Global.getInt( - mDeviceBroker.getContentResolver(), - "bluetooth_sco_channel_" - + mBluetoothHeadsetDevice.getAddress(), - SCO_MODE_VIRTUAL_CALL); - if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) { - mScoAudioMode = SCO_MODE_VIRTUAL_CALL; - } - } - } - if (mBluetoothHeadset == null) { - if (getBluetoothHeadset()) { - mScoAudioState = SCO_STATE_ACTIVATE_REQ; - } else { - Log.w(TAG, "requestScoState: getBluetoothHeadset failed during" - + " connection, mScoAudioMode=" + mScoAudioMode); - broadcastScoConnectionState( - AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + int modeOwnerPid = mDeviceBroker.getSetModeDeathHandlers().isEmpty() + ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid(); + if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) { + Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid " + + modeOwnerPid + " != creatorPid " + mCreatorPid); + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + return; + } + switch (mScoAudioState) { + case SCO_STATE_INACTIVE: + mScoAudioMode = scoAudioMode; + if (scoAudioMode == SCO_MODE_UNDEFINED) { + mScoAudioMode = SCO_MODE_VIRTUAL_CALL; + if (mBluetoothHeadsetDevice != null) { + mScoAudioMode = Settings.Global.getInt( + mDeviceBroker.getContentResolver(), + "bluetooth_sco_channel_" + + mBluetoothHeadsetDevice.getAddress(), + SCO_MODE_VIRTUAL_CALL); + if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) { + mScoAudioMode = SCO_MODE_VIRTUAL_CALL; } - break; - } - if (mBluetoothHeadsetDevice == null) { - Log.w(TAG, "requestScoState: no active device while connecting," - + " mScoAudioMode=" + mScoAudioMode); - broadcastScoConnectionState( - AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - break; } - if (connectBluetoothScoAudioHelper(mBluetoothHeadset, - mBluetoothHeadsetDevice, mScoAudioMode)) { - mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + } + if (mBluetoothHeadset == null) { + if (getBluetoothHeadset()) { + mScoAudioState = SCO_STATE_ACTIVATE_REQ; } else { - Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice - + " failed, mScoAudioMode=" + mScoAudioMode); + Log.w(TAG, "requestScoState: getBluetoothHeadset failed during" + + " connection, mScoAudioMode=" + mScoAudioMode); broadcastScoConnectionState( AudioManager.SCO_AUDIO_STATE_DISCONNECTED); } break; - case SCO_STATE_DEACTIVATING: - mScoAudioState = SCO_STATE_ACTIVATE_REQ; + } + if (mBluetoothHeadsetDevice == null) { + Log.w(TAG, "requestScoState: no active device while connecting," + + " mScoAudioMode=" + mScoAudioMode); + broadcastScoConnectionState( + AudioManager.SCO_AUDIO_STATE_DISCONNECTED); break; - case SCO_STATE_DEACTIVATE_REQ: + } + if (connectBluetoothScoAudioHelper(mBluetoothHeadset, + mBluetoothHeadsetDevice, mScoAudioMode)) { mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; - broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); - break; - default: - Log.w(TAG, "requestScoState: failed to connect in state " - + mScoAudioState + ", scoAudioMode=" + scoAudioMode); - broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - break; + } else { + Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice + + " failed, mScoAudioMode=" + mScoAudioMode); + broadcastScoConnectionState( + AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + } + break; + case SCO_STATE_DEACTIVATING: + mScoAudioState = SCO_STATE_ACTIVATE_REQ; + break; + case SCO_STATE_DEACTIVATE_REQ: + mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); + break; + default: + Log.w(TAG, "requestScoState: failed to connect in state " + + mScoAudioState + ", scoAudioMode=" + scoAudioMode); + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + break; - } } } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { switch (mScoAudioState) { @@ -906,6 +940,9 @@ public class BtHelper { return null; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") private void clearAllScoClients(int exceptPid, boolean stopSco) { ScoClient savedClient = null; for (ScoClient cl : mScoClients) { diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java index a5f22175331d..fdb499b5cd0e 100644 --- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java @@ -140,6 +140,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { private AudioPlayerStateMonitor mAudioPlayerStateMonitor; // Used to notify System UI and Settings when remote volume was changed. + @GuardedBy("mLock") final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers = new RemoteCallbackList<>(); @@ -287,17 +288,19 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { if (!session.isActive()) { return; } - int size = mRemoteVolumeControllers.beginBroadcast(); - MediaSession.Token token = session.getSessionToken(); - for (int i = size - 1; i >= 0; i--) { - try { - IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); - cb.remoteVolumeChanged(token, flags); - } catch (Exception e) { - Log.w(TAG, "Error sending volume change.", e); + synchronized (mLock) { + int size = mRemoteVolumeControllers.beginBroadcast(); + MediaSession.Token token = session.getSessionToken(); + for (int i = size - 1; i >= 0; i--) { + try { + IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); + cb.remoteVolumeChanged(token, flags); + } catch (Exception e) { + Log.w(TAG, "Error sending volume change.", e); + } } + mRemoteVolumeControllers.finishBroadcast(); } - mRemoteVolumeControllers.finishBroadcast(); } @Override @@ -647,19 +650,21 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { return; } - int size = mRemoteVolumeControllers.beginBroadcast(); - MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); - MediaSession.Token token = record == null ? null : record.getSessionToken(); + synchronized (mLock) { + int size = mRemoteVolumeControllers.beginBroadcast(); + MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); + MediaSession.Token token = record == null ? null : record.getSessionToken(); - for (int i = size - 1; i >= 0; i--) { - try { - IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); - cb.updateRemoteController(token); - } catch (Exception e) { - Log.w(TAG, "Error sending default remote volume.", e); + for (int i = size - 1; i >= 0; i--) { + try { + IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); + cb.updateRemoteController(token); + } catch (Exception e) { + Log.w(TAG, "Error sending default remote volume.", e); + } } + mRemoteVolumeControllers.finishBroadcast(); } - mRemoteVolumeControllers.finishBroadcast(); } void pushSession2TokensChangedLocked(int userId) { @@ -1676,11 +1681,13 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); - try { - enforceStatusBarServicePermission("listen for volume changes", pid, uid); - mRemoteVolumeControllers.register(rvc); - } finally { - Binder.restoreCallingIdentity(token); + synchronized (mLock) { + try { + enforceStatusBarServicePermission("listen for volume changes", pid, uid); + mRemoteVolumeControllers.register(rvc); + } finally { + Binder.restoreCallingIdentity(token); + } } } @@ -1689,11 +1696,13 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); - try { - enforceStatusBarServicePermission("listen for volume changes", pid, uid); - mRemoteVolumeControllers.unregister(rvc); - } finally { - Binder.restoreCallingIdentity(token); + synchronized (mLock) { + try { + enforceStatusBarServicePermission("listen for volume changes", pid, uid); + mRemoteVolumeControllers.unregister(rvc); + } finally { + Binder.restoreCallingIdentity(token); + } } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7f1b25ca3ca3..042ac8c5760e 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1689,6 +1689,9 @@ public class NotificationManagerService extends SystemService { mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray( com.android.internal.R.array.config_nonBlockableNotificationPackages)); + + mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( + com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); } @Override diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 7e74cc2368cd..1f5b99cb3349 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -80,6 +80,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -96,7 +97,7 @@ public class ZenModeHelper { private final Context mContext; private final H mHandler; private final SettingsObserver mSettingsObserver; - @VisibleForTesting protected final AppOpsManager mAppOps; + private final AppOpsManager mAppOps; @VisibleForTesting protected final NotificationManager mNotificationManager; @VisibleForTesting protected ZenModeConfig mDefaultConfig; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); @@ -123,11 +124,13 @@ public class ZenModeHelper { @VisibleForTesting protected boolean mIsBootComplete; + private String[] mPriorityOnlyDndExemptPackages; + public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) { mContext = context; mHandler = new H(looper); addCallback(mMetrics); - mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mAppOps = context.getSystemService(AppOpsManager.class); mNotificationManager = context.getSystemService(NotificationManager.class); mDefaultConfig = readDefaultConfig(mContext.getResources()); @@ -214,6 +217,10 @@ public class ZenModeHelper { loadConfigForUser(user, "onUserUnlocked"); } + void setPriorityOnlyDndExemptPackages(String[] packages) { + mPriorityOnlyDndExemptPackages = packages; + } + private void loadConfigForUser(int user, String reason) { if (mUser == user || user < UserHandle.USER_SYSTEM) return; mUser = user; @@ -994,53 +1001,47 @@ public class ZenModeHelper { for (int usage : AudioAttributes.SDK_USAGES) { final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage); if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) { - applyRestrictions(false /*mute*/, usage); + applyRestrictions(zenPriorityOnly, false /*mute*/, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) { - applyRestrictions(muteNotifications || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteNotifications || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) { - applyRestrictions(muteCalls || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteCalls || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) { - applyRestrictions(muteAlarms || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteAlarms || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) { - applyRestrictions(muteMedia || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteMedia || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) { if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { // normally DND will only restrict touch sounds, not haptic feedback/vibrations - applyRestrictions(muteSystem || muteEverything, usage, + applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage, AppOpsManager.OP_PLAY_AUDIO); - applyRestrictions(false, usage, AppOpsManager.OP_VIBRATE); + applyRestrictions(zenPriorityOnly, false, usage, AppOpsManager.OP_VIBRATE); } else { - applyRestrictions(muteSystem || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage); } } else { - applyRestrictions(muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteEverything, usage); } } } @VisibleForTesting - protected void applyRestrictions(boolean mute, int usage, int code) { - final String[] exceptionPackages = null; // none (for now) - - // Only do this if we are executing within the system process... otherwise - // we are running as test code, so don't have access to the protected call. - if (Process.myUid() == Process.SYSTEM_UID) { - final long ident = Binder.clearCallingIdentity(); - try { - mAppOps.setRestriction(code, usage, - mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, - exceptionPackages); - } finally { - Binder.restoreCallingIdentity(ident); - } + protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage, int code) { + final long ident = Binder.clearCallingIdentity(); + try { + mAppOps.setRestriction(code, usage, + mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, + zenPriorityOnly ? mPriorityOnlyDndExemptPackages : null); + } finally { + Binder.restoreCallingIdentity(ident); } } @VisibleForTesting - protected void applyRestrictions(boolean mute, int usage) { - applyRestrictions(mute, usage, AppOpsManager.OP_VIBRATE); - applyRestrictions(mute, usage, AppOpsManager.OP_PLAY_AUDIO); + protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage) { + applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_VIBRATE); + applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_PLAY_AUDIO); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 77e7df8b978e..c4d4106804e1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5738,6 +5738,8 @@ public class PackageManagerService extends IPackageManager.Stub "getWhitelistedRestrictedPermissions for user " + userId); } + final PackageParser.Package pkg; + synchronized (mPackages) { final PackageSetting packageSetting = mSettings.mPackages.get(packageName); if (packageSetting == null) { @@ -5745,6 +5747,8 @@ public class PackageManagerService extends IPackageManager.Stub return null; } + pkg = packageSetting.pkg; + final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission( Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS) == PackageManager.PERMISSION_GRANTED; @@ -5772,14 +5776,14 @@ public class PackageManagerService extends IPackageManager.Stub UserHandle.getCallingUserId())) { return null; } + } - final long identity = Binder.clearCallingIdentity(); - try { - return mPermissionManager.getWhitelistedRestrictedPermissions( - packageSetting.pkg, whitelistFlags, userId); - } finally { - Binder.restoreCallingIdentity(identity); - } + final long identity = Binder.clearCallingIdentity(); + try { + return mPermissionManager.getWhitelistedRestrictedPermissions( + pkg, whitelistFlags, userId); + } finally { + Binder.restoreCallingIdentity(identity); } } @@ -5790,6 +5794,10 @@ public class PackageManagerService extends IPackageManager.Stub // Other argument checks are done in get/setWhitelistedRestrictedPermissions Preconditions.checkNotNull(permission); + if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) { + return false; + } + List<String> permissions = getWhitelistedRestrictedPermissions(packageName, whitelistFlags, userId); if (permissions == null) { @@ -5797,13 +5805,31 @@ public class PackageManagerService extends IPackageManager.Stub } if (permissions.indexOf(permission) < 0) { permissions.add(permission); - setWhitelistedRestrictedPermissions(packageName, permissions, + return setWhitelistedRestrictedPermissions(packageName, permissions, whitelistFlags, userId); - return true; } return false; } + private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission( + @NonNull String permission) { + synchronized (mPackages) { + final BasePermission bp = mPermissionManager.getPermissionTEMP(permission); + if (bp == null) { + Slog.w(TAG, "No such permissions: " + permission); + return false; + } + if (bp.isHardOrSoftRestricted() && bp.isImmutablyRestricted() + && mContext.checkCallingOrSelfPermission( + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Cannot modify whitelisting of an immutably " + + "restricted permission: " + permission); + } + return true; + } + } + @Override public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName, @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags, @@ -5811,17 +5837,20 @@ public class PackageManagerService extends IPackageManager.Stub // Other argument checks are done in get/setWhitelistedRestrictedPermissions Preconditions.checkNotNull(permission); + if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) { + return false; + } + final List<String> permissions = getWhitelistedRestrictedPermissions(packageName, whitelistFlags, userId); if (permissions != null && permissions.remove(permission)) { - setWhitelistedRestrictedPermissions(packageName, permissions, + return setWhitelistedRestrictedPermissions(packageName, permissions, whitelistFlags, userId); - return true; } return false; } - private void setWhitelistedRestrictedPermissions(@NonNull String packageName, + private boolean setWhitelistedRestrictedPermissions(@NonNull String packageName, @Nullable List<String> permissions, @PermissionWhitelistFlags int whitelistFlag, @UserIdInt int userId) { Preconditions.checkNotNull(packageName); @@ -5838,13 +5867,17 @@ public class PackageManagerService extends IPackageManager.Stub "setWhitelistedRestrictedPermissions for user " + userId); } + final PackageParser.Package pkg; + synchronized (mPackages) { final PackageSetting packageSetting = mSettings.mPackages.get(packageName); if (packageSetting == null) { Slog.w(TAG, "Unknown package: " + packageName); - return; + return false; } + pkg = packageSetting.pkg; + final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission( Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS) == PackageManager.PERMISSION_GRANTED; @@ -5869,7 +5902,7 @@ public class PackageManagerService extends IPackageManager.Stub packageName, whitelistFlag, userId); if (permissions == null || permissions.isEmpty()) { if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) { - return; + return true; } } else { // Only the system can add and remove while the installer can only remove. @@ -5895,18 +5928,20 @@ public class PackageManagerService extends IPackageManager.Stub if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(), UserHandle.getCallingUserId())) { - return; + return false; } + } - final long identity = Binder.clearCallingIdentity(); - try { - mPermissionManager.setWhitelistedRestrictedPermissions(packageSetting.pkg, - new int[]{userId}, permissions, Process.myUid(), whitelistFlag, - mPermissionCallback); - } finally { - Binder.restoreCallingIdentity(identity); - } + final long identity = Binder.clearCallingIdentity(); + try { + mPermissionManager.setWhitelistedRestrictedPermissions(pkg, + new int[]{userId}, permissions, Process.myUid(), whitelistFlag, + mPermissionCallback); + } finally { + Binder.restoreCallingIdentity(identity); } + + return true; } @Override @@ -14620,6 +14655,20 @@ public class PackageManagerService extends IPackageManager.Stub return mUser; } + /** + * Gets the user handle for the user that the rollback agent should + * use to look up information about this installation when enabling + * rollback. + */ + UserHandle getRollbackUser() { + // The session for packages installed for "all" users is + // associated with the "system" user. + if (mUser == UserHandle.ALL) { + return UserHandle.SYSTEM; + } + return mUser; + } + HandlerParams setTraceMethod(String traceMethod) { this.traceMethod = traceMethod; return this; @@ -15238,7 +15287,7 @@ public class PackageManagerService extends IPackageManager.Stub installedUsers); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, - getUser().getIdentifier()); + getRollbackUser().getIdentifier()); enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), PACKAGE_MIME_TYPE); enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 4e4a0e420d86..6b804df2e068 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2423,6 +2423,16 @@ class PackageManagerShellCommand extends ShellCommand { sessionParams.setStaged(); break; case "--enable-rollback": + if (params.installerPackageName == null) { + // com.android.shell has the TEST_MANAGE_ROLLBACKS + // permission needed to enable rollback for non-module + // packages, which is likely what the user wants when + // enabling rollback through the shell command. Set + // the installer to com.android.shell if no installer + // has been provided so that the user doesn't have to + // remember to set it themselves. + params.installerPackageName = "com.android.shell"; + } sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; break; default: diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index dae07bdc37d5..db2fba97f4ac 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4419,7 +4419,7 @@ public final class Settings { ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION", ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE", ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE, "ALLOW_AUDIO_PLAYBACK_CAPTURE", - ApplicationInfo.PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX, "ALLOW_EXTERNAL_STORAGE_SANDBOX", + ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE, "PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE", ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND", ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE", ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE", @@ -4743,7 +4743,7 @@ public final class Settings { } pw.print(prefix); pw.print(" "); pw.print(perm); final BasePermission bp = mPermissions.getPermission(perm); - if (bp != null && bp.isRestricted()) { + if (bp != null && bp.isHardOrSoftRestricted()) { pw.println(": restricted=true"); } else { pw.println(); diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index 490c647c22b1..6d22faa7032e 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -203,12 +203,17 @@ public final class BasePermission { && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; } - public boolean isRestricted() { + public boolean isHardOrSoftRestricted() { return perm != null && perm.info != null && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0; } + public boolean isImmutablyRestricted() { + return perm != null && perm.info != null + && (perm.info.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0; + } + public boolean isSignature() { return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_SIGNATURE; 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 dd63e3ca290e..9ede263284a1 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2059,7 +2059,7 @@ public class PermissionManagerService { return; } - if (RESTRICTED_PERMISSIONS_ENABLED && bp.isRestricted() + if (RESTRICTED_PERMISSIONS_ENABLED && bp.isHardOrSoftRestricted() && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) { Log.e(TAG, "Cannot grant restricted non-exempt permission " + permName + " for package " + packageName); @@ -2241,7 +2241,7 @@ public class PermissionManagerService { continue; } - if (!bp.isRestricted()) { + if (!bp.isHardOrSoftRestricted()) { continue; } @@ -2294,13 +2294,16 @@ public class PermissionManagerService { updatePermissions = true; + final boolean wasWhitelisted = (oldFlags + & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0; + final boolean isWhitelisted = (newFlags + & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0; + // If the permission is policy fixed as granted but it is no longer // on any of the whitelists we need to clear the policy fixed flag // as whitelisting trumps policy i.e. policy cannot grant a non // grantable permission. if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) { - final boolean isWhitelisted = (newFlags - & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0; final boolean isGranted = permissionsState.hasPermission(permissionName, userId); if (!isWhitelisted && isGranted) { mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED; @@ -2308,6 +2311,14 @@ public class PermissionManagerService { } } + // If we are whitelisting an app that does not support runtime permissions + // we need to make sure it goes through the permission review UI at launch. + if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + && !wasWhitelisted && isWhitelisted) { + mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; + newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; + } + updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags, callingUid, userId, false, null /*callback*/); } diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 1fd8b711d348..a280d83fac27 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -19,6 +19,7 @@ package com.android.server.policy; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.GET_PERMISSIONS; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -36,9 +37,7 @@ import android.os.Process; import android.os.UserHandle; import android.permission.PermissionControllerManager; import android.permission.PermissionManagerInternal; -import android.util.ArraySet; import android.util.Slog; -import android.util.SparseArray; import android.util.SparseIntArray; import com.android.server.FgThread; @@ -46,7 +45,6 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import java.util.ArrayList; -import java.util.List; import java.util.concurrent.CountDownLatch; /** @@ -57,17 +55,10 @@ import java.util.concurrent.CountDownLatch; * and app ops - and vise versa. */ public final class PermissionPolicyService extends SystemService { - private static final String PLATFORM_PACKAGE = "android"; - private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName(); - // No need to lock as this is populated on boot when the OS is - // single threaded and is never mutated until a reboot. - private static final ArraySet<String> sAllRestrictedPermissions = new ArraySet<>(); - public PermissionPolicyService(@NonNull Context context) { super(context); - cacheAllRestrictedPermissions(context); } @Override @@ -101,20 +92,6 @@ public final class PermissionPolicyService extends SystemService { startWatchingRuntimePermissionChanges(getContext(), userId); } - private static void cacheAllRestrictedPermissions(@NonNull Context context) { - try { - final PackageInfo packageInfo = context.getPackageManager() - .getPackageInfo(PLATFORM_PACKAGE, PackageManager.GET_PERMISSIONS); - for (PermissionInfo permissionInfo : packageInfo.permissions) { - if (permissionInfo.isRestricted()) { - sAllRestrictedPermissions.add(permissionInfo.name); - } - } - } catch (NameNotFoundException impossible) { - /* cannot happen */ - } - } - private static void grantOrUpgradeDefaultRuntimePermissionsInNeeded(@NonNull Context context, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( @@ -162,7 +139,7 @@ public final class PermissionPolicyService extends SystemService { } private static @Nullable Context getUserContext(@NonNull Context context, - @NonNull UserHandle user) { + @Nullable UserHandle user) { if (context.getUser().equals(user)) { return context; } else { @@ -230,18 +207,31 @@ public final class PermissionPolicyService extends SystemService { private final @NonNull SparseIntArray mAllUids = new SparseIntArray(); /** - * All ops that need to be restricted + * All ops that need to be set to default + * + * Currently, only used by the restricted permissions logic. * * @see #syncRestrictedOps */ - private final @NonNull ArrayList<OpToRestrict> mOpsToRestrict = new ArrayList<>(); + private final @NonNull ArrayList<OpToRestrict> mOpsToDefault = new ArrayList<>(); /** - * All ops that need to be unrestricted + * All ops that need to be flipped to allow if default. + * + * Currently, only used by the restricted permissions logic. * * @see #syncRestrictedOps */ - private final @NonNull ArrayList<OpToUnrestrict> mOpsToUnrestrict = new ArrayList<>(); + private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllow = new ArrayList<>(); + + /** + * All ops that need to be flipped to ignore if default. + * + * Currently, only used by the restricted permissions logic. + * + * @see #syncRestrictedOps + */ + private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnore = new ArrayList<>(); /** * All foreground permissions @@ -262,89 +252,20 @@ public final class PermissionPolicyService extends SystemService { * <p>This processes ops previously added by {@link #addOpIfRestricted} */ private void syncRestrictedOps() { - final SparseIntArray unprocessedUids = mAllUids.clone(); - - // TRICKY: we set the app op for a restricted permission to allow if the app - // requesting the permission is whitelisted and to deny if the app requesting - // the permission is not whitelisted. However, there is another case where an - // app in a shared user can access a component in another app in the same shared - // user due to being in the same shared user and not by having the permission - // that guards the component form the rest of the world. We need to handle this. - // The way we do this is by setting app ops corresponding to non requested - // restricted permissions to allow as this would allow the shared uid access - // case and be okay for other apps as they would not have the permission and - // would fail on the permission checks before reaching the app op check. - final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid = - new SparseArray<>(); - - final int unrestrictCount = mOpsToUnrestrict.size(); - for (int i = 0; i < unrestrictCount; i++) { - final OpToUnrestrict op = mOpsToUnrestrict.get(i); - setUidModeAllowed(op.code, op.uid, op.packageName); - - // Keep track this permission was requested by the UID. - List<String> unrequestedRestrictedPermissions = - unrequestedRestrictedPermissionsForUid.get(op.uid); - if (unrequestedRestrictedPermissions == null) { - unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); - unrequestedRestrictedPermissionsForUid.put(op.uid, - unrequestedRestrictedPermissions); - } - unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); - - unprocessedUids.delete(op.uid); + final int allowCount = mOpsToAllow.size(); + for (int i = 0; i < allowCount; i++) { + final OpToUnrestrict op = mOpsToAllow.get(i); + setUidModeAllowedIfDefault(op.code, op.uid, op.packageName); } - final int restrictCount = mOpsToRestrict.size(); - for (int i = 0; i < restrictCount; i++) { - final OpToRestrict op = mOpsToRestrict.get(i); - setUidModeDefault(op.code, op.uid); - - // Keep track this permission was requested by the UID. - List<String> unrequestedRestrictedPermissions = - unrequestedRestrictedPermissionsForUid.get(op.uid); - if (unrequestedRestrictedPermissions == null) { - unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); - unrequestedRestrictedPermissionsForUid.put(op.uid, - unrequestedRestrictedPermissions); - } - unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); - - unprocessedUids.delete(op.uid); - } - - // Give root access - unprocessedUids.put(Process.ROOT_UID, Process.ROOT_UID); - - // Add records for UIDs that don't use any restricted permissions. - final int uidCount = unprocessedUids.size(); - for (int i = 0; i < uidCount; i++) { - final int uid = unprocessedUids.keyAt(i); - unrequestedRestrictedPermissionsForUid.put(uid, - new ArrayList<>(sAllRestrictedPermissions)); + final int ignoreCount = mOpsToIgnore.size(); + for (int i = 0; i < ignoreCount; i++) { + final OpToUnrestrict op = mOpsToIgnore.get(i); + setUidModeIgnoredIfDefault(op.code, op.uid, op.packageName); } - - // Flip ops for all unrequested restricted permission for the UIDs. - final int unrequestedUidCount = unrequestedRestrictedPermissionsForUid.size(); - for (int i = 0; i < unrequestedUidCount; i++) { - final List<String> unrequestedRestrictedPermissions = - unrequestedRestrictedPermissionsForUid.valueAt(i); - if (unrequestedRestrictedPermissions != null) { - final int uid = unrequestedRestrictedPermissionsForUid.keyAt(i); - final String[] packageNames = (uid != Process.ROOT_UID) - ? mPackageManager.getPackagesForUid(uid) - : new String[] {"root"}; - if (packageNames == null) { - continue; - } - final int permissionCount = unrequestedRestrictedPermissions.size(); - for (int j = 0; j < permissionCount; j++) { - final String permission = unrequestedRestrictedPermissions.get(j); - for (String packageName : packageNames) { - setUidModeAllowed(AppOpsManager.permissionToOpCode(permission), uid, - packageName); - } - } - } + final int defaultCount = mOpsToDefault.size(); + for (int i = 0; i < defaultCount; i++) { + final OpToRestrict op = mOpsToDefault.get(i); + setUidModeDefault(op.code, op.uid); } } @@ -411,12 +332,27 @@ public final class PermissionPolicyService extends SystemService { if (permissionInfo.isHardRestricted()) { if (applyRestriction) { - mOpsToRestrict.add(new OpToRestrict(uid, opCode)); + mOpsToDefault.add(new OpToRestrict(uid, opCode)); } else { - mOpsToUnrestrict.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); + mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); } } else if (permissionInfo.isSoftRestricted()) { - //TODO: Implement soft restrictions like storage here. + // Storage uses a special app op to decide the mount state and + // supports soft restriction where the restricted state allows + // the permission but only for accessing the medial collections. + if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission) + || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) { + if (applyRestriction) { + mOpsToDefault.add(new OpToRestrict(uid, + AppOpsManager.OP_LEGACY_STORAGE)); + } else if (pkg.applicationInfo.hasRequestedLegacyExternalStorage()) { + mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, + AppOpsManager.OP_LEGACY_STORAGE)); + } else { + mOpsToIgnore.add(new OpToUnrestrict(uid, pkg.packageName, + AppOpsManager.OP_LEGACY_STORAGE)); + } + } } } @@ -474,11 +410,20 @@ public final class PermissionPolicyService extends SystemService { } } - private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { + private void setUidModeAllowedIfDefault(int opCode, int uid, @NonNull String packageName) { + setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_ALLOWED, packageName); + } + + private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) { + setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName); + } + + private void setUidModeIfDefault(int opCode, int uid, int mode, + @NonNull String packageName) { final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { - mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); + mAppOpsManager.setUidMode(opCode, uid, mode); } } diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index 03814453fc52..1552fd517d30 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -312,10 +312,8 @@ public class ThermalManagerService extends SystemService { if (!mThermalEventListeners.register(listener, null)) { return false; } - if (mHalReady.get()) { - // Notify its callback after new client registered. - postEventListenerCurrentTemperatures(listener, null); - } + // Notify its callback after new client registered. + postEventListenerCurrentTemperatures(listener, null); return true; } finally { Binder.restoreCallingIdentity(token); @@ -334,10 +332,8 @@ public class ThermalManagerService extends SystemService { if (!mThermalEventListeners.register(listener, new Integer(type))) { return false; } - if (mHalReady.get()) { - // Notify its callback after new client registered. - postEventListenerCurrentTemperatures(listener, new Integer(type)); - } + // Notify its callback after new client registered. + postEventListenerCurrentTemperatures(listener, new Integer(type)); return true; } finally { Binder.restoreCallingIdentity(token); @@ -398,10 +394,8 @@ public class ThermalManagerService extends SystemService { if (!mThermalStatusListeners.register(listener)) { return false; } - if (mHalReady.get()) { - // Notify its callback after new client registered. - postStatusListener(listener); - } + // Notify its callback after new client registered. + postStatusListener(listener); return true; } finally { Binder.restoreCallingIdentity(token); diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index b2ac1b884483..654c47780f4a 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -147,6 +147,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C mLegacyRoleResolver = legacyRoleResolver; + RoleControllerManager.initializeRemoteServiceComponentName(context); + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); @@ -231,7 +233,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C // Run grants again Slog.i(LOG_TAG, "Granting default permissions..."); CompletableFuture<Void> result = new CompletableFuture<>(); - getOrCreateControllerService(userId).grantDefaultRoles(FgThread.getExecutor(), + getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(), successful -> { if (successful) { userState.setPackagesHash(packagesHash); @@ -318,7 +320,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } @NonNull - private RoleControllerManager getOrCreateControllerService(@UserIdInt int userId) { + private RoleControllerManager getOrCreateController(@UserIdInt int userId) { synchronized (mLock) { RoleControllerManager controller = mControllers.get(userId); if (controller == null) { @@ -330,7 +332,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } catch (NameNotFoundException e) { throw new RuntimeException(e); } - controller = new RoleControllerManager(context, FgThread.getHandler()); + controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName( + FgThread.getHandler(), context); mControllers.put(userId, controller); } return controller; @@ -474,7 +477,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); Preconditions.checkNotNull(callback, "callback cannot be null"); - getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, flags, + getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags, callback); } @@ -494,7 +497,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); Preconditions.checkNotNull(callback, "callback cannot be null"); - getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, flags, + getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags, callback); } @@ -513,7 +516,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); Preconditions.checkNotNull(callback, "callback cannot be null"); - getOrCreateControllerService(userId).onClearRoleHolders(roleName, flags, callback); + getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback); } @Override @@ -738,10 +741,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } }); if (packageName != null) { - getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, + getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, packageName, 0, callback); } else { - getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, + getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, callback); } try { @@ -762,10 +765,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } }); if (packageName != null) { - getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, + getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, packageName, 0, callback); } else { - getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, + getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, callback); } } @@ -791,10 +794,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C callback.accept(successful); }); if (packageName != null) { - getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME, + getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_HOME, packageName, 0, remoteCallback); } else { - getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0, + getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0, remoteCallback); } } diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index c1d872f23f0f..b5e706710823 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -435,6 +435,18 @@ public class BoundsAnimationController { moveFromFullscreen, moveToFullscreen, animationType); } + /** + * Cancel existing animation if the destination was modified. + */ + void cancel(final BoundsAnimationTarget target) { + final BoundsAnimator existing = mRunningAnimations.get(target); + if (existing != null) { + // Cancel animation. Since its already started, send animation end to client. + if (DEBUG) Slog.d(TAG, "cancel: mTarget= " + target); + existing.cancelAndCallAnimationEnd(); + } + } + @VisibleForTesting BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to, int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index bdb4d0474865..7515b3fa1249 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -388,7 +388,9 @@ public class TaskStack extends WindowContainer<Task> implements * @return true if bounds were updated to some non-empty value. */ boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) { + boolean animating = false; if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) { + animating = true; getFinalAnimationBounds(mTmpRect2); } else { mTmpRect2.set(inOutBounds); @@ -398,6 +400,13 @@ public class TaskStack extends WindowContainer<Task> implements if (updated) { inOutBounds.set(mTmpRect3); + // The final boundary is updated while there is an existing boundary animation. Let's + // cancel this animation to prevent the obsolete animation overwritten updated bounds. + if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) { + final DisplayContent displayContent = getDisplayContent(); + displayContent.mBoundsAnimationController.getHandler().post(() -> + displayContent.mBoundsAnimationController.cancel(this)); + } // Once we've set the bounds based on the rotation of the old bounds in the new // orientation, clear the animation target bounds since they are obsolete, and // cancel any currently running animations @@ -1585,7 +1594,6 @@ 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 @@ -1645,7 +1653,7 @@ public class TaskStack extends WindowContainer<Task> implements mBoundsAnimationTarget, false /* forceUpdate */); } - if (finalStackSize != null) { + if (finalStackSize != null && !mCancelCurrentBoundsAnimation) { setPinnedStackSize(finalStackSize, null); } else { // We have been canceled, so the final stack size is null, still run the @@ -1758,6 +1766,7 @@ public class TaskStack extends WindowContainer<Task> implements } final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType; + mCancelCurrentBoundsAnimation = false; displayContent.mBoundsAnimationController.getHandler().post(() -> { displayContent.mBoundsAnimationController.animateBounds(this, fromBounds, finalToBounds, animationDuration, finalSchedulePipModeChangedState, diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java index c8d1eb413ecf..74fe81c6f68e 100644 --- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java @@ -30,6 +30,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -38,6 +39,7 @@ import static org.testng.Assert.expectThrows; import android.app.backup.BackupManager; import android.app.backup.IBackupObserver; import android.app.backup.ISelectBackupTransportCallback; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; @@ -48,6 +50,7 @@ import android.os.Binder; import android.os.HandlerThread; import android.os.PowerManager; import android.os.PowerSaveState; +import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.provider.Settings; @@ -66,6 +69,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @@ -1130,6 +1134,31 @@ public class UserBackupManagerServiceTest { /* transportManager */ null)); } + /** + * Test verifying that creating a new instance registers the broadcast receiver for package + * tracking + */ + @Test + public void testCreateAndInitializeService_registersPackageTrackingReceiver() throws Exception { + Context contextSpy = Mockito.spy(mContext); + + UserBackupManagerService service = UserBackupManagerService.createAndInitializeService( + USER_ID, + contextSpy, + new Trampoline(mContext), + mBackupThread, + mBaseStateDir, + mDataDir, + mTransportManager); + + BroadcastReceiver packageTrackingReceiver = service.getPackageTrackingReceiver(); + assertThat(packageTrackingReceiver).isNotNull(); + + // One call for package changes and one call for sd card events. + verify(contextSpy, times(2)).registerReceiverAsUser( + eq(packageTrackingReceiver), eq(UserHandle.of(USER_ID)), any(), any(), any()); + } + private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() { return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks( USER_ID, mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager); diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index 164570a84cb0..cc64323e51c7 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -86,6 +86,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.net.Uri; import android.os.ConditionVariable; import android.os.DeadObjectException; @@ -100,6 +101,7 @@ import android.util.Pair; import com.android.internal.backup.IBackupTransport; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.KeyValueBackupJob; @@ -116,7 +118,6 @@ import com.android.server.backup.testing.TransportTestUtils; import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.testing.shadows.FrameworkShadowLooper; import com.android.server.testing.shadows.ShadowApplicationPackageManager; -import com.android.server.testing.shadows.ShadowBackupActivityThread; import com.android.server.testing.shadows.ShadowBackupDataInput; import com.android.server.testing.shadows.ShadowBackupDataOutput; import com.android.server.testing.shadows.ShadowEventLog; @@ -163,8 +164,7 @@ import java.util.stream.Stream; ShadowBackupDataInput.class, ShadowBackupDataOutput.class, ShadowEventLog.class, - ShadowQueuedWork.class, - ShadowBackupActivityThread.class, + ShadowQueuedWork.class }) @Presubmit public class KeyValueBackupTaskTest { @@ -179,6 +179,7 @@ public class KeyValueBackupTaskTest { @Mock private IBackupObserver mObserver; @Mock private IBackupManagerMonitor mMonitor; @Mock private OnTaskFinishedListener mListener; + @Mock private PackageManagerInternal mPackageManagerInternal; private UserBackupManagerService mBackupManagerService; private TransportData mTransport; private ShadowLooper mShadowBackupLooper; @@ -243,6 +244,11 @@ public class KeyValueBackupTaskTest { mShadowBackupLooper = shadowOf(mBackupHandler.getLooper()); ShadowEventLog.setUp(); mReporter = spy(new KeyValueBackupReporter(mBackupManagerService, mObserver, mMonitor)); + + when(mPackageManagerInternal.getApplicationEnabledState(any(), anyInt())) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + LocalServices.removeServiceForTest(PackageManagerInternal.class); + LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); } @After @@ -471,7 +477,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgentWithData(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1); runTask(task); @@ -484,7 +490,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgentWithData(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE); @@ -498,7 +504,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgentWithData(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1); runTask(task); @@ -1307,7 +1313,7 @@ public class KeyValueBackupTaskTest { argThat(packageInfo(PM_PACKAGE)), any(), anyInt())) .then(copyBackupDataTo(backupDataPath)); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> { @@ -1371,7 +1377,7 @@ public class KeyValueBackupTaskTest { setUpAgent(PACKAGE_1); when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> { @@ -1395,7 +1401,7 @@ public class KeyValueBackupTaskTest { setUpAgent(PACKAGE_1); when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> { @@ -1957,7 +1963,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); + doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); runTask(task); @@ -1970,7 +1976,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); + doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); runTask(task); @@ -1983,7 +1989,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); + doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); runTask(task); @@ -1996,7 +2002,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel)); @@ -2011,7 +2017,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel)); diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java deleted file mode 100644 index ca2e3b6dafef..000000000000 --- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.testing.shadows; - -import android.app.ActivityThread; -import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.RemoteException; - -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowActivityThread; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -import javax.annotation.Nonnull; - -/** - * Extends the existing {@link ShadowActivityThread} to add support for - * {@link PackageManager#getApplicationEnabledSetting(String)} in the shadow {@link PackageManager} - * returned by {@link ShadowBackupActivityThread#getPackageManager()}. - */ -@Implements(value = ActivityThread.class, isInAndroidSdk = false, looseSignatures = true) -public class ShadowBackupActivityThread extends ShadowActivityThread { - @Implementation - public static Object getPackageManager() { - ClassLoader classLoader = ShadowActivityThread.class.getClassLoader(); - Class<?> iPackageManagerClass; - try { - iPackageManagerClass = classLoader.loadClass("android.content.pm.IPackageManager"); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - - return Proxy.newProxyInstance( - classLoader, - new Class[] {iPackageManagerClass}, - new InvocationHandler() { - @Override - public Object invoke(Object proxy, @Nonnull Method method, Object[] args) - throws Exception { - if (method.getName().equals("getApplicationInfo")) { - String packageName = (String) args[0]; - int flags = (Integer) args[1]; - - try { - return RuntimeEnvironment.application - .getPackageManager() - .getApplicationInfo(packageName, flags); - } catch (PackageManager.NameNotFoundException e) { - throw new RemoteException(e.getMessage()); - } - } else if (method.getName().equals("getApplicationEnabledSetting")) { - return 0; - } else { - return null; - } - } - }); - } -} diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java deleted file mode 100644 index 97a6e6657b7a..000000000000 --- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java +++ /dev/null @@ -1,1217 +0,0 @@ -/* - * 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.backup.testutils; - -import android.content.ComponentName; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.IntentSender; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.ChangedPackages; -import android.content.pm.IDexModuleRegisterCallback; -import android.content.pm.IOnPermissionsChangeListener; -import android.content.pm.IPackageDataObserver; -import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageDeleteObserver2; -import android.content.pm.IPackageInstaller; -import android.content.pm.IPackageManager; -import android.content.pm.IPackageMoveObserver; -import android.content.pm.IPackageStatsObserver; -import android.content.pm.InstrumentationInfo; -import android.content.pm.KeySet; -import android.content.pm.ModuleInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ParceledListSlice; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; -import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.content.pm.SuspendDialogInfo; -import android.content.pm.VerifierDeviceIdentity; -import android.content.pm.VersionedPackage; -import android.content.pm.dex.IArtManager; -import android.graphics.Bitmap; -import android.os.IBinder; -import android.os.PersistableBundle; -import android.os.RemoteException; - -import java.util.List; - -/** - * Stub for IPackageManager to use in tests. - */ -public class IPackageManagerStub implements IPackageManager { - public static PackageInfo sPackageInfo; - public static int sApplicationEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - - @Override - public PackageInfo getPackageInfo(String packageName, int flags, int userId) - throws RemoteException { - return sPackageInfo; - } - - @Override - public int getApplicationEnabledSetting(String packageName, int userId) throws RemoteException { - return sApplicationEnabledSetting; - } - - @Override - public void checkPackageStartable(String packageName, int userId) throws RemoteException { - - } - - @Override - public boolean isPackageAvailable(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public int getPackageUid(String packageName, int flags, int userId) throws RemoteException { - return 0; - } - - @Override - public int[] getPackageGids(String packageName, int flags, int userId) throws RemoteException { - return new int[0]; - } - - @Override - public String[] currentToCanonicalPackageNames(String[] names) throws RemoteException { - return new String[0]; - } - - @Override - public String[] canonicalToCurrentPackageNames(String[] names) throws RemoteException { - return new String[0]; - } - - @Override - public PermissionInfo getPermissionInfo(String name, String packageName, int flags) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryPermissionsByGroup(String group, int flags) - throws RemoteException { - return null; - } - - @Override - public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getAllPermissionGroups(int flags) throws RemoteException { - return null; - } - - @Override - public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ActivityInfo getActivityInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean activitySupportsIntent(ComponentName className, Intent intent, - String resolvedType) - throws RemoteException { - return false; - } - - @Override - public ActivityInfo getReceiverInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ServiceInfo getServiceInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ProviderInfo getProviderInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public int checkPermission(String permName, String pkgName, int userId) throws RemoteException { - return 0; - } - - @Override - public int checkUidPermission(String permName, int uid) throws RemoteException { - return 0; - } - - @Override - public boolean addPermission(PermissionInfo info) throws RemoteException { - return false; - } - - @Override - public void removePermission(String name) throws RemoteException { - - } - - @Override - public void grantRuntimePermission(String packageName, String permissionName, int userId) - throws RemoteException { - - } - - @Override - public void revokeRuntimePermission(String packageName, String permissionName, int userId) - throws RemoteException { - - } - - @Override - public void resetRuntimePermissions() throws RemoteException { - - } - - @Override - public int getPermissionFlags(String permissionName, String packageName, int userId) - throws RemoteException { - return 0; - } - - @Override - public void updatePermissionFlags(String permissionName, String packageName, int flagMask, - int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) - throws RemoteException { - - } - - @Override - public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) - throws RemoteException { - - } - - @Override - public List<String> getWhitelistedRestrictedPermissions(String packageName, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public boolean addWhitelistedRestrictedPermission(String packageName, String permission, - int whitelistFlags, int userId) throws RemoteException { - return false; - } - - @Override - public boolean removeWhitelistedRestrictedPermission(String packageName, String permission, - int whitelistFlags, int userId) throws RemoteException { - return false; - } - - @Override - public boolean shouldShowRequestPermissionRationale(String permissionName, String packageName, - int userId) throws RemoteException { - return false; - } - - @Override - public boolean isProtectedBroadcast(String actionName) throws RemoteException { - return false; - } - - @Override - public int checkSignatures(String pkg1, String pkg2) throws RemoteException { - return 0; - } - - @Override - public int checkUidSignatures(int uid1, int uid2) throws RemoteException { - return 0; - } - - @Override - public List<String> getAllPackages() throws RemoteException { - return null; - } - - @Override - public String[] getPackagesForUid(int uid) throws RemoteException { - return new String[0]; - } - - @Override - public String getNameForUid(int uid) throws RemoteException { - return null; - } - - @Override - public String[] getNamesForUids(int[] uids) throws RemoteException { - return new String[0]; - } - - @Override - public int getUidForSharedUser(String sharedUserName) throws RemoteException { - return 0; - } - - @Override - public int getFlagsForUid(int uid) throws RemoteException { - return 0; - } - - @Override - public int getPrivateFlagsForUid(int uid) throws RemoteException { - return 0; - } - - @Override - public boolean isUidPrivileged(int uid) throws RemoteException { - return false; - } - - @Override - public String[] getAppOpPermissionPackages(String permissionName) throws RemoteException { - return new String[0]; - } - - @Override - public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId, - int targetUserId) throws RemoteException { - return false; - } - - @Override - public ParceledListSlice queryIntentActivities(Intent intent, String resolvedType, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentActivityOptions(ComponentName caller, Intent[] specifics, - String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentReceivers(Intent intent, String resolvedType, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentServices(Intent intent, String resolvedType, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentContentProviders(Intent intent, String resolvedType, - int flags, int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getInstalledPackages(int flags, int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getPackagesHoldingPermissions(String[] permissions, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getInstalledApplications(int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getPersistentApplications(int flags) throws RemoteException { - return null; - } - - @Override - public ProviderInfo resolveContentProvider(String name, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) - throws RemoteException { - - } - - @Override - public ParceledListSlice queryContentProviders(String processName, int uid, int flags, - String metaDataKey) throws RemoteException { - return null; - } - - @Override - public InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryInstrumentation(String targetPackage, int flags) - throws RemoteException { - return null; - } - - @Override - public void finishPackageInstall(int token, boolean didLaunch) throws RemoteException { - - } - - @Override - public void setInstallerPackageName(String targetPackage, String installerPackageName) - throws RemoteException { - - } - - @Override - public void setApplicationCategoryHint(String packageName, int categoryHint, - String callerPackageName) throws RemoteException { - - } - - @Override - public void deletePackageAsUser(String packageName, int versionCode, - IPackageDeleteObserver observer, int userId, int flags) throws RemoteException { - - } - - @Override - public void deletePackageVersioned(VersionedPackage versionedPackage, - IPackageDeleteObserver2 observer, int userId, int flags) throws RemoteException { - - } - - @Override - public String getInstallerPackageName(String packageName) throws RemoteException { - return null; - } - - @Override - public void resetApplicationPreferences(int userId) throws RemoteException { - - } - - @Override - public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) - throws RemoteException { - return null; - } - - @Override - public void setLastChosenActivity(Intent intent, String resolvedType, int flags, - IntentFilter filter, int match, ComponentName activity) throws RemoteException { - - } - - @Override - public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, - ComponentName activity, int userId) throws RemoteException { - - } - - @Override - public void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set, - ComponentName activity, int userId) throws RemoteException { - - } - - @Override - public void clearPackagePreferredActivities(String packageName) throws RemoteException { - - } - - @Override - public int getPreferredActivities(List<IntentFilter> outFilters, - List<ComponentName> outActivities, String packageName) throws RemoteException { - return 0; - } - - @Override - public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity, - int userId) throws RemoteException { - - } - - @Override - public void clearPackagePersistentPreferredActivities(String packageName, int userId) - throws RemoteException { - - } - - @Override - public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage, - int sourceUserId, int targetUserId, int flags) throws RemoteException { - - } - - @Override - public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage) - throws RemoteException { - - } - - @Override - public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames, - int restrictionFlags, int userId) throws RemoteException { - return new String[0]; - } - - @Override - public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended, - PersistableBundle appExtras, PersistableBundle launcherExtras, SuspendDialogInfo dialogInfo, - String callingPackage, int userId) throws RemoteException { - return new String[0]; - } - - @Override - public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) - throws RemoteException { - return new String[0]; - } - - @Override - public boolean isPackageSuspendedForUser(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId) - throws RemoteException { - return null; - } - - @Override - public byte[] getPreferredActivityBackup(int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public void restorePreferredActivities(byte[] backup, int userId) throws RemoteException { - - } - - @Override - public byte[] getDefaultAppsBackup(int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public void restoreDefaultApps(byte[] backup, int userId) throws RemoteException { - - } - - @Override - public byte[] getIntentFilterVerificationBackup(int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public void restoreIntentFilterVerification(byte[] backup, int userId) throws RemoteException { - - } - - @Override - public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates) - throws RemoteException { - return null; - } - - @Override - public void setHomeActivity(ComponentName className, int userId) throws RemoteException { - - } - - @Override - public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, - int userId) throws RemoteException { - - } - - @Override - public int getComponentEnabledSetting(ComponentName componentName, int userId) - throws RemoteException { - return 0; - } - - @Override - public void setApplicationEnabledSetting(String packageName, int newState, int flags, - int userId, - String callingPackage) throws RemoteException { - - } - - @Override - public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, - String apkFile, - int pid) throws RemoteException { - - } - - @Override - public void flushPackageRestrictionsAsUser(int userId) throws RemoteException { - - } - - @Override - public void setPackageStoppedState(String packageName, boolean stopped, int userId) - throws RemoteException { - - } - - @Override - public void freeStorageAndNotify(String volumeUuid, long freeStorageSize, int storageFlags, - IPackageDataObserver observer) throws RemoteException { - - } - - @Override - public void freeStorage(String volumeUuid, long freeStorageSize, int storageFlags, - IntentSender pi) throws RemoteException { - - } - - @Override - public void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer) - throws RemoteException { - - } - - @Override - public void deleteApplicationCacheFilesAsUser(String packageName, int userId, - IPackageDataObserver observer) throws RemoteException { - - } - - @Override - public void clearApplicationUserData(String packageName, IPackageDataObserver observer, - int userId) throws RemoteException { - - } - - @Override - public void clearApplicationProfileData(String packageName) throws RemoteException { - - } - - @Override - public void getPackageSizeInfo(String packageName, int userHandle, - IPackageStatsObserver observer) - throws RemoteException { - - } - - @Override - public String[] getSystemSharedLibraryNames() throws RemoteException { - return new String[0]; - } - - @Override - public ParceledListSlice getSystemAvailableFeatures() throws RemoteException { - return null; - } - - @Override - public boolean hasSystemFeature(String name, int version) throws RemoteException { - return false; - } - - @Override - public void enterSafeMode() throws RemoteException { - - } - - @Override - public boolean isSafeMode() throws RemoteException { - return false; - } - - @Override - public void systemReady() throws RemoteException { - - } - - @Override - public boolean hasSystemUidErrors() throws RemoteException { - return false; - } - - @Override - public void performFstrimIfNeeded() throws RemoteException { - - } - - @Override - public void updatePackagesIfNeeded() throws RemoteException { - - } - - @Override - public void notifyPackageUse(String packageName, int reason) throws RemoteException { - - } - - @Override - public void notifyDexLoad(String loadingPackageName, List<String> classLoadersNames, - List<String> classPaths, String loaderIsa) throws RemoteException { - - } - - @Override - public void registerDexModule(String packageName, String dexModulePath, boolean isSharedModule, - IDexModuleRegisterCallback callback) throws RemoteException { - - } - - @Override - public boolean performDexOptMode(String packageName, boolean checkProfiles, - String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) - throws RemoteException { - return false; - } - - @Override - public boolean performDexOptSecondary(String packageName, String targetCompilerFilter, - boolean force) throws RemoteException { - return false; - } - - @Override - public boolean compileLayouts(String packageName) throws RemoteException { - return false; - } - - @Override - public void dumpProfiles(String packageName) throws RemoteException { - - } - - @Override - public void forceDexOpt(String packageName) throws RemoteException { - - } - - @Override - public boolean runBackgroundDexoptJob(List<String> packageNames) throws RemoteException { - return false; - } - - @Override - public void reconcileSecondaryDexFiles(String packageName) throws RemoteException { - - } - - @Override - public int getMoveStatus(int moveId) throws RemoteException { - return 0; - } - - @Override - public void registerMoveCallback(IPackageMoveObserver callback) throws RemoteException { - - } - - @Override - public void unregisterMoveCallback(IPackageMoveObserver callback) throws RemoteException { - - } - - @Override - public int movePackage(String packageName, String volumeUuid) throws RemoteException { - return 0; - } - - @Override - public int movePrimaryStorage(String volumeUuid) throws RemoteException { - return 0; - } - - @Override - public boolean addPermissionAsync(PermissionInfo info) throws RemoteException { - return false; - } - - @Override - public boolean setInstallLocation(int loc) throws RemoteException { - return false; - } - - @Override - public int getInstallLocation() throws RemoteException { - return 0; - } - - @Override - public int installExistingPackageAsUser(String packageName, int userId, int installFlags, - int installReason) throws RemoteException { - return 0; - } - - @Override - public void verifyPendingInstall(int id, int verificationCode) throws RemoteException { - - } - - @Override - public void extendVerificationTimeout(int id, int verificationCodeAtTimeout, - long millisecondsToDelay) throws RemoteException { - - } - - @Override - public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) - throws RemoteException { - - } - - @Override - public int getIntentVerificationStatus(String packageName, int userId) throws RemoteException { - return 0; - } - - @Override - public boolean updateIntentVerificationStatus(String packageName, int status, int userId) - throws RemoteException { - return false; - } - - @Override - public ParceledListSlice getIntentFilterVerifications(String packageName) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getAllIntentFilters(String packageName) throws RemoteException { - return null; - } - - @Override - public boolean setDefaultBrowserPackageName(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public String getDefaultBrowserPackageName(int userId) throws RemoteException { - return null; - } - - @Override - public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException { - return null; - } - - @Override - public boolean isFirstBoot() throws RemoteException { - return false; - } - - @Override - public boolean isOnlyCoreApps() throws RemoteException { - return false; - } - - @Override - public boolean isDeviceUpgrading() throws RemoteException { - return false; - } - - @Override - public void setPermissionEnforced(String permission, boolean enforced) throws RemoteException { - - } - - @Override - public boolean isPermissionEnforced(String permission) throws RemoteException { - return false; - } - - @Override - public boolean isStorageLow() throws RemoteException { - return false; - } - - @Override - public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId) - throws RemoteException { - return false; - } - - @Override - public boolean getApplicationHiddenSettingAsUser(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) - throws RemoteException { - - } - - @Override - public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) - throws RemoteException { - return false; - } - - @Override - public IPackageInstaller getPackageInstaller() throws RemoteException { - return null; - } - - @Override - public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId) - throws RemoteException { - return false; - } - - @Override - public boolean getBlockUninstallForUser(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public KeySet getKeySetByAlias(String packageName, String alias) throws RemoteException { - return null; - } - - @Override - public KeySet getSigningKeySet(String packageName) throws RemoteException { - return null; - } - - @Override - public boolean isPackageSignedByKeySet(String packageName, KeySet ks) throws RemoteException { - return false; - } - - @Override - public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks) - throws RemoteException { - return false; - } - - @Override - public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) - throws RemoteException { - - } - - @Override - public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) - throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) - throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) - throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToEnabledTelephonyDataServices(String[] packageNames, - int userId) throws RemoteException { - - } - - @Override - public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(String[] packageNames, - int userId) throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) - throws RemoteException { - - } - - @Override - public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) - throws RemoteException { - - } - - @Override - public boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public String getPermissionControllerPackageName() throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getInstantApps(int userId) throws RemoteException { - return null; - } - - @Override - public byte[] getInstantAppCookie(String packageName, int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) - throws RemoteException { - return false; - } - - @Override - public Bitmap getInstantAppIcon(String packageName, int userId) throws RemoteException { - return null; - } - - @Override - public boolean isInstantApp(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) - throws RemoteException { - return false; - } - - @Override - public void setUpdateAvailable(String packageName, boolean updateAvaialble) - throws RemoteException { - - } - - @Override - public String getServicesSystemSharedLibraryPackageName() throws RemoteException { - return null; - } - - @Override - public String getSharedSystemSharedLibraryPackageName() throws RemoteException { - return null; - } - - @Override - public ChangedPackages getChangedPackages(int sequenceNumber, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean isPackageDeviceAdminOnAnyUser(String packageName) throws RemoteException { - return false; - } - - @Override - public int getInstallReason(String packageName, int userId) throws RemoteException { - return 0; - } - - @Override - public ParceledListSlice getSharedLibraries(String packageName, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getDeclaredSharedLibraries(String packageName, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean canRequestPackageInstalls(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public void deletePreloadsFileCache() throws RemoteException { - - } - - @Override - public ComponentName getInstantAppResolverComponent() throws RemoteException { - return null; - } - - @Override - public ComponentName getInstantAppResolverSettingsComponent() throws RemoteException { - return null; - } - - @Override - public ComponentName getInstantAppInstallerComponent() throws RemoteException { - return null; - } - - @Override - public String getInstantAppAndroidId(String packageName, int userId) throws RemoteException { - return null; - } - - @Override - public IArtManager getArtManager() throws RemoteException { - return null; - } - - @Override - public void setHarmfulAppWarning(String packageName, CharSequence warning, int userId) - throws RemoteException { - - } - - @Override - public CharSequence getHarmfulAppWarning(String packageName, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean hasSigningCertificate(String packageName, byte[] signingCertificate, int flags) - throws RemoteException { - return false; - } - - @Override - public boolean hasUidSigningCertificate(int uid, byte[] signingCertificate, int flags) - throws RemoteException { - return false; - } - - @Override - public String getSystemTextClassifierPackageName() throws RemoteException { - return null; - } - - @Override - public String getWellbeingPackageName() throws RemoteException { - return null; - } - - @Override - public String getSystemCaptionsServicePackageName() throws RemoteException { - return null; - } - - @Override - public String getAttentionServicePackageName() throws RemoteException { - return null; - } - - public String getIncidentReportApproverPackageName() throws RemoteException { - return null; - } - - @Override - public String getAppPredictionServicePackageName() { - return null; - } - - @Override - public boolean isPackageStateProtected(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public void sendDeviceCustomizationReadyBroadcast() throws RemoteException { - - } - - @Override - public List<ModuleInfo> getInstalledModules(int flags) throws RemoteException { - return null; - } - - @Override - public ModuleInfo getModuleInfo(String packageName, int flags) throws RemoteException { - return null; - } - - @Override - public int getRuntimePermissionsVersion(int userId) throws RemoteException { - return 0; - } - - @Override - public void setRuntimePermissionsVersion(int version, int userId) throws RemoteException { - - } - - @Override - public IBinder asBinder() { - return null; - } -} diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java index a92b576e5d0f..a9011756240d 100644 --- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -36,7 +37,6 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.backup.UserBackupManagerService; -import com.android.server.backup.testutils.IPackageManagerStub; import org.junit.Before; import org.junit.Test; @@ -54,14 +54,12 @@ public class AppBackupUtilsTest { private static final Signature SIGNATURE_3 = generateSignature((byte) 3); private static final Signature SIGNATURE_4 = generateSignature((byte) 4); - private IPackageManagerStub mPackageManagerStub; private PackageManagerInternal mMockPackageManagerInternal; private int mUserId; @Before public void setUp() throws Exception { - mPackageManagerStub = new IPackageManagerStub(); mMockPackageManagerInternal = mock(PackageManagerInternal.class); mUserId = UserHandle.USER_SYSTEM; @@ -76,7 +74,7 @@ public class AppBackupUtilsTest { applicationInfo.packageName = TEST_PACKAGE_NAME; boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -91,7 +89,7 @@ public class AppBackupUtilsTest { applicationInfo.packageName = TEST_PACKAGE_NAME; boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -105,7 +103,7 @@ public class AppBackupUtilsTest { applicationInfo.packageName = UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -118,12 +116,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.SYSTEM_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isTrue(); } @@ -136,12 +133,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = null; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isTrue(); } @@ -154,12 +150,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isTrue(); } @@ -172,12 +167,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.SYSTEM_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -190,12 +184,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = null; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -208,12 +201,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -226,12 +218,11 @@ public class AppBackupUtilsTest { applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; applicationInfo.enabled = true; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isFalse(); } @@ -244,12 +235,12 @@ public class AppBackupUtilsTest { applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; applicationInfo.enabled = false; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } @@ -261,12 +252,12 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isFalse(); } @@ -278,12 +269,12 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } @@ -295,12 +286,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; - - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } @@ -312,12 +302,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; - - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 355ff63d18f7..2d101dd87a0f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -349,6 +349,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner); when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG}); when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG}); + mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); // write to a test file; the system file isn't readable from tests mFile = new File(mContext.getCacheDir(), "test.xml"); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index 91d3e5e4d7f6..7e3d4b47bbdf 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -206,6 +206,7 @@ public class RoleObserverTest extends UiServiceTestCase { LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class)); + mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); mUsers = new ArrayList<>(); mUsers.add(new UserInfo(0, "system", 0)); 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 08d83333e91b..89364500fd80 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -110,6 +110,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { private ZenModeHelper mZenModeHelperSpy; private Context mContext; private ContentResolver mContentResolver; + @Mock AppOpsManager mAppOps; @Before public void setUp() { @@ -127,6 +128,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { e.toString()); } + when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps); when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager); mConditionProviders = new ConditionProviders(mContext, new UserProfiles(), AppGlobals.getPackageManager()); @@ -219,10 +221,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyInt()); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + doNothing().when(mZenModeHelperSpy).applyRestrictions(eq(false), anyBoolean(), anyInt()); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_MEDIA); } @@ -233,9 +235,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, AudioAttributes.USAGE_MEDIA); } @@ -244,13 +246,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, AudioAttributes.USAGE_ALARM); // Media is a catch-all that includes games - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, AudioAttributes.USAGE_GAME); } @@ -262,17 +264,17 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.applyRestrictions(); // Total silence will silence alarms, media and system noises (but not vibrations) - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_GAME); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_VIBRATE); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_UNKNOWN); } @@ -283,19 +285,19 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.applyRestrictions(); // Alarms only mode will not silence alarms - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ALARM); // Alarms only mode will not silence media - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_GAME); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_UNKNOWN); // Alarms only will silence system noises (but not vibrations) - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); } @@ -306,9 +308,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.applyRestrictions(); // Alarms only mode will silence calls despite priority-mode config - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_NOTIFICATION_RINGTONE); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); } @@ -319,7 +321,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ALARM); } @@ -334,19 +336,64 @@ public class ZenModeHelperTest extends UiServiceTestCase { for (int usage : AudioAttributes.SDK_USAGES) { if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { // only mute audio, not vibrations - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, usage, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, usage, AppOpsManager.OP_PLAY_AUDIO); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, usage, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, usage, AppOpsManager.OP_VIBRATE); } else { boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage) != AudioAttributes.SUPPRESSIBLE_NEVER; - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, shouldMute, usage); } } } @Test + public void testApplyRestrictions_whitelist_priorityOnlyMode() { + mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); + mZenModeHelperSpy.applyRestrictions(); + + for (int usage : AudioAttributes.SDK_USAGES) { + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(new String[]{PKG_O})); + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(new String[]{PKG_O})); + } + } + + @Test + public void testApplyRestrictions_whitelist_alarmsOnlyMode() { + mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_ALARMS; + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); + mZenModeHelperSpy.applyRestrictions(); + + for (int usage : AudioAttributes.SDK_USAGES) { + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null)); + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null)); + } + } + + @Test + public void testApplyRestrictions_whitelist_totalSilenceMode() { + mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_NO_INTERRUPTIONS; + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); + mZenModeHelperSpy.applyRestrictions(); + + for (int usage : AudioAttributes.SDK_USAGES) { + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null)); + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null)); + } + } + + @Test public void testZenUpgradeNotification() { // shows zen upgrade notification if stored settings says to shows, // zen has not been updated, boot is completed diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index 6382acf0511d..6000b56d191e 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -68,6 +68,7 @@ public abstract class Conference extends Conferenceable { public void onExtrasRemoved(Conference c, List<String> keys) {} public void onConferenceStateChanged(Conference c, boolean isConference) {} public void onAddressChanged(Conference c, Uri newAddress, int presentation) {} + public void onConnectionEvent(Conference c, String event, Bundle extras) {} public void onCallerDisplayNameChanged( Conference c, String callerDisplayName, int presentation) {} } @@ -1024,4 +1025,14 @@ public abstract class Conference extends Conferenceable { } onExtrasChanged(b); } + + /** + * See {@link Connection#sendConnectionEvent(String, Bundle)} + * @hide + */ + public void sendConnectionEvent(String event, Bundle extras) { + for (Listener l : mListeners) { + l.onConnectionEvent(this, event, extras); + } + } } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 9bafbe09998e..49b34b38c663 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -1279,6 +1279,14 @@ public abstract class ConnectionService extends Service { mAdapter.setCallerDisplayName(id, callerDisplayName, presentation); } } + + @Override + public void onConnectionEvent(Conference c, String event, Bundle extras) { + String id = mIdByConference.get(c); + if (id != null) { + mAdapter.onConnectionEvent(id, event, extras); + } + } }; private final Connection.Listener mConnectionListener = new Connection.Listener() { diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 037e47520c94..9bba2e8947ed 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -3039,6 +3039,7 @@ public final class Telephony { * The {@code content://} style URL for this table. Can be appended with a part ID to * address individual parts. */ + @NonNull public static final Uri CONTENT_URI = Uri.withAppendedPath(Mms.CONTENT_URI, "part"); /** diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 30875165867a..258a873c3ac5 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -243,4 +243,23 @@ public abstract class CellIdentity implements Parcelable { protected void log(String s) { Rlog.w(mTag, s); } + + /** @hide */ + protected static final int inRangeOrUnavailable(int value, int rangeMin, int rangeMax) { + if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE; + return value; + } + + /** @hide */ + protected static final long inRangeOrUnavailable(long value, long rangeMin, long rangeMax) { + if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE_LONG; + return value; + } + + /** @hide */ + protected static final int inRangeOrUnavailable( + int value, int rangeMin, int rangeMax, int special) { + if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE; + return value; + } } diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 4c00611b2355..880d3db681b5 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -28,12 +28,25 @@ public final class CellIdentityCdma extends CellIdentity { private static final String TAG = CellIdentityCdma.class.getSimpleName(); private static final boolean DBG = false; + private static final int NETWORK_ID_MAX = 65535; + private static final int SYSTEM_ID_MAX = 32767; + private static final int BASESTATION_ID_MAX = 65535; + + private static final int LONGITUDE_MIN = -2592000; + private static final int LONGITUDE_MAX = 2592000; + + private static final int LATITUDE_MIN = -1296000; + private static final int LATITUDE_MAX = 1296000; + // Network Id 0..65535 private final int mNetworkId; + // CDMA System Id 0..32767 private final int mSystemId; + // Base Station Id 0..65535 private final int mBasestationId; + /** * Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0. * It is represented in units of 0.25 seconds and ranges from -2592000 @@ -41,6 +54,7 @@ public final class CellIdentityCdma extends CellIdentity { * to +180 degrees). */ private final int mLongitude; + /** * Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0. * It is represented in units of 0.25 seconds and ranges from -1296000 @@ -78,9 +92,12 @@ public final class CellIdentityCdma extends CellIdentity { public CellIdentityCdma( int nid, int sid, int bid, int lon, int lat, String alphal, String alphas) { super(TAG, CellInfo.TYPE_CDMA, null, null, alphal, alphas); - mNetworkId = nid; - mSystemId = sid; - mBasestationId = bid; + mNetworkId = inRangeOrUnavailable(nid, 0, NETWORK_ID_MAX); + mSystemId = inRangeOrUnavailable(sid, 0, SYSTEM_ID_MAX); + mBasestationId = inRangeOrUnavailable(bid, 0, BASESTATION_ID_MAX); + lat = inRangeOrUnavailable(lat, LATITUDE_MIN, LATITUDE_MAX); + lon = inRangeOrUnavailable(lon, LONGITUDE_MIN, LONGITUDE_MAX); + if (!isNullIsland(lat, lon)) { mLongitude = lon; mLatitude = lat; diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index 864540d91be3..25c6577bdcf5 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -31,6 +31,11 @@ public final class CellIdentityGsm extends CellIdentity { private static final String TAG = CellIdentityGsm.class.getSimpleName(); private static final boolean DBG = false; + private static final int MAX_LAC = 65535; + private static final int MAX_CID = 65535; + private static final int MAX_ARFCN = 65535; + private static final int MAX_BSIC = 63; + // 16-bit Location Area Code, 0..65535 private final int mLac; // 16-bit GSM Cell Identity described in TS 27.007, 0..65535 @@ -68,10 +73,10 @@ public final class CellIdentityGsm extends CellIdentity { public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr, String mncStr, String alphal, String alphas) { super(TAG, CellInfo.TYPE_GSM, mccStr, mncStr, alphal, alphas); - mLac = lac; - mCid = cid; - mArfcn = arfcn; - mBsic = bsic; + mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); + mCid = inRangeOrUnavailable(cid, 0, MAX_CID); + mArfcn = inRangeOrUnavailable(arfcn, 0, MAX_ARFCN); + mBsic = inRangeOrUnavailable(bsic, 0, MAX_BSIC); } /** @hide */ diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 14503c7cdd4d..997b19f3d4eb 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -32,6 +32,12 @@ public final class CellIdentityLte extends CellIdentity { private static final String TAG = CellIdentityLte.class.getSimpleName(); private static final boolean DBG = false; + private static final int MAX_CI = 268435455; + private static final int MAX_PCI = 503; + private static final int MAX_TAC = 65535; + private static final int MAX_EARFCN = 262143; + private static final int MAX_BANDWIDTH = 20000; + // 28-bit cell identity private final int mCi; // physical cell id 0..503 @@ -89,11 +95,11 @@ public final class CellIdentityLte extends CellIdentity { public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, String mccStr, String mncStr, String alphal, String alphas) { super(TAG, CellInfo.TYPE_LTE, mccStr, mncStr, alphal, alphas); - mCi = ci; - mPci = pci; - mTac = tac; - mEarfcn = earfcn; - mBandwidth = bandwidth; + mCi = inRangeOrUnavailable(ci, 0, MAX_CI); + mPci = inRangeOrUnavailable(pci, 0, MAX_PCI); + mTac = inRangeOrUnavailable(tac, 0, MAX_TAC); + mEarfcn = inRangeOrUnavailable(earfcn, 0, MAX_EARFCN); + mBandwidth = inRangeOrUnavailable(bandwidth, 0, MAX_BANDWIDTH); } /** @hide */ diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java index 62d23cee3bf5..6df60ba0ca32 100644 --- a/telephony/java/android/telephony/CellIdentityNr.java +++ b/telephony/java/android/telephony/CellIdentityNr.java @@ -29,6 +29,11 @@ import java.util.Objects; public final class CellIdentityNr extends CellIdentity { private static final String TAG = "CellIdentityNr"; + private static final int MAX_PCI = 1007; + private static final int MAX_TAC = 65535; + private static final int MAX_NRARFCN = 3279165; + private static final long MAX_NCI = 68719476735L; + private final int mNrArfcn; private final int mPci; private final int mTac; @@ -41,6 +46,7 @@ public final class CellIdentityNr extends CellIdentity { * @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165]. * @param mccStr 3-digit Mobile Country Code in string format. * @param mncStr 2 or 3-digit Mobile Network Code in string format. + * @param nci The 36-bit NR Cell Identity in range [0, 68719476735]. * @param alphal long alpha Operator Name String or Enhanced Operator Name String. * @param alphas short alpha Operator Name String or Enhanced Operator Name String. * @@ -49,10 +55,10 @@ public final class CellIdentityNr extends CellIdentity { public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr, long nci, String alphal, String alphas) { super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas); - mPci = pci; - mTac = tac; - mNrArfcn = nrArfcn; - mNci = nci; + mPci = inRangeOrUnavailable(pci, 0, MAX_PCI); + mTac = inRangeOrUnavailable(tac, 0, MAX_TAC); + mNrArfcn = inRangeOrUnavailable(nrArfcn, 0, MAX_NRARFCN); + mNci = inRangeOrUnavailable(nci, 0, MAX_NCI); } /** @hide */ diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index 937de706aec0..558e346284ea 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -30,12 +30,18 @@ public final class CellIdentityTdscdma extends CellIdentity { private static final String TAG = CellIdentityTdscdma.class.getSimpleName(); private static final boolean DBG = false; + private static final int MAX_LAC = 65535; + private static final int MAX_CID = 268435455; + private static final int MAX_CPID = 127; + private static final int MAX_UARFCN = 65535; + // 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown. private final int mLac; // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, CellInfo.UNAVAILABLE // if unknown. private final int mCid; - // 8-bit Cell Parameters ID described in TS 25.331, 0..127, CellInfo.UNAVAILABLE if unknown. + // 8-bit Cell Parameters ID described in TS 25.331 sec 10.3.6.9, + // 0..127, CellInfo.UNAVAILABLE if unknown. private final int mCpid; // 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3 private final int mUarfcn; @@ -68,10 +74,10 @@ public final class CellIdentityTdscdma extends CellIdentity { public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid, int uarfcn, String alphal, String alphas) { super(TAG, CellInfo.TYPE_TDSCDMA, mcc, mnc, alphal, alphas); - mLac = lac; - mCid = cid; - mCpid = cpid; - mUarfcn = uarfcn; + mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); + mCid = inRangeOrUnavailable(cid, 0, MAX_CID); + mCpid = inRangeOrUnavailable(cpid, 0, MAX_CPID); + mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN); } private CellIdentityTdscdma(CellIdentityTdscdma cid) { diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index b4a2ead7fc3d..031fed13d9f1 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -31,6 +31,11 @@ public final class CellIdentityWcdma extends CellIdentity { private static final String TAG = CellIdentityWcdma.class.getSimpleName(); private static final boolean DBG = false; + private static final int MAX_LAC = 65535; + private static final int MAX_CID = 268435455; + private static final int MAX_PSC = 511; + private static final int MAX_UARFCN = 16383; // a 14 bit number; TS 25.331 ex sec 10.3.8.15 + // 16-bit Location Area Code, 0..65535 private final int mLac; // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455 @@ -68,10 +73,10 @@ public final class CellIdentityWcdma extends CellIdentity { public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn, String mccStr, String mncStr, String alphal, String alphas) { super(TAG, CellInfo.TYPE_WCDMA, mccStr, mncStr, alphal, alphas); - mLac = lac; - mCid = cid; - mPsc = psc; - mUarfcn = uarfcn; + mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); + mCid = inRangeOrUnavailable(cid, 0, MAX_CID); + mPsc = inRangeOrUnavailable(psc, 0, MAX_PSC); + mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN); } /** @hide */ diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 0808adf26aef..d4f98743089e 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -294,6 +294,19 @@ public class SubscriptionManager { public static final String SUBSCRIPTION_TYPE = "subscription_type"; /** + * TelephonyProvider column name white_listed_apn_data. + * It's a bitmask of APN types that will be allowed on this subscription even if it's metered + * and mobile data is turned off by the user. + * <P>Type: INTEGER (int)</P> For example, if TYPE_MMS is is true, Telephony will allow MMS + * data connection to setup even if MMS is metered and mobile_data is turned off on that + * subscription. + * + * Default value is 0. + */ + /** @hide */ + public static final String WHITE_LISTED_APN_DATA = "white_listed_apn_data"; + + /** * This constant is to designate a subscription as a Local-SIM Subscription. * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on the * device. @@ -3086,6 +3099,31 @@ public class SubscriptionManager { return subId; } + /** + * Set whether a subscription always allows MMS connection. If true, MMS network + * request will be accepted by telephony even if user turns "mobile data" off + * on this subscription. + * + * @param subId which subscription it's setting to. + * @param alwaysAllow whether Mms data is always allowed. + * @return whether operation is successful. + * + * @hide + */ + public boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow) { + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + return iSub.setAlwaysAllowMmsData(subId, alwaysAllow); + } + } catch (RemoteException ex) { + if (!isSystemProcess()) { + ex.rethrowAsRuntimeException(); + } + } + return false; + } + private interface CallISubMethodHelper { int callMethod(ISub iSub) throws RemoteException; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 2bd4f8f336fd..18b9fbbf414e 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10948,4 +10948,33 @@ public class TelephonyManager { } return new Pair<Integer, Integer>(-1, -1); } + + + /** + * Return whether MMS data is enabled. This will tell if framework will accept a MMS network + * request on a subId. + * + * Mms is enabled if: + * 1) user data is turned on, or + * 2) MMS is un-metered for this subscription, or + * 3) alwaysAllowMms setting {@link SubscriptionManager#setAlwaysAllowMmsData} is turned on. + * + * @return whether MMS data is allowed. + * + * @hide + */ + public boolean isMmsDataEnabled() { + String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.isMmsDataEnabled(getSubId(), pkgForDebug); + } + } catch (RemoteException ex) { + if (!isSystemProcess()) { + ex.rethrowAsRuntimeException(); + } + } + return false; + } } diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index e9aede7336f0..be5872387d7b 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -781,8 +781,13 @@ public class ImsMmTelManager { } /** - * Change the user's setting for RTT capability of this device. - * @param isEnabled if true RTT will be enabled during calls. + * Sets the capability of RTT for IMS calls placed on this subscription. + * + * Note: This does not affect the value of + * {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting + * for RTT. That value is enabled/disabled separately by the user through the Accessibility + * settings. + * @param isEnabled if true RTT should be enabled during calls made on this subscription. */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean isEnabled) { diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index c008711ff236..e6777c17203a 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -40,8 +40,6 @@ import android.util.SparseArray; import com.android.ims.internal.IImsFeatureStatusCallback; import com.android.internal.annotations.VisibleForTesting; -import static android.Manifest.permission.MODIFY_PHONE_STATE; - /** * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend * ImsService must register the service in their AndroidManifest to be detected by the framework. @@ -229,8 +227,8 @@ public class ImsService extends Service { private void setupFeature(ImsFeature f, int slotId, int featureType, IImsFeatureStatusCallback c) { - f.addImsFeatureStatusCallback(c); f.initialize(this, slotId); + f.addImsFeatureStatusCallback(c); addImsFeature(slotId, featureType, f); } diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 6e8d038eda4f..bb5c251b69e1 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -94,6 +94,7 @@ public class DctConstants { public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48; public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49; public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50; + public static final int EVENT_APN_WHITE_LIST_CHANGE = BASE + 51; /***** Constants *****/ diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index cfba0529e664..b081228d9616 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -279,4 +279,6 @@ interface ISub { int getSimStateForSlotIndex(int slotIndex); boolean isActiveSubId(int subId, String callingPackage); + + boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index ecbbd6a6c786..536c514356cb 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1966,4 +1966,6 @@ interface ITelephony { int getRadioHalVersion(); boolean isModemEnabledForSlot(int slotIndex, String callingPackage); + + boolean isMmsDataEnabled(int subId, String callingPackage); } diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index 80fb58d45078..12b20efcb0b3 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -344,10 +344,22 @@ public final class TelephonyPermissions { return true; } // if the calling package is null then return now as there's no way to perform the - // DevicePolicyManager device / profile owner checks. + // DevicePolicyManager device / profile owner and AppOp checks if (callingPackage == null) { return false; } + // Allow access to an app that has been granted the READ_DEVICE_IDENTIFIERS app op. + long token = Binder.clearCallingIdentity(); + AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService( + Context.APP_OPS_SERVICE); + try { + if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid, + callingPackage) == AppOpsManager.MODE_ALLOWED) { + return true; + } + } finally { + Binder.restoreCallingIdentity(token); + } // Allow access to a device / profile owner app. DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService( Context.DEVICE_POLICY_SERVICE); diff --git a/tests/FlickerTests/lib/Android.bp b/tests/FlickerTests/lib/Android.bp index 982fcbadddf7..5d8ed2c205e9 100644 --- a/tests/FlickerTests/lib/Android.bp +++ b/tests/FlickerTests/lib/Android.bp @@ -20,7 +20,7 @@ java_test { srcs: ["src/**/*.java"], static_libs: [ "androidx.test.janktesthelper", - "cts-amwm-util", + "cts-wm-util", "platformprotosnano", "layersprotosnano", "truth-prebuilt", diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 98324850f3f5..3da22b4fb9fa 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -129,12 +129,20 @@ class ValueBodyPrinter : public ConstValueVisitor { constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS; if (attr->type_mask & kMask) { for (const auto& symbol : attr->symbols) { - printer_->Print(symbol.symbol.name.value().entry); - if (symbol.symbol.id) { - printer_->Print("("); + if (symbol.symbol.name) { + printer_->Print(symbol.symbol.name.value().entry); + + if (symbol.symbol.id) { + printer_->Print("("); + printer_->Print(symbol.symbol.id.value().to_string()); + printer_->Print(")"); + } + } else if (symbol.symbol.id) { printer_->Print(symbol.symbol.id.value().to_string()); - printer_->Print(")"); + } else { + printer_->Print("???"); } + printer_->Println(StringPrintf("=0x%08x", symbol.value)); } } diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 950c6f801461..9d4b837ce2d1 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -967,6 +967,10 @@ public class WifiEnterpriseConfig implements Parcelable { * from the top-level domain and all the labels in domain_suffix_match shall be included in the * certificate. The certificate may include additional sub-level labels in addition to the * required labels. + * <p>More than one match string can be provided by using semicolons to separate the strings + * (e.g., example.org;example.com). When multiple strings are specified, a match with any one of + * the values is considered a sufficient match for the certificate, i.e., the conditions are + * ORed ogether. * <p>For example, domain_suffix_match=example.com would match test.example.com but would not * match test-example.com. * @param domain The domain value |