diff options
567 files changed, 17612 insertions, 8520 deletions
diff --git a/Android.bp b/Android.bp index f40aab15e26e..88b2473169f5 100644 --- a/Android.bp +++ b/Android.bp @@ -296,6 +296,7 @@ java_defaults { "core/java/android/service/notification/IConditionListener.aidl", "core/java/android/service/notification/IConditionProvider.aidl", "core/java/android/service/settings/suggestions/ISuggestionService.aidl", + "core/java/android/service/sms/IFinancialSmsService.aidl", "core/java/android/service/vr/IPersistentVrStateCallbacks.aidl", "core/java/android/service/vr/IVrListener.aidl", "core/java/android/service/vr/IVrManager.aidl", @@ -348,6 +349,7 @@ java_defaults { "core/java/android/view/accessibility/IAccessibilityManagerClient.aidl", "core/java/android/view/autofill/IAutoFillManager.aidl", "core/java/android/view/autofill/IAutoFillManagerClient.aidl", + "core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl", "core/java/android/view/autofill/IAutofillWindowPresenter.aidl", "core/java/android/view/intelligence/IIntelligenceManager.aidl", "core/java/android/view/IApplicationToken.aidl", @@ -724,6 +726,7 @@ java_defaults { "android.hardware.wifi-V1.0-java-constants", "android.hardware.radio-V1.0-java", "android.hardware.radio-V1.3-java", + "android.hardware.radio-V1.4-java", "android.hardware.usb.gadget-V1.0-java", "netd_aidl_interface-java", ], @@ -859,7 +862,7 @@ gensrcs { java_library { name: "ext", installable: true, - sdk_version: "core_current", + no_framework_libs: true, static_libs: [ "libphonenumber-platform", "nist-sip", @@ -1717,7 +1720,9 @@ filegroup { "core/java/android/annotation/RequiresPermission.java", "core/java/android/annotation/SdkConstant.java", "core/java/android/annotation/StringDef.java", + "core/java/android/annotation/TestApi.java", "core/java/android/annotation/UnsupportedAppUsage.java", + "core/java/com/android/internal/annotations/GuardedBy.java", ], } diff --git a/api/current.txt b/api/current.txt index ac1ae34f4bdc..6f2568824da4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -159,9 +159,6 @@ package android { field public static final java.lang.String WRITE_CONTACTS = "android.permission.WRITE_CONTACTS"; field public static final deprecated java.lang.String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"; field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES"; - field public static final java.lang.String WRITE_MEDIA_AUDIO = "android.permission.WRITE_MEDIA_AUDIO"; - field public static final java.lang.String WRITE_MEDIA_IMAGES = "android.permission.WRITE_MEDIA_IMAGES"; - field public static final java.lang.String WRITE_MEDIA_VIDEO = "android.permission.WRITE_MEDIA_VIDEO"; field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS"; field public static final java.lang.String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS"; field public static final java.lang.String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS"; @@ -1319,6 +1316,7 @@ package android { field public static final int supportsAssist = 16844016; // 0x10104f0 field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1 field public static final int supportsLocalInteraction = 16844047; // 0x101050f + field public static final int supportsMultipleDisplays = 16844183; // 0x1010597 field public static final int supportsPictureInPicture = 16844023; // 0x10104f7 field public static final int supportsRtl = 16843695; // 0x10103af field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb @@ -1499,6 +1497,7 @@ package android { field public static final int unselectedAlpha = 16843278; // 0x101020e field public static final int updatePeriodMillis = 16843344; // 0x1010250 field public static final int use32bitAbi = 16844053; // 0x1010515 + field public static final int useAppZygote = 16844184; // 0x1010598 field public static final int useDefaultMargins = 16843641; // 0x1010379 field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310 field public static final int useLevel = 16843167; // 0x101019f @@ -6354,6 +6353,7 @@ package android.app { method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager); method public boolean supportsAmbientMode(); + method public boolean supportsMultipleDisplays(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR; } @@ -10041,6 +10041,7 @@ package android.content { field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT"; field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED"; field public static final java.lang.String ACTION_DEFAULT = "android.intent.action.VIEW"; + field public static final java.lang.String ACTION_DEFINE = "android.intent.action.DEFINE"; field public static final java.lang.String ACTION_DELETE = "android.intent.action.DELETE"; field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW"; field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK"; @@ -10131,6 +10132,7 @@ package android.content { field public static final java.lang.String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED"; field public static final java.lang.String ACTION_TIME_CHANGED = "android.intent.action.TIME_SET"; field public static final java.lang.String ACTION_TIME_TICK = "android.intent.action.TIME_TICK"; + field public static final java.lang.String ACTION_TRANSLATE = "android.intent.action.TRANSLATE"; field public static final java.lang.String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED"; field public static final deprecated java.lang.String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED"; field public static final deprecated java.lang.String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED"; @@ -11712,6 +11714,7 @@ package android.content.pm { field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2 field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 + field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8 field public int flags; field public java.lang.String permission; } @@ -14822,6 +14825,7 @@ package android.graphics { ctor public Typeface.CustomFallbackBuilder(android.graphics.fonts.FontFamily); method public android.graphics.Typeface.CustomFallbackBuilder addCustomFallback(android.graphics.fonts.FontFamily); method public android.graphics.Typeface build(); + method public static int getMaxCustomFallbackCount(); method public android.graphics.Typeface.CustomFallbackBuilder setStyle(android.graphics.fonts.FontStyle); method public android.graphics.Typeface.CustomFallbackBuilder setSystemFallback(java.lang.String); } @@ -22641,7 +22645,7 @@ package android.location { method public abstract void onLocationChanged(android.location.Location); method public abstract void onProviderDisabled(java.lang.String); method public abstract void onProviderEnabled(java.lang.String); - method public abstract void onStatusChanged(java.lang.String, int, android.os.Bundle); + method public abstract deprecated void onStatusChanged(java.lang.String, int, android.os.Bundle); } public class LocationManager { @@ -22653,7 +22657,7 @@ package android.location { method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int); method public void clearTestProviderEnabled(java.lang.String); method public void clearTestProviderLocation(java.lang.String); - method public void clearTestProviderStatus(java.lang.String); + method public deprecated void clearTestProviderStatus(java.lang.String); method public java.util.List<java.lang.String> getAllProviders(); method public java.lang.String getBestProvider(android.location.Criteria, boolean); method public java.lang.String getGnssHardwareModelName(); @@ -22690,7 +22694,7 @@ package android.location { method public boolean sendExtraCommand(java.lang.String, java.lang.String, android.os.Bundle); method public void setTestProviderEnabled(java.lang.String, boolean); method public void setTestProviderLocation(java.lang.String, android.location.Location); - method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long); + method public deprecated void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long); method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback); method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback); method public void unregisterGnssStatusCallback(android.location.GnssStatus.Callback); @@ -22698,7 +22702,7 @@ package android.location { field public static final java.lang.String KEY_LOCATION_CHANGED = "location"; field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled"; field public static final java.lang.String KEY_PROXIMITY_ENTERING = "entering"; - field public static final java.lang.String KEY_STATUS_CHANGED = "status"; + field public static final deprecated java.lang.String KEY_STATUS_CHANGED = "status"; field public static final java.lang.String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"; field public static final java.lang.String NETWORK_PROVIDER = "network"; field public static final java.lang.String PASSIVE_PROVIDER = "passive"; @@ -22717,9 +22721,9 @@ package android.location { method public boolean supportsAltitude(); method public boolean supportsBearing(); method public boolean supportsSpeed(); - field public static final int AVAILABLE = 2; // 0x2 - field public static final int OUT_OF_SERVICE = 0; // 0x0 - field public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1 + field public static final deprecated int AVAILABLE = 2; // 0x2 + field public static final deprecated int OUT_OF_SERVICE = 0; // 0x0 + field public static final deprecated int TEMPORARILY_UNAVAILABLE = 1; // 0x1 } public abstract interface OnNmeaMessageListener { @@ -22948,7 +22952,7 @@ package android.media { method public void adjustSuggestedStreamVolume(int, int, int); method public void adjustVolume(int, int); method public void dispatchMediaKeyEvent(android.view.KeyEvent); - method public static int generateAudioSessionId(); + method public int generateAudioSessionId(); method public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations(); method public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations(); method public android.media.AudioDeviceInfo[] getDevices(int); @@ -23457,6 +23461,7 @@ package android.media { } public class ExifInterface { + ctor public ExifInterface(java.io.File) throws java.io.IOException; ctor public ExifInterface(java.lang.String) throws java.io.IOException; ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException; ctor public ExifInterface(java.io.InputStream) throws java.io.IOException; @@ -23464,11 +23469,13 @@ package android.media { method public java.lang.String getAttribute(java.lang.String); method public double getAttributeDouble(java.lang.String, double); method public int getAttributeInt(java.lang.String, int); + method public long[] getAttributeRange(java.lang.String); method public boolean getLatLong(float[]); method public byte[] getThumbnail(); method public android.graphics.Bitmap getThumbnailBitmap(); method public byte[] getThumbnailBytes(); method public long[] getThumbnailRange(); + method public boolean hasAttribute(java.lang.String); method public boolean hasThumbnail(); method public boolean isThumbnailCompressed(); method public void saveAttributes() throws java.io.IOException; @@ -29131,15 +29138,18 @@ package android.net.wifi { method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion(); method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress); method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress); - method public android.net.wifi.WifiNetworkConfigBuilder setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig); method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired(); + method public android.net.wifi.WifiNetworkConfigBuilder setIsEnhancedOpen(); method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid(); method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered(); method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired(); method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int); - method public android.net.wifi.WifiNetworkConfigBuilder setPskPassphrase(java.lang.String); method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String); method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher); + method public android.net.wifi.WifiNetworkConfigBuilder setWpa2EnterpriseConfig(android.net.wifi.WifiEnterpriseConfig); + method public android.net.wifi.WifiNetworkConfigBuilder setWpa2Passphrase(java.lang.String); + method public android.net.wifi.WifiNetworkConfigBuilder setWpa3EnterpriseConfig(android.net.wifi.WifiEnterpriseConfig); + method public android.net.wifi.WifiNetworkConfigBuilder setWpa3Passphrase(java.lang.String); } public final class WifiNetworkSuggestion implements android.os.Parcelable { @@ -43233,9 +43243,9 @@ package android.telephony { public class MbmsGroupCallSession implements java.lang.AutoCloseable { method public void close(); - method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsGroupCallSessionCallback); + method public static android.telephony.MbmsGroupCallSession create(android.content.Context, int, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback); method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback); - method public android.telephony.mbms.GroupCall startGroupCall(java.util.concurrent.Executor, long, int[], int[], android.telephony.mbms.GroupCallCallback); + method public android.telephony.mbms.GroupCall startGroupCall(long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, java.util.concurrent.Executor, android.telephony.mbms.GroupCallCallback); } public class MbmsStreamingSession implements java.lang.AutoCloseable { @@ -43620,7 +43630,7 @@ package android.telephony { method public static int getDefaultVoiceSubscriptionId(); method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(); method public static int getSlotIndex(int); - method public static int[] getSubscriptionIds(int); + method public int[] getSubscriptionIds(int); method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); method public boolean isActiveSubscriptionId(int); method public boolean isNetworkRoaming(int); @@ -44240,7 +44250,7 @@ package android.telephony.mbms { public class GroupCall implements java.lang.AutoCloseable { method public void close(); method public long getTmgi(); - method public void updateGroupCall(int[], int[]); + method public void updateGroupCall(java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>); field public static final int REASON_BY_USER_REQUEST = 1; // 0x1 field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3 field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6 @@ -44252,11 +44262,10 @@ package android.telephony.mbms { field public static final int STATE_STOPPED = 1; // 0x1 } - public class GroupCallCallback { - ctor public GroupCallCallback(); - method public void onBroadcastSignalStrengthUpdated(int); - method public void onError(int, java.lang.String); - method public void onGroupCallStateChanged(int, int); + public abstract interface GroupCallCallback { + method public abstract void onBroadcastSignalStrengthUpdated(int); + method public abstract void onError(int, java.lang.String); + method public abstract void onGroupCallStateChanged(int, int); field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff } @@ -44296,6 +44305,11 @@ package android.telephony.mbms { field public static final int ERROR_UNABLE_TO_READ_SIM = 206; // 0xce } + public static class MbmsErrors.GroupCallErrors { + field public static final int ERROR_DUPLICATE_START_GROUP_CALL = 502; // 0x1f6 + field public static final int ERROR_UNABLE_TO_START_SERVICE = 501; // 0x1f5 + } + public static class MbmsErrors.InitializationErrors { field public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 102; // 0x66 field public static final int ERROR_DUPLICATE_INITIALIZE = 101; // 0x65 @@ -44308,12 +44322,11 @@ package android.telephony.mbms { field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e } - public class MbmsGroupCallSessionCallback { - ctor public MbmsGroupCallSessionCallback(); - method public void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>); - method public void onError(int, java.lang.String); - method public void onMiddlewareReady(); - method public void onServiceInterfaceAvailable(java.lang.String, int); + public abstract interface MbmsGroupCallSessionCallback { + method public abstract void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>); + method public abstract void onError(int, java.lang.String); + method public abstract void onMiddlewareReady(); + method public abstract void onServiceInterfaceAvailable(java.lang.String, int); } public class MbmsStreamingSessionCallback { @@ -45614,9 +45627,14 @@ package android.text.style { method public abstract void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt); } - public static class LineHeightSpan.Standard implements android.text.style.LineHeightSpan { + public static class LineHeightSpan.Standard implements android.text.style.LineHeightSpan android.text.ParcelableSpan { ctor public LineHeightSpan.Standard(int); + ctor public LineHeightSpan.Standard(android.os.Parcel); method public void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt); + method public int describeContents(); + method public int getHeight(); + method public int getSpanTypeId(); + method public void writeToParcel(android.os.Parcel, int); } public static abstract interface LineHeightSpan.WithDensity implements android.text.style.LineHeightSpan { @@ -49319,6 +49337,8 @@ package android.view { method public final boolean startDragAndDrop(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int); method public boolean startNestedScroll(int); method public void stopNestedScroll(); + method public void transformMatrixToGlobal(android.graphics.Matrix); + method public void transformMatrixToLocal(android.graphics.Matrix); method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); method public void unscheduleDrawable(android.graphics.drawable.Drawable); method public final void updateDragShadow(android.view.View.DragShadowBuilder); @@ -51911,6 +51931,7 @@ package android.view.textclassifier { method public java.time.ZonedDateTime getTime(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.Message> CREATOR; + field public static final android.app.Person PERSON_USER_LOCAL; } public static final class ConversationActions.Message.Builder { @@ -52179,6 +52200,7 @@ package android.view.textclassifier { field public static final int STATUS_LINKS_APPLIED = 0; // 0x0 field public static final int STATUS_NO_LINKS_APPLIED = 2; // 0x2 field public static final int STATUS_NO_LINKS_FOUND = 1; // 0x1 + field public static final int STATUS_UNSUPPORTED_CHARACTER = 4; // 0x4 } public static final class TextLinks.Builder { @@ -54172,6 +54194,7 @@ package android.widget { ctor public ImageView(android.content.Context, android.util.AttributeSet); ctor public ImageView(android.content.Context, android.util.AttributeSet, int); ctor public ImageView(android.content.Context, android.util.AttributeSet, int, int); + method public void animateTransform(android.graphics.Matrix); method public final void clearColorFilter(); method public boolean getAdjustViewBounds(); method public boolean getBaselineAlignBottom(); @@ -55469,6 +55492,7 @@ package android.widget { method public java.lang.CharSequence getText(); method public android.view.textclassifier.TextClassifier getTextClassifier(); method public final android.content.res.ColorStateList getTextColors(); + method public android.text.TextDirectionHeuristic getTextDirectionHeuristic(); method public java.util.Locale getTextLocale(); method public android.os.LocaleList getTextLocales(); method public android.text.PrecomputedText.Params getTextMetricsParams(); diff --git a/api/system-current.txt b/api/system-current.txt index 5f0d20b5caec..53e819dfa289 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1225,7 +1225,6 @@ package android.content.pm { method public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps(); method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String); method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int); - method public android.content.pm.PackageInfo getPackageInfoAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle); method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -1821,9 +1820,19 @@ package android.hardware.location { field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR; } + public class ContextHubIntentEvent { + method public static android.hardware.location.ContextHubIntentEvent fromIntent(android.content.Intent); + method public android.hardware.location.ContextHubInfo getContextHubInfo(); + method public int getEventType(); + method public int getNanoAppAbortCode(); + method public long getNanoAppId(); + method public android.hardware.location.NanoAppMessage getNanoAppMessage(); + } + public final class ContextHubManager { method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.hardware.location.ContextHubClientCallback, java.util.concurrent.Executor); method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.hardware.location.ContextHubClientCallback); + method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.app.PendingIntent, long); method public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(android.hardware.location.ContextHubInfo, long); method public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(android.hardware.location.ContextHubInfo, long); method public deprecated int[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter); @@ -1840,6 +1849,18 @@ package android.hardware.location { method public deprecated int unloadNanoApp(int); method public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(android.hardware.location.ContextHubInfo, long); method public deprecated int unregisterCallback(android.hardware.location.ContextHubManager.Callback); + field public static final int EVENT_HUB_RESET = 6; // 0x6 + field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4 + field public static final int EVENT_NANOAPP_DISABLED = 3; // 0x3 + field public static final int EVENT_NANOAPP_ENABLED = 2; // 0x2 + field public static final int EVENT_NANOAPP_LOADED = 0; // 0x0 + field public static final int EVENT_NANOAPP_MESSAGE = 5; // 0x5 + field public static final int EVENT_NANOAPP_UNLOADED = 1; // 0x1 + field public static final java.lang.String EXTRA_CONTEXT_HUB_INFO = "android.hardware.location.extra.CONTEXT_HUB_INFO"; + field public static final java.lang.String EXTRA_EVENT_TYPE = "android.hardware.location.extra.EVENT_TYPE"; + field public static final java.lang.String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE"; + field public static final java.lang.String EXTRA_NANOAPP_ABORT_CODE = "android.hardware.location.extra.NANOAPP_ABORT_CODE"; + field public static final java.lang.String EXTRA_NANOAPP_ID = "android.hardware.location.extra.NANOAPP_ID"; } public static abstract deprecated class ContextHubManager.Callback { @@ -4938,12 +4959,47 @@ package android.service.euicc { package android.service.intelligence { + public final class FillCallback { + method public void onSuccess(android.service.intelligence.FillResponse); + } + + public final class FillController { + method public void autofill(java.util.List<android.util.Pair<android.view.autofill.AutofillId, android.view.autofill.AutofillValue>>); + } + + public final class FillRequest { + method public android.view.autofill.AutofillId getFocusedId(); + method public android.service.intelligence.PresentationParams getPresentationParams(); + method public android.service.intelligence.InteractionSessionId getSessionId(); + } + + public final class FillResponse implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.intelligence.FillResponse> CREATOR; + } + + public static class FillResponse.Builder { + ctor public FillResponse.Builder(); + method public android.service.intelligence.FillResponse build(); + method public android.service.intelligence.FillResponse.Builder setFillWindow(android.service.intelligence.FillWindow); + method public android.service.intelligence.FillResponse.Builder setIgnoredIds(java.util.List<android.view.autofill.AutofillId>); + } + + public final class FillWindow { + ctor public FillWindow(); + method public void destroy(); + method public boolean update(android.service.intelligence.PresentationParams.Area, android.view.View, long); + field public static final long FLAG_METADATA_ADDRESS = 1L; // 0x1L + } + public abstract class IntelligenceService extends android.app.Service { ctor public IntelligenceService(); method public void onActivitySnapshot(android.service.intelligence.InteractionSessionId, android.service.intelligence.SnapshotData); method public abstract void onContentCaptureEvent(android.service.intelligence.InteractionSessionId, java.util.List<android.view.intelligence.ContentCaptureEvent>); method public void onCreateInteractionSession(android.service.intelligence.InteractionContext, android.service.intelligence.InteractionSessionId); method public void onDestroyInteractionSession(android.service.intelligence.InteractionSessionId); + method public void onFillRequest(android.service.intelligence.InteractionSessionId, android.service.intelligence.FillRequest, android.os.CancellationSignal, android.service.intelligence.FillController, android.service.intelligence.FillCallback); field public static final java.lang.String SERVICE_INTERFACE = "android.service.intelligence.IntelligenceService"; } @@ -4965,6 +5021,23 @@ package android.service.intelligence { field public static final android.os.Parcelable.Creator<android.service.intelligence.InteractionSessionId> CREATOR; } + public abstract class PresentationParams { + method public int getFlags(); + method public android.service.intelligence.PresentationParams.Area getFullArea(); + method public android.service.intelligence.PresentationParams.Area getSuggestionArea(); + field public static final int FLAG_HINT_GRAVITY_BOTTOM = 2; // 0x2 + field public static final int FLAG_HINT_GRAVITY_LEFT = 4; // 0x4 + field public static final int FLAG_HINT_GRAVITY_RIGHT = 8; // 0x8 + field public static final int FLAG_HINT_GRAVITY_TOP = 1; // 0x1 + field public static final int FLAG_HOST_IME = 16; // 0x10 + field public static final int FLAG_HOST_SYSTEM = 32; // 0x20 + } + + public static abstract class PresentationParams.Area { + method public android.graphics.Rect getBounds(); + method public android.service.intelligence.PresentationParams.Area getSubArea(android.graphics.Rect); + } + public final class SnapshotData implements android.os.Parcelable { method public int describeContents(); method public android.app.assist.AssistContent getAssistContent(); @@ -5024,13 +5097,18 @@ package android.service.notification { method public final void adjustNotification(android.service.notification.Adjustment); method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); method public final android.os.IBinder onBind(android.content.Intent); + method public void onNotificationDirectReply(java.lang.String); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel); + method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean); method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int); method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String); method public void onNotificationsSeen(java.util.List<java.lang.String>); + method public void onSuggestedReplySent(java.lang.String, java.lang.CharSequence, int); method public final void unsnoozeNotification(java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; + field public static final int SOURCE_FROM_APP = 0; // 0x0 + field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1 } public final class NotificationStats implements android.os.Parcelable { @@ -5184,6 +5262,16 @@ package android.service.settings.suggestions { } +package android.service.sms { + + public abstract class FinancialSmsService extends android.app.Service { + method public android.os.IBinder onBind(android.content.Intent); + method public abstract android.database.CursorWindow onGetSmsMessages(android.os.Bundle); + field public static final java.lang.String ACTION_FINANCIAL_SERVICE_INTENT = "android.service.sms.action.FINANCIAL_SERVICE_INTENT"; + } + +} + package android.service.textclassifier { public abstract class TextClassifierService extends android.app.Service { @@ -7023,9 +7111,9 @@ package android.telephony.mbms.vendor { method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException; method public void onAppCallbackDied(int, int); method public android.os.IBinder onBind(android.content.Intent); - method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback); + method public int startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback); method public void stopGroupCall(int, long); - method public void updateGroupCall(int, long, int[], int[]); + method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>); } public class MbmsStreamingServiceBase extends android.os.Binder { diff --git a/api/test-current.txt b/api/test-current.txt index 1c01cf1daf18..738caeca1b64 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -985,6 +985,7 @@ package android.provider { public static final class Settings.Global extends android.provider.Settings.NameValueTable { field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages"; + field public static final java.lang.String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = "autofill_smart_suggestion_emulation_flags"; field public static final java.lang.String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode"; field public static final java.lang.String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold"; field public static final java.lang.String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; @@ -1155,12 +1156,17 @@ package android.service.notification { method public final void adjustNotification(android.service.notification.Adjustment); method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); method public final android.os.IBinder onBind(android.content.Intent); + method public void onNotificationDirectReply(java.lang.String); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel); + method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean); method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String); method public void onNotificationsSeen(java.util.List<java.lang.String>); + method public void onSuggestedReplySent(java.lang.String, java.lang.CharSequence, int); method public final void unsnoozeNotification(java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; + field public static final int SOURCE_FROM_APP = 0; // 0x0 + field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1 } public abstract class NotificationListenerService extends android.app.Service { @@ -1318,9 +1324,9 @@ package android.telephony.mbms.vendor { method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException; method public void onAppCallbackDied(int, int); method public android.os.IBinder onBind(android.content.Intent); - method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback); + method public int startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback); method public void stopGroupCall(int, long); - method public void updateGroupCall(int, long, int[], int[]); + method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>); } public class MbmsStreamingServiceBase extends android.os.Binder { diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 7d675cebfb33..d7922bc08cea 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -181,6 +181,7 @@ cc_binary { "libutils", "libziparchive", ], + init_rc: ["idmap2d/idmap2d.rc"], } filegroup { diff --git a/cmds/idmap2/idmap2d/idmap2d.rc b/cmds/idmap2/idmap2d/idmap2d.rc new file mode 100644 index 000000000000..203e7bee4af6 --- /dev/null +++ b/cmds/idmap2/idmap2d/idmap2d.rc @@ -0,0 +1,4 @@ +service idmap2d /system/bin/idmap2d + class main + user system + group system diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 3ee0a06e2cd8..2fc7e03ca91f 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -34,6 +34,8 @@ import "frameworks/base/core/proto/android/stats/launcher/launcher.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; import "frameworks/base/core/proto/android/telephony/enums.proto"; import "frameworks/base/core/proto/android/view/enums.proto"; +import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto"; +import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto"; /** * The master atom class. This message defines all of the available @@ -156,6 +158,7 @@ message Atom { ServiceLaunchReported service_launch_reported = 100; PhenotypeFlagStateChanged phenotype_flag_state_changed = 101; BinaryPushStateChanged binary_push_state_changed = 102; + DevicePolicyEvent device_policy_event = 103; } // Pulled events will start at field 10000. @@ -205,6 +208,7 @@ message Atom { DeviceCalculatedPowerBlameOther device_calculated_power_blame_other = 10041; ProcessMemoryHighWaterMark process_memory_high_water_mark = 10042; BatteryLevel battery_level = 10043; + BuildInformation build_information = 10044; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -2421,8 +2425,8 @@ message CpuTimePerFreq { */ message CpuTimePerUid { optional int32 uid = 1 [(is_uid) = true]; - optional uint64 user_time_millis = 2; - optional uint64 sys_time_millis = 3; + optional uint64 user_time_micros = 2; + optional uint64 sys_time_micros = 3; } /** @@ -3331,6 +3335,40 @@ message CpuTimePerThreadFreq { } /** + * Pulls information about the device's build. + */ +message BuildInformation { + // Build.FINGERPRINT. A string that uniquely identifies this build. Do not parse. + // E.g. may be composed of the brand, product, device, release, id, incremental, type, and tags. + optional string fingerprint = 1; + + // Build.BRAND. The consumer-visible brand with which the product/hardware will be associated. + optional string brand = 2; + + // Build.PRODUCT. The name of the overall product. + optional string product = 3; + + // Build.DEVICE. The name of the industrial design. + optional string device = 4; + + // Build.VERSION.RELEASE. The user-visible version string. E.g., "1.0" or "3.4b5" or "bananas". + optional string version_release = 5; + + // Build.ID. E.g. a label like "M4-rc20". + optional string id = 6; + + // Build.VERSION.INCREMENTAL. The internal value used by the underlying source control to + // represent this build. + optional string version_incremental = 7; + + // Build.TYPE. The type of build, like "user" or "eng". + optional string type = 8; + + // Build.TAGS. Comma-separated tags describing the build, like "unsigned,debug". + optional string tags = 9; +} + +/** * Pulls on-device BatteryStats power use calculations for the overall device. */ message DeviceCalculatedPowerUse { @@ -3389,3 +3427,25 @@ message DeviceCalculatedPowerBlameOther { // (i.e. roughly since device was last significantly charged). optional float power_milli_amp_hours = 2; } + +/** + * Logs device policy features. + * + * Logged from: + * frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java + * packages/apps/ManagedProvisioning/src/com/android/managedprovisioning/ + */ +message DevicePolicyEvent { + // The event id - unique for each event. + optional android.stats.devicepolicy.EventId event_id = 1; + // The admin package name. + optional string admin_package_name = 2; + // A generic integer parameter. + optional int32 integer_value = 3; + // A generic boolean parameter. + optional bool boolean_value = 4; + // A parameter specifying a time period in milliseconds. + optional uint64 time_period_millis = 5; + // A parameter specifying a list of package names, bundle extras or string parameters. + optional android.stats.devicepolicy.StringList string_list_value = 6 [(log_mode) = MODE_BYTES]; +} diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index ab635a048bbe..87a065b81813 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -265,6 +265,11 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}}, + // BuildInformation. + {android::util::BUILD_INFORMATION, + {{}, {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 343709a2a1eb..31570379b080 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -113,7 +113,7 @@ public: // Max memory allowed for storing metrics per configuration. If this limit is exceeded, statsd // drops the metrics data in memory. - static const size_t kMaxMetricsBytesPerConfig = 256 * 1024; + static const size_t kMaxMetricsBytesPerConfig = 2 * 1024 * 1024; // Soft memory limit per configuration. Once this limit is exceeded, we begin notifying the // data subscriber that it's time to call getData. @@ -130,7 +130,7 @@ public: static const int64_t kMinBroadcastPeriodNs = 60 * NS_PER_SEC; /* Min period between two checks of byte size per config key in nanoseconds. */ - static const int64_t kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC; + static const int64_t kMinByteSizeCheckPeriodNs = 60 * NS_PER_SEC; // Maximum age (30 days) that files on disk can exist in seconds. static const int kMaxAgeSecond = 60 * 60 * 24 * 30; diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index 2dcf50fd680c..c2e441b35f48 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -24296,7 +24296,8 @@ HSPLandroid/icu/util/CodePointMap;->get(I)I HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$RangeOption;ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z HSPLandroid/icu/util/CodePointMap;->iterator()Ljava/util/Iterator; -HSPLandroid/icu/util/CodePointMap;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;HSPLandroid/icu/util/Currency$1;-><init>()V +HSPLandroid/icu/util/CodePointMap;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator; +HSPLandroid/icu/util/Currency$1;-><init>()V HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/String;Ljava/lang/Void;)Landroid/icu/util/Currency; HSPLandroid/icu/util/Currency$CurrencyUsage;-><init>(Ljava/lang/String;I)V @@ -32940,8 +32941,8 @@ HSPLandroid/view/IWindowManager;->isViewServerRunning()Z HSPLandroid/view/IWindowManager;->isWindowTraceEnabled()Z HSPLandroid/view/IWindowManager;->lockNow(Landroid/os/Bundle;)V HSPLandroid/view/IWindowManager;->openSession(Landroid/view/IWindowSessionCallback;Lcom/android/internal/view/IInputMethodClient;Lcom/android/internal/view/IInputContext;)Landroid/view/IWindowSession; -HSPLandroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;Z)V -HSPLandroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;)V +HSPLandroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;Z;I)V +HSPLandroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;I)V HSPLandroid/view/IWindowManager;->prepareAppTransition(IZ)V HSPLandroid/view/IWindowManager;->reenableKeyguard(Landroid/os/IBinder;)V HSPLandroid/view/IWindowManager;->refreshScreenCaptureDisabled(I)V @@ -41154,7 +41155,7 @@ HSPLcom/android/internal/telephony/TimeServiceHelper;->setDeviceTimeZoneStatic(L HSPLcom/android/internal/telephony/TimeServiceHelper;->setListener(Lcom/android/internal/telephony/TimeServiceHelper$Listener;)V HSPLcom/android/internal/telephony/TimeZoneLookupHelper$CountryResult;->toString()Ljava/lang/String; HSPLcom/android/internal/telephony/TimeZoneLookupHelper$OffsetResult;->toString()Ljava/lang/String; -HSPLcom/android/internal/telephony/TimeZoneLookupHelper;->getCountryTimeZones(Ljava/lang/String;)Llibcore/util/CountryTimeZones; +HSPLcom/android/internal/telephony/TimeZoneLookupHelper;->getCountryTimeZones(Ljava/lang/String;)Llibcore/timezone/CountryTimeZones; HSPLcom/android/internal/telephony/TimeZoneLookupHelper;->lookupByCountry(Ljava/lang/String;J)Lcom/android/internal/telephony/TimeZoneLookupHelper$CountryResult; HSPLcom/android/internal/telephony/TimeZoneLookupHelper;->lookupByNitzCountry(Lcom/android/internal/telephony/NitzData;Ljava/lang/String;)Lcom/android/internal/telephony/TimeZoneLookupHelper$OffsetResult; HSPLcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastRangeForSubscriber(IIII)Z @@ -51930,7 +51931,46 @@ HSPLlibcore/reflect/Types;->getType(Ljava/lang/reflect/Type;)Ljava/lang/reflect/ HSPLlibcore/reflect/Types;->getTypeArray(Llibcore/reflect/ListOfTypes;Z)[Ljava/lang/reflect/Type; HSPLlibcore/reflect/WildcardTypeImpl;->getLowerBounds()[Ljava/lang/reflect/Type; HSPLlibcore/reflect/WildcardTypeImpl;->getUpperBounds()[Ljava/lang/reflect/Type; -HSPLlibcore/util/-$$Lambda$TimeZoneFinder$ReaderSupplier$IAVNuAYizGfcsPtGXEBkDPhlBF0;->get()Ljava/io/Reader; +HSPLlibcore/timezone/-$$Lambda$TimeZoneFinder$ReaderSupplier$IAVNuAYizGfcsPtGXEBkDPhlBF0;->get()Ljava/io/Reader; +HSPLlibcore/timezone/CountryTimeZones;->createValidated(Ljava/lang/String;Ljava/lang/String;ZLjava/util/List;Ljava/lang/String;)Llibcore/timezone/CountryTimeZones; +HSPLlibcore/timezone/CountryTimeZones;->getDefaultTimeZone()Landroid/icu/util/TimeZone; +HSPLlibcore/timezone/CountryTimeZones;->getIcuTimeZones()Ljava/util/List; +HSPLlibcore/timezone/CountryTimeZones;->isDefaultOkForCountryTimeZoneDetection(J)Z +HSPLlibcore/timezone/CountryTimeZones;->isForCountryCode(Ljava/lang/String;)Z +HSPLlibcore/timezone/CountryTimeZones;->lookupByOffsetWithBias(IZJLandroid/icu/util/TimeZone;)Llibcore/timezone/CountryTimeZones$OffsetResult; +HSPLlibcore/timezone/TimeZoneDataFiles;->generateIcuDataPath()Ljava/lang/String; +HSPLlibcore/timezone/TimeZoneDataFiles;->getTimeZoneFilePaths(Ljava/lang/String;)[Ljava/lang/String; +HSPLlibcore/timezone/TimeZoneFinder$ReaderSupplier;->forFile(Ljava/lang/String;Ljava/nio/charset/Charset;)Llibcore/timezone/TimeZoneFinder$ReaderSupplier; +HSPLlibcore/timezone/TimeZoneFinder$ReaderSupplier;->get()Ljava/io/Reader; +HSPLlibcore/timezone/TimeZoneFinder$SelectiveCountryTimeZonesExtractor;->processCountryZones(Ljava/lang/String;Ljava/lang/String;ZLjava/util/List;Ljava/lang/String;)Z +HSPLlibcore/timezone/TimeZoneFinder$TimeZonesProcessor;->processHeader(Ljava/lang/String;)Z +HSPLlibcore/timezone/TimeZoneFinder;->checkOnEndTag(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V +HSPLlibcore/timezone/TimeZoneFinder;->consumeText(Lorg/xmlpull/v1/XmlPullParser;)Ljava/lang/String; +HSPLlibcore/timezone/TimeZoneFinder;->createInstanceWithFallback([Ljava/lang/String;)Llibcore/timezone/TimeZoneFinder; +HSPLlibcore/timezone/TimeZoneFinder;->findStartTag(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z +HSPLlibcore/timezone/TimeZoneFinder;->getInstance()Llibcore/timezone/TimeZoneFinder; +HSPLlibcore/timezone/TimeZoneFinder;->lookupCountryTimeZones(Ljava/lang/String;)Llibcore/timezone/CountryTimeZones; +HSPLlibcore/timezone/TimeZoneFinder;->parseBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/Boolean; +HSPLlibcore/timezone/TimeZoneFinder;->parseLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/Long;)Ljava/lang/Long; +HSPLlibcore/timezone/TimeZoneFinder;->parseTimeZoneMappings(Lorg/xmlpull/v1/XmlPullParser;)Ljava/util/List; +HSPLlibcore/timezone/TimeZoneFinder;->processCountryZones(Lorg/xmlpull/v1/XmlPullParser;Llibcore/timezone/TimeZoneFinder$TimeZonesProcessor;)Z +HSPLlibcore/timezone/TimeZoneFinder;->processXml(Llibcore/timezone/TimeZoneFinder$TimeZonesProcessor;)V +HSPLlibcore/timezone/ZoneInfoDB$TzData$1;->create(Ljava/lang/Object;)Ljava/lang/Object; +HSPLlibcore/timezone/ZoneInfoDB$TzData$1;->create(Ljava/lang/String;)Llibcore/util/ZoneInfo; +HSPLlibcore/timezone/ZoneInfoDB$TzData;->close()V +HSPLlibcore/timezone/ZoneInfoDB$TzData;->finalize()V +HSPLlibcore/timezone/ZoneInfoDB$TzData;->getAvailableIDs()[Ljava/lang/String; +HSPLlibcore/timezone/ZoneInfoDB$TzData;->getBufferIterator(Ljava/lang/String;)Llibcore/io/BufferIterator; +HSPLlibcore/timezone/ZoneInfoDB$TzData;->hasTimeZone(Ljava/lang/String;)Z +HSPLlibcore/timezone/ZoneInfoDB$TzData;->loadData(Ljava/lang/String;)Z +HSPLlibcore/timezone/ZoneInfoDB$TzData;->loadTzDataWithFallback([Ljava/lang/String;)Llibcore/timezone/ZoneInfoDB$TzData; +HSPLlibcore/timezone/ZoneInfoDB$TzData;->makeTimeZone(Ljava/lang/String;)Llibcore/util/ZoneInfo; +HSPLlibcore/timezone/ZoneInfoDB$TzData;->makeTimeZoneUncached(Ljava/lang/String;)Llibcore/util/ZoneInfo; +HSPLlibcore/timezone/ZoneInfoDB$TzData;->readHeader()V +HSPLlibcore/timezone/ZoneInfoDB$TzData;->readIndex(Llibcore/io/BufferIterator;II)V +HSPLlibcore/timezone/ZoneInfoDB$TzData;->readZoneTab(Llibcore/io/BufferIterator;II)V +HSPLlibcore/timezone/ZoneInfoDB$TzData;->validateOffset(II)V +HSPLlibcore/timezone/ZoneInfoDB;->getInstance()Llibcore/timezone/ZoneInfoDB$TzData; HSPLlibcore/util/BasicLruCache;-><init>(I)V HSPLlibcore/util/BasicLruCache;->create(Ljava/lang/Object;)Ljava/lang/Object; HSPLlibcore/util/BasicLruCache;->entryEvicted(Ljava/lang/Object;Ljava/lang/Object;)V @@ -51938,12 +51978,6 @@ HSPLlibcore/util/BasicLruCache;->evictAll()V HSPLlibcore/util/BasicLruCache;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLlibcore/util/BasicLruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLlibcore/util/CollectionUtils;->removeDuplicates(Ljava/util/List;Ljava/util/Comparator;)V -HSPLlibcore/util/CountryTimeZones;->createValidated(Ljava/lang/String;Ljava/lang/String;ZLjava/util/List;Ljava/lang/String;)Llibcore/util/CountryTimeZones; -HSPLlibcore/util/CountryTimeZones;->getDefaultTimeZone()Landroid/icu/util/TimeZone; -HSPLlibcore/util/CountryTimeZones;->getIcuTimeZones()Ljava/util/List; -HSPLlibcore/util/CountryTimeZones;->isDefaultOkForCountryTimeZoneDetection(J)Z -HSPLlibcore/util/CountryTimeZones;->isForCountryCode(Ljava/lang/String;)Z -HSPLlibcore/util/CountryTimeZones;->lookupByOffsetWithBias(IZJLandroid/icu/util/TimeZone;)Llibcore/util/CountryTimeZones$OffsetResult; HSPLlibcore/util/HexEncoding;->encode([BII)[C HSPLlibcore/util/NativeAllocationRegistry$CleanerRunner;->run()V HSPLlibcore/util/NativeAllocationRegistry$CleanerThunk;->run()V @@ -51951,23 +51985,6 @@ HSPLlibcore/util/NativeAllocationRegistry;-><init>(Ljava/lang/ClassLoader;JJ)V HSPLlibcore/util/NativeAllocationRegistry;->registerNativeAllocation(Ljava/lang/Object;J)Ljava/lang/Runnable; HSPLlibcore/util/SneakyThrow;->sneakyThrow(Ljava/lang/Throwable;)V HSPLlibcore/util/SneakyThrow;->sneakyThrow_(Ljava/lang/Throwable;)V -HSPLlibcore/util/TimeZoneDataFiles;->generateIcuDataPath()Ljava/lang/String; -HSPLlibcore/util/TimeZoneDataFiles;->getTimeZoneFilePaths(Ljava/lang/String;)[Ljava/lang/String; -HSPLlibcore/util/TimeZoneFinder$ReaderSupplier;->forFile(Ljava/lang/String;Ljava/nio/charset/Charset;)Llibcore/util/TimeZoneFinder$ReaderSupplier; -HSPLlibcore/util/TimeZoneFinder$ReaderSupplier;->get()Ljava/io/Reader; -HSPLlibcore/util/TimeZoneFinder$SelectiveCountryTimeZonesExtractor;->processCountryZones(Ljava/lang/String;Ljava/lang/String;ZLjava/util/List;Ljava/lang/String;)Z -HSPLlibcore/util/TimeZoneFinder$TimeZonesProcessor;->processHeader(Ljava/lang/String;)Z -HSPLlibcore/util/TimeZoneFinder;->checkOnEndTag(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V -HSPLlibcore/util/TimeZoneFinder;->consumeText(Lorg/xmlpull/v1/XmlPullParser;)Ljava/lang/String; -HSPLlibcore/util/TimeZoneFinder;->createInstanceWithFallback([Ljava/lang/String;)Llibcore/util/TimeZoneFinder; -HSPLlibcore/util/TimeZoneFinder;->findStartTag(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z -HSPLlibcore/util/TimeZoneFinder;->getInstance()Llibcore/util/TimeZoneFinder; -HSPLlibcore/util/TimeZoneFinder;->lookupCountryTimeZones(Ljava/lang/String;)Llibcore/util/CountryTimeZones; -HSPLlibcore/util/TimeZoneFinder;->parseBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/Boolean; -HSPLlibcore/util/TimeZoneFinder;->parseLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/Long;)Ljava/lang/Long; -HSPLlibcore/util/TimeZoneFinder;->parseTimeZoneMappings(Lorg/xmlpull/v1/XmlPullParser;)Ljava/util/List; -HSPLlibcore/util/TimeZoneFinder;->processCountryZones(Lorg/xmlpull/v1/XmlPullParser;Llibcore/util/TimeZoneFinder$TimeZonesProcessor;)Z -HSPLlibcore/util/TimeZoneFinder;->processXml(Llibcore/util/TimeZoneFinder$TimeZonesProcessor;)V HSPLlibcore/util/ZoneInfo$WallTime;-><init>()V HSPLlibcore/util/ZoneInfo$WallTime;->copyFieldsFromCalendar()V HSPLlibcore/util/ZoneInfo$WallTime;->copyFieldsToCalendar()V @@ -52007,22 +52024,6 @@ HSPLlibcore/util/ZoneInfo;->hasSameRules(Ljava/util/TimeZone;)Z HSPLlibcore/util/ZoneInfo;->hashCode()I HSPLlibcore/util/ZoneInfo;->inDaylightTime(Ljava/util/Date;)Z HSPLlibcore/util/ZoneInfo;->readTimeZone(Ljava/lang/String;Llibcore/io/BufferIterator;J)Llibcore/util/ZoneInfo; -HSPLlibcore/util/ZoneInfoDB$TzData$1;->create(Ljava/lang/Object;)Ljava/lang/Object; -HSPLlibcore/util/ZoneInfoDB$TzData$1;->create(Ljava/lang/String;)Llibcore/util/ZoneInfo; -HSPLlibcore/util/ZoneInfoDB$TzData;->close()V -HSPLlibcore/util/ZoneInfoDB$TzData;->finalize()V -HSPLlibcore/util/ZoneInfoDB$TzData;->getAvailableIDs()[Ljava/lang/String; -HSPLlibcore/util/ZoneInfoDB$TzData;->getBufferIterator(Ljava/lang/String;)Llibcore/io/BufferIterator; -HSPLlibcore/util/ZoneInfoDB$TzData;->hasTimeZone(Ljava/lang/String;)Z -HSPLlibcore/util/ZoneInfoDB$TzData;->loadData(Ljava/lang/String;)Z -HSPLlibcore/util/ZoneInfoDB$TzData;->loadTzDataWithFallback([Ljava/lang/String;)Llibcore/util/ZoneInfoDB$TzData; -HSPLlibcore/util/ZoneInfoDB$TzData;->makeTimeZone(Ljava/lang/String;)Llibcore/util/ZoneInfo; -HSPLlibcore/util/ZoneInfoDB$TzData;->makeTimeZoneUncached(Ljava/lang/String;)Llibcore/util/ZoneInfo; -HSPLlibcore/util/ZoneInfoDB$TzData;->readHeader()V -HSPLlibcore/util/ZoneInfoDB$TzData;->readIndex(Llibcore/io/BufferIterator;II)V -HSPLlibcore/util/ZoneInfoDB$TzData;->readZoneTab(Llibcore/io/BufferIterator;II)V -HSPLlibcore/util/ZoneInfoDB$TzData;->validateOffset(II)V -HSPLlibcore/util/ZoneInfoDB;->getInstance()Llibcore/util/ZoneInfoDB$TzData; HSPLorg/apache/harmony/dalvik/ddmc/Chunk;-><init>(ILjava/nio/ByteBuffer;)V HSPLorg/apache/harmony/dalvik/ddmc/ChunkHandler;->putString(Ljava/nio/ByteBuffer;Ljava/lang/String;)V HSPLorg/apache/harmony/dalvik/ddmc/ChunkHandler;->type(Ljava/lang/String;)I @@ -63455,13 +63456,21 @@ Llibcore/reflect/ParameterizedTypeImpl; Llibcore/reflect/TypeVariableImpl; Llibcore/reflect/Types; Llibcore/reflect/WildcardTypeImpl; -Llibcore/util/-$$Lambda$TimeZoneFinder$ReaderSupplier$IAVNuAYizGfcsPtGXEBkDPhlBF0; +Llibcore/timezone/-$$Lambda$TimeZoneFinder$ReaderSupplier$IAVNuAYizGfcsPtGXEBkDPhlBF0; +Llibcore/timezone/CountryTimeZones$OffsetResult; +Llibcore/timezone/CountryTimeZones$TimeZoneMapping; +Llibcore/timezone/CountryTimeZones; +Llibcore/timezone/TimeZoneDataFiles; +Llibcore/timezone/TimeZoneFinder$ReaderSupplier; +Llibcore/timezone/TimeZoneFinder$SelectiveCountryTimeZonesExtractor; +Llibcore/timezone/TimeZoneFinder$TimeZonesProcessor; +Llibcore/timezone/TimeZoneFinder; +Llibcore/timezone/ZoneInfoDB$TzData$1; +Llibcore/timezone/ZoneInfoDB$TzData; +Llibcore/timezone/ZoneInfoDB; Llibcore/util/BasicLruCache; Llibcore/util/CharsetUtils; Llibcore/util/CollectionUtils; -Llibcore/util/CountryTimeZones$OffsetResult; -Llibcore/util/CountryTimeZones$TimeZoneMapping; -Llibcore/util/CountryTimeZones; Llibcore/util/EmptyArray; Llibcore/util/HexEncoding; Llibcore/util/NativeAllocationRegistry$CleanerRunner; @@ -63469,18 +63478,10 @@ Llibcore/util/NativeAllocationRegistry$CleanerThunk; Llibcore/util/NativeAllocationRegistry; Llibcore/util/Objects; Llibcore/util/SneakyThrow; -Llibcore/util/TimeZoneDataFiles; -Llibcore/util/TimeZoneFinder$ReaderSupplier; -Llibcore/util/TimeZoneFinder$SelectiveCountryTimeZonesExtractor; -Llibcore/util/TimeZoneFinder$TimeZonesProcessor; -Llibcore/util/TimeZoneFinder; Llibcore/util/ZoneInfo$CheckedArithmeticException; Llibcore/util/ZoneInfo$OffsetInterval; Llibcore/util/ZoneInfo$WallTime; Llibcore/util/ZoneInfo; -Llibcore/util/ZoneInfoDB$TzData$1; -Llibcore/util/ZoneInfoDB$TzData; -Llibcore/util/ZoneInfoDB; Lorg/apache/harmony/dalvik/NativeTestTarget; Lorg/apache/harmony/dalvik/ddmc/Chunk; Lorg/apache/harmony/dalvik/ddmc/ChunkHandler; diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 8a770b936563..0bfcadd04553 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -189,10 +189,10 @@ Landroid/app/IUiModeManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app Landroid/app/IUiModeManager;->disableCarMode(I)V Landroid/app/IUserSwitchObserver$Stub;-><init>()V Landroid/app/IWallpaperManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IWallpaperManager; -Landroid/app/IWallpaperManager;->getHeightHint()I +Landroid/app/IWallpaperManager;->getHeightHint(I)I Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor; Landroid/app/IWallpaperManager;->getWallpaperInfo(I)Landroid/app/WallpaperInfo; -Landroid/app/IWallpaperManager;->getWidthHint()I +Landroid/app/IWallpaperManager;->getWidthHint(I)I Landroid/app/IWallpaperManager;->hasNamedWallpaper(Ljava/lang/String;)Z Landroid/app/IWallpaperManager;->setWallpaperComponent(Landroid/content/ComponentName;)V Landroid/app/IWallpaperManagerCallback$Stub;-><init>()V @@ -1435,7 +1435,7 @@ Landroid/view/IWindowManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/view/IWindowManager$Stub$Proxy;->getBaseDisplayDensity(I)I Landroid/view/IWindowManager$Stub$Proxy;->getDockedStackSide()I Landroid/view/IWindowManager$Stub$Proxy;->getInitialDisplayDensity(I)I -Landroid/view/IWindowManager$Stub$Proxy;->hasNavigationBar()Z +Landroid/view/IWindowManager$Stub$Proxy;->hasNavigationBar(I)Z Landroid/view/IWindowManager$Stub$Proxy;->watchRotation(Landroid/view/IRotationWatcher;I)I Landroid/view/IWindowManager$Stub;-><init>()V Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager; @@ -1447,7 +1447,7 @@ Landroid/view/IWindowManager;->getBaseDisplaySize(ILandroid/graphics/Point;)V Landroid/view/IWindowManager;->getDockedStackSide()I Landroid/view/IWindowManager;->getInitialDisplayDensity(I)I Landroid/view/IWindowManager;->getInitialDisplaySize(ILandroid/graphics/Point;)V -Landroid/view/IWindowManager;->hasNavigationBar()Z +Landroid/view/IWindowManager;->hasNavigationBar(I)Z Landroid/view/IWindowManager;->isKeyguardLocked()Z Landroid/view/IWindowManager;->isKeyguardSecure()Z Landroid/view/IWindowManager;->isSafeModeEnabled()Z @@ -1488,86 +1488,10 @@ Landroid/widget/DigitalClock$FormatChangeObserver;-><init>(Landroid/widget/Digit Landroid/widget/QuickContactBadge$QueryHandler;-><init>(Landroid/widget/QuickContactBadge;Landroid/content/ContentResolver;)V Landroid/widget/RelativeLayout$DependencyGraph$Node;-><init>()V Landroid/widget/ScrollBarDrawable;-><init>()V -Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->clear()V -Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->getRememberedPosition()I -Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigit(C)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigitAndRememberPosition(C)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getDescriptionForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/util/Locale;)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getInstance()Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder; -Lcom/android/i18n/phonenumbers/NumberParseException;->getErrorType()Lcom/android/i18n/phonenumbers/NumberParseException$ErrorType; -Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getDomesticCarrierCodeFormattingRule()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getFormat()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getLeadingDigitsPattern(I)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getNationalPrefixFormattingRule()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getPattern()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->leadingDigitsPatternSize()I -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getCountryCode()I -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getGeneralDesc()Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixForParsing()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixTransformRule()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getPreferredExtnPrefix()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasNationalPrefix()Z -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasPreferredExtnPrefix()Z -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->intlNumberFormats()Ljava/util/List; -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->numberFormats()Ljava/util/List; -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;-><init>()V -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;->getMetadataList()Ljava/util/List; -Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->getNationalNumberPattern()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_DEFAULT_COUNTRY:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITHOUT_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_IDD:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->values()[Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->clearCountryCode()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCode()I -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCodeSource()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getExtension()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getNationalNumber()J -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasCountryCode()Z -Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasExtension()Z -Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->end()I -Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->number()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber; -Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->rawString()Ljava/lang/String; -Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->start()I -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;->POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->EXACT_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NOT_A_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NO_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->SHORT_NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->E164:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->INTERNATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->NATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->RFC3966:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE_OR_MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PAGER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PERSONAL_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PREMIUM_RATE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->SHARED_COST:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->TOLL_FREE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->UAN:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOICEMAIL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOIP:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->IS_POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->TOO_LONG:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->findNumbers(Ljava/lang/CharSequence;Ljava/lang/String;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;J)Ljava/lang/Iterable; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->format(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->formatInOriginalFormat(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/lang/String;)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getAsYouTypeFormatter(Ljava/lang/String;)Lcom/android/i18n/phonenumbers/AsYouTypeFormatter; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getCountryCodeForRegion(Ljava/lang/String;)I -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getInstance()Lcom/android/i18n/phonenumbers/PhoneNumberUtil; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNationalSignificantNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNumberType(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getRegionCodeForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isNumberMatch(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumberWithReason(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; -Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isValidNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z Lcom/android/ims/ImsCall;->deflect(Ljava/lang/String;)V Lcom/android/ims/ImsCall;->isMultiparty()Z Lcom/android/ims/ImsCall;->reject(I)V @@ -4139,77 +4063,6 @@ Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrolled(IFI Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrollStateChanged(I)V Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageSelected(I)V Lcom/android/internal/widget/ViewPager;->getCurrentItem()I -Lcom/android/okhttp/Connection;->getSocket()Ljava/net/Socket; -Lcom/android/okhttp/ConnectionPool;->connections:Ljava/util/Deque; -Lcom/android/okhttp/ConnectionPool;->keepAliveDurationNs:J -Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I -Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool; -Lcom/android/okhttp/HttpHandler;-><init>()V -Lcom/android/okhttp/HttpsHandler;-><init>()V -Lcom/android/okhttp/HttpUrl$Builder;->build()Lcom/android/okhttp/HttpUrl; -Lcom/android/okhttp/HttpUrl;->encodedPath()Ljava/lang/String; -Lcom/android/okhttp/HttpUrl;->newBuilder()Lcom/android/okhttp/HttpUrl$Builder; -Lcom/android/okhttp/HttpUrl;->parse(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl; -Lcom/android/okhttp/HttpUrl;->query()Ljava/lang/String; -Lcom/android/okhttp/internal/http/HeaderParser;->skipUntil(Ljava/lang/String;ILjava/lang/String;)I -Lcom/android/okhttp/internal/http/HeaderParser;->skipWhitespace(Ljava/lang/String;I)I -Lcom/android/okhttp/internal/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String; -Lcom/android/okhttp/internal/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date; -Lcom/android/okhttp/internal/http/HttpEngine;->getConnection()Lcom/android/okhttp/Connection; -Lcom/android/okhttp/internal/http/HttpEngine;->hasResponse()Z -Lcom/android/okhttp/internal/http/HttpEngine;->httpStream:Lcom/android/okhttp/internal/http/HttpStream; -Lcom/android/okhttp/internal/http/HttpEngine;->networkRequest(Lcom/android/okhttp/Request;)Lcom/android/okhttp/Request; -Lcom/android/okhttp/internal/http/HttpEngine;->networkRequest:Lcom/android/okhttp/Request; -Lcom/android/okhttp/internal/http/HttpEngine;->priorResponse:Lcom/android/okhttp/Response; -Lcom/android/okhttp/internal/http/HttpEngine;->readResponse()V -Lcom/android/okhttp/internal/http/HttpEngine;->sendRequest()V -Lcom/android/okhttp/internal/http/HttpEngine;->sentRequestMillis:J -Lcom/android/okhttp/internal/http/HttpEngine;->userResponse:Lcom/android/okhttp/Response; -Lcom/android/okhttp/internal/http/HttpEngine;->writingRequestHeaders()V -Lcom/android/okhttp/internal/http/RouteSelector;->hasNext()Z -Lcom/android/okhttp/internal/huc/HttpsURLConnectionImpl;->delegate:Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl; -Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->client:Lcom/android/okhttp/OkHttpClient; -Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->httpEngine:Lcom/android/okhttp/internal/http/HttpEngine; -Lcom/android/okhttp/internal/Internal;-><init>()V -Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;)V -Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;Ljava/lang/String;)V -Lcom/android/okhttp/internal/Internal;->apply(Lcom/android/okhttp/ConnectionSpec;Ljavax/net/ssl/SSLSocket;Z)V -Lcom/android/okhttp/internal/Internal;->callEngineGetStreamAllocation(Lcom/android/okhttp/Call;)Lcom/android/okhttp/internal/http/StreamAllocation; -Lcom/android/okhttp/internal/Internal;->callEnqueue(Lcom/android/okhttp/Call;Lcom/android/okhttp/Callback;Z)V -Lcom/android/okhttp/internal/Internal;->connectionBecameIdle(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)Z -Lcom/android/okhttp/internal/Internal;->get(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/Address;Lcom/android/okhttp/internal/http/StreamAllocation;)Lcom/android/okhttp/internal/io/RealConnection; -Lcom/android/okhttp/internal/Internal;->getHttpUrlChecked(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl; -Lcom/android/okhttp/internal/Internal;->instance:Lcom/android/okhttp/internal/Internal; -Lcom/android/okhttp/internal/Internal;->internalCache(Lcom/android/okhttp/OkHttpClient;)Lcom/android/okhttp/internal/InternalCache; -Lcom/android/okhttp/internal/Internal;->put(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)V -Lcom/android/okhttp/internal/Internal;->routeDatabase(Lcom/android/okhttp/ConnectionPool;)Lcom/android/okhttp/internal/RouteDatabase; -Lcom/android/okhttp/internal/Internal;->setCache(Lcom/android/okhttp/OkHttpClient;Lcom/android/okhttp/internal/InternalCache;)V -Lcom/android/okhttp/internal/Platform;->get()Lcom/android/okhttp/internal/Platform; -Lcom/android/okhttp/internal/Platform;->logW(Ljava/lang/String;)V -Lcom/android/okhttp/internal/Util;->closeAll(Ljava/io/Closeable;Ljava/io/Closeable;)V -Lcom/android/okhttp/internal/Util;->closeQuietly(Ljava/io/Closeable;)V -Lcom/android/okhttp/internal/Util;->EMPTY_BYTE_ARRAY:[B -Lcom/android/okhttp/internal/Util;->UTF_8:Ljava/nio/charset/Charset; -Lcom/android/okhttp/OkHttpClient;-><init>()V -Lcom/android/okhttp/OkHttpClient;->connectionPool:Lcom/android/okhttp/ConnectionPool; -Lcom/android/okhttp/OkHttpClient;->DEFAULT_PROTOCOLS:Ljava/util/List; -Lcom/android/okhttp/OkHttpClient;->dns:Lcom/android/okhttp/Dns; -Lcom/android/okhttp/OkHttpClient;->getConnectionPool()Lcom/android/okhttp/ConnectionPool; -Lcom/android/okhttp/OkHttpClient;->getCookieHandler()Ljava/net/CookieHandler; -Lcom/android/okhttp/OkHttpClient;->getHostnameVerifier()Ljavax/net/ssl/HostnameVerifier; -Lcom/android/okhttp/OkHttpClient;->getProxy()Ljava/net/Proxy; -Lcom/android/okhttp/OkHttpClient;->getProxySelector()Ljava/net/ProxySelector; -Lcom/android/okhttp/OkHttpClient;->getSslSocketFactory()Ljavax/net/ssl/SSLSocketFactory; -Lcom/android/okhttp/OkHttpClient;->setProtocols(Ljava/util/List;)Lcom/android/okhttp/OkHttpClient; -Lcom/android/okhttp/OkHttpClient;->setRetryOnConnectionFailure(Z)V -Lcom/android/okhttp/Request;->headers:Lcom/android/okhttp/Headers; -Lcom/android/okhttp/Request;->method:Ljava/lang/String; -Lcom/android/okhttp/Request;->url:Lcom/android/okhttp/HttpUrl; -Lcom/android/okhttp/Response;->code:I -Lcom/android/okhttp/Response;->headers:Lcom/android/okhttp/Headers; -Lcom/android/okhttp/Response;->message:Ljava/lang/String; -Lcom/android/okhttp/Response;->networkResponse:Lcom/android/okhttp/Response; -Lcom/android/okhttp/Response;->protocol:Lcom/android/okhttp/Protocol; Lcom/android/server/net/BaseNetworkObserver;-><init>()V Lcom/android/server/net/NetlinkTracker;-><init>(Ljava/lang/String;Lcom/android/server/net/NetlinkTracker$Callback;)V Lcom/android/server/net/NetlinkTracker;->clearLinkProperties()V @@ -4809,7 +4662,6 @@ Llibcore/util/BasicLruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lan Llibcore/util/EmptyArray;->BYTE:[B Llibcore/util/EmptyArray;->INT:[I Llibcore/util/EmptyArray;->OBJECT:[Ljava/lang/Object; -Llibcore/util/ZoneInfoDB$TzData;-><init>()V Lorg/apache/harmony/dalvik/ddmc/Chunk;-><init>(ILjava/nio/ByteBuffer;)V Lorg/apache/harmony/dalvik/ddmc/ChunkHandler;->CHUNK_ORDER:Ljava/nio/ByteOrder; Lorg/apache/harmony/dalvik/ddmc/DdmServer;->broadcast(I)V diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 575ba340f52a..a21fa3063f17 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -147,8 +147,8 @@ Landroid/view/IWindowManager;->createInputConsumer(Landroid/os/IBinder;Ljava/lan Landroid/view/IWindowManager;->destroyInputConsumer(Ljava/lang/String;I)Z Landroid/view/IWindowManager;->endProlongedAnimations()V Landroid/view/IWindowManager;->getStableInsets(ILandroid/graphics/Rect;)V -Landroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;Z)V -Landroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;)V +Landroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;ZI)V +Landroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;I)V Landroid/view/IWindowManager;->setNavBarVirtualKeyHapticFeedbackEnabled(Z)V Lcom/android/ims/ImsConfigListener;->onSetFeatureResponse(IIII)V Lcom/android/ims/internal/IImsCallSessionListener;->callSessionConferenceStateUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsConferenceState;)V diff --git a/config/preloaded-classes b/config/preloaded-classes index 550e795bd1e6..5940c45466fb 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -6172,6 +6172,9 @@ libcore.reflect.TypeVariableImpl libcore.reflect.Types libcore.reflect.WildcardTypeImpl libcore.timezone.TimeZoneDataFiles +libcore.timezone.ZoneInfoDB +libcore.timezone.ZoneInfoDB$TzData +libcore.timezone.ZoneInfoDB$TzData$1 libcore.util.BasicLruCache libcore.util.CharsetUtils libcore.util.CollectionUtils @@ -6184,9 +6187,6 @@ libcore.util.SneakyThrow libcore.util.ZoneInfo libcore.util.ZoneInfo$CheckedArithmeticException libcore.util.ZoneInfo$WallTime -libcore.util.ZoneInfoDB -libcore.util.ZoneInfoDB$TzData -libcore.util.ZoneInfoDB$TzData$1 org.apache.harmony.dalvik.NativeTestTarget org.apache.harmony.dalvik.ddmc.Chunk org.apache.harmony.dalvik.ddmc.ChunkHandler diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index 9b134208cb80..2f0f14aab75a 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -35,7 +35,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.proto.ProtoOutputStream; -import libcore.util.ZoneInfoDB; +import libcore.timezone.ZoneInfoDB; import java.io.IOException; import java.lang.annotation.Retention; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 63a41ecc8b86..3069be6b5714 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1180,11 +1180,11 @@ public class AppOpsManager { Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission.SMS_FINANCIAL_TRANSACTIONS, Manifest.permission.READ_MEDIA_AUDIO, - Manifest.permission.WRITE_MEDIA_AUDIO, + null, // no permission for OP_WRITE_MEDIA_AUDIO Manifest.permission.READ_MEDIA_VIDEO, - Manifest.permission.WRITE_MEDIA_VIDEO, + null, // no permission for OP_WRITE_MEDIA_VIDEO Manifest.permission.READ_MEDIA_IMAGES, - Manifest.permission.WRITE_MEDIA_IMAGES, + null, // no permission for OP_WRITE_MEDIA_IMAGES }; /** @@ -1462,11 +1462,11 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION AppOpsManager.MODE_DEFAULT, // SMS_FINANCIAL_TRANSACTIONS AppOpsManager.MODE_ALLOWED, // READ_MEDIA_AUDIO - AppOpsManager.MODE_ALLOWED, // WRITE_MEDIA_AUDIO + AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_AUDIO AppOpsManager.MODE_ALLOWED, // READ_MEDIA_VIDEO - AppOpsManager.MODE_ALLOWED, // WRITE_MEDIA_VIDEO + AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_VIDEO AppOpsManager.MODE_ALLOWED, // READ_MEDIA_IMAGES - AppOpsManager.MODE_ALLOWED, // WRITE_MEDIA_IMAGES + AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES }; /** diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 8bb704d76e85..8a797dcaf449 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2046,8 +2046,6 @@ public class ApplicationPackageManager extends PackageManager { StorageManager storage) { if (app.isInternal()) { return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL); - } else if (app.isExternalAsec()) { - return storage.getPrimaryPhysicalVolume(); } else { return storage.findVolumeByUuid(app.volumeUuid); } diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 5ef4be18ef2f..00547b4a5ce4 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -87,24 +87,24 @@ interface IWallpaperManager { /** * Sets the dimension hint for the wallpaper. These hints indicate the desired - * minimum width and height for the wallpaper. + * minimum width and height for the wallpaper in a particular display. */ - void setDimensionHints(in int width, in int height, in String callingPackage); + void setDimensionHints(in int width, in int height, in String callingPackage, int displayId); /** - * Returns the desired minimum width for the wallpaper. + * Returns the desired minimum width for the wallpaper in a particular display. */ - int getWidthHint(); + int getWidthHint(int displayId); /** - * Returns the desired minimum height for the wallpaper. + * Returns the desired minimum height for the wallpaper in a particular display. */ - int getHeightHint(); + int getHeightHint(int displayId); /** * Sets extra padding that we would like the wallpaper to have outside of the display. */ - void setDisplayPadding(in Rect padding, in String callingPackage); + void setDisplayPadding(in Rect padding, in String callingPackage, int displayId); /** * Returns the name of the wallpaper. Private API. diff --git a/core/java/android/app/Person.java b/core/java/android/app/Person.java index a2dae3b9de03..0abc99821c1e 100644 --- a/core/java/android/app/Person.java +++ b/core/java/android/app/Person.java @@ -127,8 +127,8 @@ public final class Person implements Parcelable { if (obj instanceof Person) { final Person other = (Person) obj; return Objects.equals(mName, other.mName) - && mIcon == null ? other.mIcon == null : - (other.mIcon != null && mIcon.sameAs(other.mIcon)) + && (mIcon == null ? other.mIcon == null : + (other.mIcon != null && mIcon.sameAs(other.mIcon))) && Objects.equals(mUri, other.mUri) && Objects.equals(mKey, other.mKey) && mIsBot == other.mIsBot diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index e33d1fed4b4c..3ea3da25e2fc 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -36,6 +36,7 @@ import android.service.wallpaper.WallpaperService; import android.util.AttributeSet; import android.util.Printer; import android.util.Xml; +import android.view.SurfaceHolder; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -79,6 +80,7 @@ public final class WallpaperInfo implements Parcelable { final boolean mShowMetadataInPreview; final boolean mSupportsAmbientMode; final String mSettingsSliceUri; + final boolean mSupportMultipleDisplays; /** * Constructor. @@ -143,6 +145,9 @@ public final class WallpaperInfo implements Parcelable { false); mSettingsSliceUri = sa.getString( com.android.internal.R.styleable.Wallpaper_settingsSliceUri); + mSupportMultipleDisplays = sa.getBoolean( + com.android.internal.R.styleable.Wallpaper_supportsMultipleDisplays, + false); sa.recycle(); } catch (NameNotFoundException e) { @@ -163,6 +168,7 @@ public final class WallpaperInfo implements Parcelable { mShowMetadataInPreview = source.readInt() != 0; mSupportsAmbientMode = source.readInt() != 0; mSettingsSliceUri = source.readString(); + mSupportMultipleDisplays = source.readInt() != 0; mService = ResolveInfo.CREATOR.createFromParcel(source); } @@ -358,6 +364,19 @@ public final class WallpaperInfo implements Parcelable { return Uri.parse(mSettingsSliceUri); } + /** + * Returns whether this wallpaper service can support multiple engines to render on each surface + * independently. An example use case is a multi-display set-up where the wallpaper service can + * render surfaces to each of the connected displays. + * + * @see WallpaperService#onCreateEngine() + * @see WallpaperService.Engine#onCreate(SurfaceHolder) + * @return {@code true} if multiple engines can render independently on each surface. + */ + public boolean supportsMultipleDisplays() { + return mSupportMultipleDisplays; + } + public void dump(Printer pw, String prefix) { pw.println(prefix + "Service:"); mService.dump(pw, prefix + " "); @@ -387,6 +406,7 @@ public final class WallpaperInfo implements Parcelable { dest.writeInt(mShowMetadataInPreview ? 1 : 0); dest.writeInt(mSupportsAmbientMode ? 1 : 0); dest.writeString(mSettingsSliceUri); + dest.writeInt(mSupportMultipleDisplays ? 1 : 0); mService.writeToParcel(dest, flags); } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index bebe79e41e5b..27471cac10e9 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1485,7 +1485,7 @@ public class WallpaperManager { throw new RuntimeException(new DeadSystemException()); } try { - return sGlobals.mService.getWidthHint(); + return sGlobals.mService.getWidthHint(mContext.getDisplayId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1511,7 +1511,7 @@ public class WallpaperManager { throw new RuntimeException(new DeadSystemException()); } try { - return sGlobals.mService.getHeightHint(); + return sGlobals.mService.getHeightHint(mContext.getDisplayId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1572,7 +1572,7 @@ public class WallpaperManager { throw new RuntimeException(new DeadSystemException()); } else { sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight, - mContext.getOpPackageName()); + mContext.getOpPackageName(), mContext.getDisplayId()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1597,7 +1597,8 @@ public class WallpaperManager { Log.w(TAG, "WallpaperService not running"); throw new RuntimeException(new DeadSystemException()); } else { - sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName()); + sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName(), + mContext.getDisplayId()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 55148511ed10..3f348033a8aa 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -193,10 +193,6 @@ public final class UsageStatsManager { /** @hide */ public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D; /** @hide */ - public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_START = 0x000E; - /** @hide */ - public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP = 0x000F; - /** @hide */ public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 75f5b1731e88..e7f0053721d1 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3589,6 +3589,27 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE"; + + /** + * Activity Action: Perform text translation. + * <p> + * Input: {@link #EXTRA_TEXT getCharSequence(EXTRA_TEXT)} is the text to translate. + * <p> + * Output: nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_TRANSLATE = "android.intent.action.TRANSLATE"; + + /** + * Activity Action: Define the meaning of the selected word(s). + * <p> + * Input: {@link #EXTRA_TEXT getCharSequence(EXTRA_TEXT)} is the text to define. + * <p> + * Output: nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_DEFINE = "android.intent.action.DEFINE"; + /** * Broadcast Action: List of dynamic sensor is changed due to new sensor being connected or * exisiting sensor being disconnected. diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 4e110dad44ff..7c3b5e48cb5b 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -32,7 +32,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import android.os.storage.StorageManager; -import android.text.TextUtils; import android.util.Printer; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; @@ -464,16 +463,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1<<1; /** - * Value for {@link #privateFlags}: Set to true if the application has been - * installed using the forward lock option. - * - * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml. - * - * {@hide} - */ - public static final int PRIVATE_FLAG_FORWARD_LOCK = 1<<2; - - /** * Value for {@link #privateFlags}: set to {@code true} if the application * is permitted to hold privileged permissions. * @@ -651,7 +640,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_CANT_SAVE_STATE, PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, PRIVATE_FLAG_DIRECT_BOOT_AWARE, - PRIVATE_FLAG_FORWARD_LOCK, PRIVATE_FLAG_HAS_DOMAIN_URLS, PRIVATE_FLAG_HIDDEN, PRIVATE_FLAG_INSTANT, @@ -1843,17 +1831,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } - /** @hide */ - public boolean isExternalAsec() { - return TextUtils.isEmpty(volumeUuid) && isExternal(); - } - - /** @hide */ - @UnsupportedAppUsage - public boolean isForwardLocked() { - return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; - } - /** * True if the application is installed as an instant app. * @hide diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 8f901996db40..07672d979cf5 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1374,12 +1374,6 @@ public class PackageInstaller { } /** {@hide} */ - public void setInstallFlagsInternal() { - installFlags |= PackageManager.INSTALL_INTERNAL; - installFlags &= ~PackageManager.INSTALL_EXTERNAL; - } - - /** {@hide} */ @SystemApi public void setAllowDowngrade(boolean allowDowngrade) { if (allowDowngrade) { @@ -1390,12 +1384,6 @@ public class PackageInstaller { } /** {@hide} */ - public void setInstallFlagsExternal() { - installFlags |= PackageManager.INSTALL_EXTERNAL; - installFlags &= ~PackageManager.INSTALL_INTERNAL; - } - - /** {@hide} */ public void setInstallFlagsForcePermissionPrompt() { installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT; } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index ad06be3b026b..a4b724ba48e7 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -700,10 +700,8 @@ public abstract class PackageManager { /** @hide */ @IntDef(flag = true, prefix = { "INSTALL_" }, value = { - INSTALL_FORWARD_LOCK, INSTALL_REPLACE_EXISTING, INSTALL_ALLOW_TEST, - INSTALL_EXTERNAL, INSTALL_INTERNAL, INSTALL_FROM_ADB, INSTALL_ALL_USERS, @@ -721,17 +719,6 @@ public abstract class PackageManager { public @interface InstallFlags {} /** - * Flag parameter for {@link #installPackage} to indicate that this package - * should be installed as forward locked, i.e. only the app itself should - * have access to its code and non-resource assets. - * - * @deprecated new installs into ASEC containers are no longer supported. - * @hide - */ - @Deprecated - public static final int INSTALL_FORWARD_LOCK = 0x00000001; - - /** * Flag parameter for {@link #installPackage} to indicate that you want to * replace an already installed package, if one exists. * @@ -750,17 +737,6 @@ public abstract class PackageManager { /** * Flag parameter for {@link #installPackage} to indicate that this package - * must be installed to an ASEC on a {@link VolumeInfo#TYPE_PUBLIC}. - * - * @deprecated new installs into ASEC containers are no longer supported; - * use adoptable storage instead. - * @hide - */ - @Deprecated - public static final int INSTALL_EXTERNAL = 0x00000008; - - /** - * Flag parameter for {@link #installPackage} to indicate that this package * must be installed to internal storage. * * @hide @@ -1521,14 +1497,6 @@ public abstract class PackageManager { /** * Error code that is passed to the {@link IPackageMoveObserver} if the - * specified package cannot be moved since its forward locked. - * - * @hide - */ - public static final int MOVE_FAILED_FORWARD_LOCKED = -4; - - /** - * Error code that is passed to the {@link IPackageMoveObserver} if the * specified package cannot be moved to the specified location. * * @hide @@ -3143,33 +3111,6 @@ public abstract class PackageManager { @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException; /** - * Retrieve overall information about an application package that is - * installed on the system. - * - * @param packageName The full name (i.e. com.google.apps.contacts) of the - * desired package. - * @param flags Additional option flags to modify the data returned. - * @param userHandle The user. - * @return A PackageInfo object containing information about the package. If - * flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the package - * is not found in the list of installed applications, the package - * information is retrieved from the list of uninstalled - * applications (which includes installed applications as well as - * applications with data directory i.e. applications which had been - * deleted with {@code DONT_DELETE_DATA} flag set). - * @throws NameNotFoundException if a package with the given name cannot be - * found on the system. - * @hide - */ - @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) - @SystemApi - public @NonNull PackageInfo getPackageInfoAsUser(@NonNull String packageName, - @PackageInfoFlags int flags, - @NonNull UserHandle userHandle) throws NameNotFoundException { - return getPackageInfoAsUser(packageName, flags, userHandle.getIdentifier()); - } - - /** * Map from the current package names in use on the device to whatever * the current canonical name of that package is. * @param names Array of current names to be mapped. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 2fcf1dd0a3a8..d00c9a036a53 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -829,9 +829,6 @@ public class PackageParser { public static final int PARSE_MUST_BE_APK = 1 << 0; public static final int PARSE_IGNORE_PROCESSES = 1 << 1; - /** @deprecated forward lock no longer functional. remove. */ - @Deprecated - public static final int PARSE_FORWARD_LOCK = 1 << 2; public static final int PARSE_EXTERNAL_STORAGE = 1 << 3; public static final int PARSE_IS_SYSTEM_DIR = 1 << 4; public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5; @@ -845,7 +842,6 @@ public class PackageParser { PARSE_ENFORCE_CODE, PARSE_EXTERNAL_STORAGE, PARSE_FORCE_SDK, - PARSE_FORWARD_LOCK, PARSE_IGNORE_PROCESSES, PARSE_IS_SYSTEM_DIR, PARSE_MUST_BE_APK, @@ -2006,11 +2002,6 @@ public class PackageParser { PARSE_DEFAULT_TARGET_SANDBOX); pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion; - /* Set the global "forward lock" flag */ - if ((flags & PARSE_FORWARD_LOCK) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK; - } - /* Set the global "on SD card" flag */ if ((flags & PARSE_EXTERNAL_STORAGE) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; @@ -2532,55 +2523,33 @@ public class PackageParser { final ArraySet<String> newPermissions = new ArraySet<>(); newPermissions.add(android.Manifest.permission.READ_MEDIA_AUDIO); - newPermissions.add(android.Manifest.permission.WRITE_MEDIA_AUDIO); newPermissions.add(android.Manifest.permission.READ_MEDIA_VIDEO); - newPermissions.add(android.Manifest.permission.WRITE_MEDIA_VIDEO); newPermissions.add(android.Manifest.permission.READ_MEDIA_IMAGES); - newPermissions.add(android.Manifest.permission.WRITE_MEDIA_IMAGES); newPermissions.add(android.Manifest.permission.ACCESS_MEDIA_LOCATION); newPermissions.add(android.Manifest.permission.WRITE_OBB); - final ArraySet<String> dangerousPermissions = new ArraySet<>(); - dangerousPermissions.add(android.Manifest.permission.READ_EXTERNAL_STORAGE); - dangerousPermissions.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE); + final ArraySet<String> removedPermissions = new ArraySet<>(); + removedPermissions.add(android.Manifest.permission.READ_EXTERNAL_STORAGE); + removedPermissions.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE); for (int i = pkg.permissions.size() - 1; i >= 0; i--) { final Permission p = pkg.permissions.get(i); if (newPermissions.contains(p.info.name)) { pkg.permissions.remove(i); - } else if (dangerousPermissions.contains(p.info.name)) { - p.info.protectionLevel &= ~PermissionInfo.PROTECTION_MASK_BASE; - p.info.protectionLevel |= PermissionInfo.PROTECTION_DANGEROUS; + } else if (removedPermissions.contains(p.info.name)) { + p.info.flags &= ~PermissionInfo.FLAG_REMOVED; } } } } else { if (FORCE_AUDIO_PACKAGES.contains(pkg.packageName)) { pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_AUDIO); - pkg.requestedPermissions.add(android.Manifest.permission.WRITE_MEDIA_AUDIO); } if (FORCE_VIDEO_PACKAGES.contains(pkg.packageName)) { pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_VIDEO); - pkg.requestedPermissions.add(android.Manifest.permission.WRITE_MEDIA_VIDEO); } if (FORCE_IMAGES_PACKAGES.contains(pkg.packageName)) { pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_IMAGES); - pkg.requestedPermissions.add(android.Manifest.permission.WRITE_MEDIA_IMAGES); - } - - if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_LEGACY, false)) { - if (pkg.requestedPermissions - .contains(android.Manifest.permission.READ_EXTERNAL_STORAGE)) { - pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_AUDIO); - pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_VIDEO); - pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_IMAGES); - } - if (pkg.requestedPermissions - .contains(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - pkg.requestedPermissions.add(android.Manifest.permission.WRITE_MEDIA_AUDIO); - pkg.requestedPermissions.add(android.Manifest.permission.WRITE_MEDIA_VIDEO); - pkg.requestedPermissions.add(android.Manifest.permission.WRITE_MEDIA_IMAGES); - } } } @@ -5369,6 +5338,11 @@ public class PackageParser { s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE; } if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestService_useAppZygote, + false)) { + s.info.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE; + } + if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestService_singleUser, false)) { s.info.flags |= ServiceInfo.FLAG_SINGLE_USER; @@ -6801,7 +6775,7 @@ public class PackageParser { /** @hide */ public boolean isForwardLocked() { - return applicationInfo.isForwardLocked(); + return false; } /** @hide */ @@ -6843,9 +6817,7 @@ public class PackageParser { public boolean canHaveOatDir() { // The following app types CANNOT have oat directory // - non-updated system apps - // - forward-locked apps or apps installed in ASEC containers - return (!isSystem() || isUpdatedSystemApp()) - && !isForwardLocked() && !applicationInfo.isExternalAsec(); + return !isSystem() || isUpdatedSystemApp(); } public boolean isMatch(int flags) { diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 91f884ccd3dc..ad2c72274c07 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -56,6 +56,23 @@ public class ServiceInfo extends ComponentInfo public static final int FLAG_EXTERNAL_SERVICE = 0x0004; /** + * Bit in {@link #flags}: If set, the service (which must be isolated) + * will be spawned from an Application Zygote, instead of the regular Zygote. + * The Application Zygote will pre-initialize the application's class loader, + * and call a static callback into the application to allow it to perform + * application-specific preloads (such as loading a shared library). Therefore, + * spawning from the Application Zygote will typically reduce the service + * launch time and reduce its memory usage. The downside of using this flag + * is that you will have an additional process (the app zygote itself) that + * is taking up memory. Whether actual memory usage is improved therefore + * strongly depends on the number of isolated services that an application + * starts, and how much memory those services save by preloading. Therefore, + * it is recommended to measure memory usage under typical workloads to + * determine whether it makes sense to use this flag. + */ + public static final int FLAG_USE_APP_ZYGOTE = 0x0008; + + /** * Bit in {@link #flags} indicating if the service is visible to ephemeral applications. * @hide */ diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 4371c772c047..740cdae0dd5b 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -58,7 +58,7 @@ import java.util.HashMap; public final class AssetManager implements AutoCloseable { private static final String TAG = "AssetManager"; private static final boolean DEBUG_REFS = false; - private static final boolean FEATURE_FLAG_IDMAP2 = false; + private static final boolean FEATURE_FLAG_IDMAP2 = true; private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/core/java/android/hardware/location/ContextHubIntentEvent.java b/core/java/android/hardware/location/ContextHubIntentEvent.java index 539c49408c8f..d1190ab28ed5 100644 --- a/core/java/android/hardware/location/ContextHubIntentEvent.java +++ b/core/java/android/hardware/location/ContextHubIntentEvent.java @@ -17,6 +17,7 @@ package android.hardware.location; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.app.PendingIntent; import android.content.Intent; @@ -30,6 +31,7 @@ import com.android.internal.util.Preconditions; * * @hide */ +@SystemApi public class ContextHubIntentEvent { @ContextHubManager.Event private final int mEventType; diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 88fb3de24c91..76393022ef2f 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -56,38 +56,28 @@ public final class ContextHubManager { /** * An extra of type {@link ContextHubInfo} describing the source of the event. - * - * @hide */ public static final String EXTRA_CONTEXT_HUB_INFO = "android.hardware.location.extra.CONTEXT_HUB_INFO"; /** * An extra of type {@link ContextHubManager.Event} describing the event type. - * - * @hide */ public static final String EXTRA_EVENT_TYPE = "android.hardware.location.extra.EVENT_TYPE"; /** * An extra of type long describing the ID of the nanoapp an event is for. - * - * @hide */ public static final String EXTRA_NANOAPP_ID = "android.hardware.location.extra.NANOAPP_ID"; /** * An extra of type int describing the nanoapp-specific abort code. - * - * @hide */ public static final String EXTRA_NANOAPP_ABORT_CODE = "android.hardware.location.extra.NANOAPP_ABORT_CODE"; /** * An extra of type {@link NanoAppMessage} describing contents of a message from a nanoapp. - * - * @hide */ public static final String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE"; @@ -109,56 +99,41 @@ public final class ContextHubManager { /** * An event describing that a nanoapp has been loaded. Contains the EXTRA_NANOAPP_ID extra. - * - * @hide */ public static final int EVENT_NANOAPP_LOADED = 0; /** * An event describing that a nanoapp has been unloaded. Contains the EXTRA_NANOAPP_ID extra. - * - * @hide */ public static final int EVENT_NANOAPP_UNLOADED = 1; /** * An event describing that a nanoapp has been enabled. Contains the EXTRA_NANOAPP_ID extra. - * - * @hide */ public static final int EVENT_NANOAPP_ENABLED = 2; /** * An event describing that a nanoapp has been disabled. Contains the EXTRA_NANOAPP_ID extra. - * - * @hide */ public static final int EVENT_NANOAPP_DISABLED = 3; /** * An event describing that a nanoapp has aborted. Contains the EXTRA_NANOAPP_ID and * EXTRA_NANOAPP_ABORT_CODE extras. - * - * @hide */ public static final int EVENT_NANOAPP_ABORTED = 4; /** * An event containing a message sent from a nanoapp. Contains the EXTRA_NANOAPP_ID and * EXTRA_NANOAPP_MESSAGE extras. - * - * @hide */ public static final int EVENT_NANOAPP_MESSAGE = 5; /** * An event describing that the Context Hub has reset. - * - * @hide */ public static final int EVENT_HUB_RESET = 6; - private final Looper mMainLooper; private final IContextHubService mService; private Callback mCallback; @@ -797,14 +772,14 @@ public final class ContextHubManager { * Creates a ContextHubClient that will receive notifications based on Intent events. * * This method should be used instead of {@link #createClient(ContextHubInfo, - * ContextHubClientCallback)} and the equivalent API if the caller wants to preserve the - * messaging endpoint of a ContextHubClient, even after a process exits. If the PendingIntent - * with the provided nanoapp has already been registered at the service previously, then the - * same ContextHubClient will be regenerated without creating a new client connection at the - * service. Note that the PendingIntent, nanoapp, and Context Hub must all match in identifying - * a previously registered ContextHubClient. If a client is regenerated, it can be treated as - * the same endpoint entity from a nanoapp's perspective, and can be continued to be - * used to send messages even if the original process has exited. + * ContextHubClientCallback)} or {@link #createClient(ContextHubInfo, ContextHubClientCallback, + * Executor)} if the caller wants to preserve the messaging endpoint of a ContextHubClient, even + * after a process exits. If the PendingIntent with the provided nanoapp has already been + * registered at the service, then the same ContextHubClient will be regenerated without + * creating a new client connection at the service. Note that the PendingIntent, nanoapp, and + * Context Hub must all match in identifying a previously registered ContextHubClient. + * If a client is regenerated, the host endpoint identifier attached to messages sent to the + * nanoapp remains consistent, even if the original process has exited. * * If registered successfully, intents will be delivered regarding events or messages from the * specified nanoapp from the attached Context Hub. The intent will have an extra @@ -815,10 +790,11 @@ public final class ContextHubManager { * each event type, along with event-specific extra fields. The client can also use * {@link ContextHubIntentEvent.fromIntent(Intent)} to parse the Intent generated by the event. * - * Intent events will be delivered until it is unregistered through - * {@link ContextHubClient.close()}. Note that the registration of this - * ContextHubClient at the Context Hub Service will continued to be maintained until - * {@link ContextHubClient.close()} is called. + * Intent events will be delivered until {@link ContextHubClient.close()} is called. Note that + * the registration of this ContextHubClient at the Context Hub Service will be maintained until + * {@link ContextHubClient.close()} is called. If {@link PendingIntent.cancel()} is called + * on the provided PendingIntent, then the client will be automatically unregistered by the + * service. * * @param hubInfo the hub to attach this client to * @param pendingIntent the PendingIntent to register to the client @@ -828,8 +804,6 @@ public final class ContextHubManager { * @throws IllegalArgumentException if hubInfo does not represent a valid hub * @throws IllegalStateException if there were too many registered clients at the service * @throws NullPointerException if pendingIntent or hubInfo is null - * - * @hide */ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public ContextHubClient createClient( diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java index 1999e78decc4..cb82fbe71f6b 100644 --- a/core/java/android/net/metrics/NetworkEvent.java +++ b/core/java/android/net/metrics/NetworkEvent.java @@ -44,6 +44,8 @@ public final class NetworkEvent implements Parcelable { public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; + public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; + @IntDef(value = { NETWORK_CONNECTED, NETWORK_VALIDATED, @@ -56,6 +58,7 @@ public final class NetworkEvent implements Parcelable { NETWORK_REVALIDATION_SUCCESS, NETWORK_FIRST_VALIDATION_PORTAL_FOUND, NETWORK_REVALIDATION_PORTAL_FOUND, + NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND, }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index c7184c0743ce..1468fe5bfca8 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -400,6 +400,9 @@ public class Binder implements IBinder { * } * </pre> * + * <p>The work source will be propagated for future outgoing binder transactions + * executed on this thread. + * * @param workSource The original UID responsible for the binder call. * @return token to restore original work source. * @hide @@ -423,6 +426,9 @@ public class Binder implements IBinder { /** * Clears the work source on this thread. * + * <p>The work source will be propagated for future outgoing binder transactions + * executed on this thread. + * * @return token to restore original work source. * @hide **/ @@ -442,6 +448,9 @@ public class Binder implements IBinder { * Binder.restoreCallingWorkSource(token); * } * </pre> + * + * <p>The work source will be propagated for future outgoing binder transactions + * executed on this thread. * @hide **/ @CriticalNative diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 720c16723c63..97d72f01dbb3 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -360,6 +360,16 @@ public final class BinderProxy implements IBinder { } /** + * Returns the number of binder proxies held in this process. + * @return number of binder proxies in this process + */ + public static int getProxyCount() { + synchronized (sProxyMap) { + return sProxyMap.size(); + } + } + + /** * Dump proxy debug information. * * @hide diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 8c5c415614f9..900b62d98bf4 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -54,7 +54,7 @@ public class GraphicsEnvironment { private static final String TAG = "GraphicsEnvironment"; private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; private static final String PROPERTY_GFX_DRIVER_WHITELIST = "ro.gfx.driver.whitelist.0"; - private static final String ANGLE_PACKAGE_NAME = "com.android.angle"; + private static final String ANGLE_PACKAGE_NAME = "com.google.android.angle"; private static final String ANGLE_RULES_FILE = "a4a_rules.json"; private static final String ANGLE_TEMP_RULES = "debug.angle.rules"; diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 1c1db68babc3..894015ff5a92 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1008,7 +1008,8 @@ public final class PowerManager { * progress, does nothing. Unlike {@link #nap(long)}, this does not put device to sleep when * dream ends. * </p><p> - * Requires the {@link android.Manifest.permission#WRITE_DREAM_STATE} permission. + * Requires the {@link android.Manifest.permission#READ_DREAM_STATE} and + * {@link android.Manifest.permission#WRITE_DREAM_STATE} permissions. * </p> * * @param time The time when the request to nap was issued, in the @@ -1019,7 +1020,9 @@ public final class PowerManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) + @RequiresPermission(allOf = { + android.Manifest.permission.READ_DREAM_STATE, + android.Manifest.permission.WRITE_DREAM_STATE }) public void dream(long time) { Sandman.startDreamByUserRequest(mContext); } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 423ce771969f..b42f1c4df4e3 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -137,8 +137,6 @@ public class StorageManager { public static final String PROP_FORCE_VIDEO = "persist.fw.force_video"; /** {@hide} */ public static final String PROP_FORCE_IMAGES = "persist.fw.force_images"; - /** {@hide} */ - public static final String PROP_FORCE_LEGACY = "persist.fw.force_legacy"; /** {@hide} */ public static final String UUID_PRIVATE_INTERNAL = null; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d579f0ff3681..4369ea2a6693 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9339,6 +9339,13 @@ public final class Settings { "location_background_throttle_package_whitelist"; /** + * Whether to disable location status callbacks in preparation for deprecation. + * @hide + */ + public static final String LOCATION_DISABLE_STATUS_CALLBACKS = + "location_disable_status_callbacks"; + + /** * Maximum staleness allowed for last location when returned to clients with only foreground * location permissions. * @hide @@ -10773,6 +10780,41 @@ public final class Settings { public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; /** + * The threshold value for the number of consecutive dns timeout events received to be a + * signal of data stall. Set the value to 0 or less than 0 to disable. Note that the value + * should be larger than 0 if the DNS data stall detection is enabled. + * + * @hide + */ + public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = + "data_stall_consecutive_dns_timeout_threshold"; + + /** + * The minimal time interval in milliseconds for data stall reevaluation. + * + * @hide + */ + public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = + "data_stall_min_evaluate_interval"; + + /** + * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting + * a data stall. + * + * @hide + */ + public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = + "data_stall_valid_dns_time_threshold"; + + /** + * Which data stall detection signal to use. Possible values are a union of the powers of 2 + * of DATA_STALL_EVALUATION_TYPE_*. + * + * @hide + */ + public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type"; + + /** * Whether network service discovery is enabled. * * @hide @@ -12701,6 +12743,17 @@ public final class Settings { public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets"; /** + * Used to emulate Smart Suggestion for Augmented Autofill during development + * + * <p>Valid values: {@code 0x1} for IME and/or {@code 0x2} for popup window. + * + * @hide + */ + @TestApi + public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = + "autofill_smart_suggestion_emulation_flags"; + + /** * Exemptions to the hidden API blacklist. * * @hide @@ -13700,6 +13753,15 @@ public final class Settings { */ public static final String LAST_ACTIVE_USER_ID = "last_active_persistent_user_id"; + + /** + * Whether we've enabled native flags health check on this device. Takes effect on + * reboot. The value "1" enables native flags health check; otherwise it's disabled. + * @hide + */ + public static final String NATIVE_FLAGS_HEALTH_CHECK_ENABLED = + "native_flags_health_check_enabled"; + } /** diff --git a/core/java/android/service/intelligence/FillCallback.java b/core/java/android/service/intelligence/FillCallback.java new file mode 100644 index 000000000000..af2da79170ef --- /dev/null +++ b/core/java/android/service/intelligence/FillCallback.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import android.annotation.Nullable; +import android.annotation.SystemApi; + +/** + * Callback used to indicate at {@link FillRequest} has been fulfilled. + * + * @hide + */ +@SystemApi +public final class FillCallback { + + FillCallback() {} + + /** + * Sets the response associated with the request. + * + * @param response response associated with the request, or {@code null} if the service + * could not provide autofill for the request. + */ + public void onSuccess(@Nullable FillResponse response) { + final FillWindow fillWindow = response.getFillWindow(); + if (fillWindow != null) { + fillWindow.show(); + } + // TODO(b/111330312): properly implement on server-side by updating the Session state + // accordingly (and adding CTS tests) + } +} diff --git a/core/java/android/service/intelligence/FillController.java b/core/java/android/service/intelligence/FillController.java new file mode 100644 index 000000000000..c5e1242842bb --- /dev/null +++ b/core/java/android/service/intelligence/FillController.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import static android.service.intelligence.IntelligenceService.DEBUG; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.RemoteException; +import android.service.intelligence.IntelligenceService.AutofillProxy; +import android.util.Log; +import android.util.Pair; +import android.view.autofill.AutofillId; +import android.view.autofill.AutofillValue; + +import com.android.internal.util.Preconditions; + +import java.util.List; + +/** + * Object used to interact with the autofill system. + * + * @hide + */ +@SystemApi +public final class FillController { + private static final String TAG = "FillController"; + + private final AutofillProxy mProxy; + + FillController(@NonNull AutofillProxy proxy) { + mProxy = proxy; + } + + /** + * Fills the activity with the provided values. + * + * <p>As a side effect, the {@link FillWindow} associated with the {@link FillResponse} will be + * automatically {@link FillWindow#destroy() destroyed}. + */ + public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> values) { + Preconditions.checkNotNull(values); + + if (DEBUG) { + Log.d(TAG, "autofill() with " + values.size() + " values"); + } + + try { + mProxy.autofill(values); + final FillWindow fillWindow = mProxy.getFillWindow(); + if (fillWindow != null) { + fillWindow.destroy(); + } + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } +} diff --git a/core/java/android/service/intelligence/FillRequest.java b/core/java/android/service/intelligence/FillRequest.java new file mode 100644 index 000000000000..95e922487906 --- /dev/null +++ b/core/java/android/service/intelligence/FillRequest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.service.intelligence.IntelligenceService.AutofillProxy; +import android.view.autofill.AutofillId; + +/** + * Represents a request to augment-fill an activity. + * @hide + */ +@SystemApi +public final class FillRequest { + + final AutofillProxy mProxy; + + /** @hide */ + FillRequest(@NonNull AutofillProxy proxy) { + mProxy = proxy; + } + + /** + * Gets the session associated with this request. + */ + @NonNull + public InteractionSessionId getSessionId() { + return mProxy.sessionId; + } + + /** + * Gets the id of the field that triggered the request. + */ + @NonNull + public AutofillId getFocusedId() { + return mProxy.focusedId; + } + + /** + * Gets the Smart Suggestions object used to embed the autofill UI. + * + * @return object used to embed the autofill UI, or {@code null} if not supported. + */ + @Nullable + public PresentationParams getPresentationParams() { + return mProxy.getSmartSuggestionParams(); + } + + @Override + public String toString() { + return "FillRequest[id=" + mProxy.focusedId + "]"; + } +} diff --git a/core/java/android/service/intelligence/FillResponse.java b/core/java/android/service/intelligence/FillResponse.java new file mode 100644 index 000000000000..860c0275732a --- /dev/null +++ b/core/java/android/service/intelligence/FillResponse.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.autofill.AutofillId; + +import java.util.List; + +/** + * Response to a {@link FillRequest}. + * + * @hide + */ +@SystemApi +public final class FillResponse implements Parcelable { + + private final FillWindow mFillWindow; + + private FillResponse(@NonNull Builder builder) { + mFillWindow = builder.mFillWindow; + } + + /** @hide */ + @Nullable + FillWindow getFillWindow() { + return mFillWindow; + } + + /** + * Builder for {@link FillResponse} objects. + * + * @hide + */ + @SystemApi + public static class Builder { + + private FillWindow mFillWindow; + + /** + * Sets the {@link FillWindow} used to display the Autofill UI. + * + * <p>Must be called when the service is handling the request so the Android System can + * properly synchronize the UI. + * + * @return this builder + */ + public Builder setFillWindow(@NonNull FillWindow fillWindow) { + // TODO(b/111330312): implement / check not null / unit test + // TODO(b/111330312): throw exception if FillWindow not updated yet + mFillWindow = fillWindow; + return this; + } + + /** + * Tells the Android System that the given {@code ids} should not trigger further + * {@link FillRequest requests} when focused. + * + * @param ids ids of the fields that should be ignored + * + * @return this builder + */ + public Builder setIgnoredIds(@NonNull List<AutofillId> ids) { + // TODO(b/111330312): implement / check not null / unit test + return this; + } + + /** + * Builds a new {@link FillResponse} instance. + * + * @throws IllegalStateException if any of the following conditions occur: + * <ol> + * <li>{@link #build()} was already called. + * <li>No call was made to {@link #setFillWindow(FillWindow)} or + * {@ling #setIgnoredIds(List<AutofillId>)}. + * </ol> + * + * @return A built response. + */ + public FillResponse build() { + // TODO(b/111330312): check conditions / add unit test + return new FillResponse(this); + } + + // TODO(b/111330312): add methods to disable app / activity, either here or on manager + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + // TODO(b/111330312): implement + } + + public static final Parcelable.Creator<FillResponse> CREATOR = + new Parcelable.Creator<FillResponse>() { + + @Override + public FillResponse createFromParcel(Parcel parcel) { + // TODO(b/111330312): implement + return null; + } + + @Override + public FillResponse[] newArray(int size) { + return new FillResponse[size]; + } + }; +} diff --git a/core/java/android/service/intelligence/FillWindow.java b/core/java/android/service/intelligence/FillWindow.java new file mode 100644 index 000000000000..4ea07bfc86cf --- /dev/null +++ b/core/java/android/service/intelligence/FillWindow.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import static android.service.intelligence.IntelligenceService.DEBUG; + +import android.annotation.LongDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.app.Dialog; +import android.graphics.Rect; +import android.service.intelligence.PresentationParams.Area; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.Preconditions; + +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Handle to a window used to display the augmented autofill UI. + * + * <p>The steps to create an augmented autofill UI are: + * + * <ol> + * <li>Gets the {@link PresentationParams} from the {@link FillRequest}. + * <li>Gets the {@link Area} to display the UI (for example, through + * {@link PresentationParams#getSuggestionArea()}. + * <li>Creates a {@link View} that must fit in the {@link Area#getBounds() area boundaries}. + * <li>Set the proper listeners to the view (for example, a click listener that + * triggers {@link FillController#autofill(java.util.List)} + * <li>Call {@link #update(Area, View, long)} with these arguments. + * <li>Create a {@link FillResponse} with the {@link FillWindow}. + * <li>Pass such {@link FillResponse} to {@link FillCallback#onSuccess(FillResponse)}. + * </ol> + * + * @hide + */ +@SystemApi +public final class FillWindow { + private static final String TAG = "FillWindow"; + + /** Indicates the data being shown is a physical address */ + public static final long FLAG_METADATA_ADDRESS = 0x1; + + // TODO(b/111330312): add moar flags + + /** @hide */ + @LongDef(prefix = { "FLAG" }, value = { + FLAG_METADATA_ADDRESS, + }) + @Retention(RetentionPolicy.SOURCE) + @interface Flags{} + + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private Dialog mDialog; + + @GuardedBy("mLock") + private boolean mDestroyed; + + /** + * Updates the content of the window. + * + * @param rootView new root view + * @param area coordinates to render the view. + * @param flags optional flags such as metadata of what will be rendered in the window. The + * Smart Suggestion host might decide whether or not to render the UI based on them. + * + * @return boolean whether the window was updated or not. + * + * @throws IllegalArgumentException if the area is not compatible with this window + */ + public boolean update(@NonNull Area area, @NonNull View rootView, @Flags long flags) { + if (DEBUG) { + Log.d(TAG, "Updating " + area + " + with " + rootView); + } + // TODO(b/111330312): add test case for null + Preconditions.checkNotNull(area); + Preconditions.checkNotNull(rootView); + // TODO(b/111330312): must check the area is a valid object returned by + // SmartSuggestionParams, throw IAE if not + + // TODO(b/111330312): must some how pass metadata to the SmartSuggestiongs provider + + + // TODO(b/111330312): use a SurfaceControl approach; for now, we're manually creating + // the window underneath the existing view. + + final PresentationParams smartSuggestion = area.proxy.getSmartSuggestionParams(); + if (smartSuggestion == null) { + Log.w(TAG, "No SmartSuggestionParams"); + return false; + } + + final Rect rect = area.getBounds(); + if (rect == null) { + Log.wtf(TAG, "No Rect on SmartSuggestionParams"); + return false; + } + + synchronized (mLock) { + checkNotDestroyedLocked(); + + // TODO(b/111330312): once we have the SurfaceControl approach, we should update the + // window instead of destroying. In fact, it might be better to allocate a full window + // initially, which is transparent (and let touches get through) everywhere but in the + // rect boundaries. + destroy(); + + // TODO(b/111330312): make sure all touch events are handled, window is always closed, + // etc. + + mDialog = new Dialog(rootView.getContext()); + final Window window = mDialog.getWindow(); + window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + + final int height = rect.bottom - rect.top; + final int width = rect.right - rect.left; + final WindowManager.LayoutParams windowParams = window.getAttributes(); + windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + windowParams.y = rect.top - height; + windowParams.height = height; + windowParams.x = rect.left; + windowParams.width = width; + + window.setAttributes(windowParams); + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + + mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + final ViewGroup.LayoutParams diagParams = new ViewGroup.LayoutParams(width, height); + mDialog.setContentView(rootView, diagParams); + + if (DEBUG) { + Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView); + } + + area.proxy.setFillWindow(this); + return true; + } + } + + /** @hide */ + void show() { + // TODO(b/111330312): check if updated first / throw exception + if (DEBUG) Log.d(TAG, "show()"); + + synchronized (mLock) { + checkNotDestroyedLocked(); + if (mDialog == null) { + throw new IllegalStateException("update() not called yet, or already destroyed()"); + } + + mDialog.show(); + } + } + + /** + * Destroys the window. + * + * <p>Once destroyed, this window cannot be used anymore + */ + public void destroy() { + if (DEBUG) Log.d(TAG, "destroy(): mDestroyed = " + mDestroyed); + + synchronized (this) { + if (mDestroyed) return; + + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + } + } + + private void checkNotDestroyedLocked() { + if (mDestroyed) { + throw new IllegalStateException("already destroyed()"); + } + } + + /** @hide */ + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + synchronized (this) { + pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed); + if (mDialog != null) { + pw.print(prefix); pw.print("dialog: "); + pw.println(mDialog.isShowing() ? "shown" : "hidden"); + pw.print(prefix); pw.print("window: "); + pw.println(mDialog.getWindow().getAttributes()); + } + } + } +} diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl index 709c3b720579..e2260d7d3d76 100644 --- a/core/java/android/service/intelligence/IIntelligenceService.aidl +++ b/core/java/android/service/intelligence/IIntelligenceService.aidl @@ -16,10 +16,12 @@ package android.service.intelligence; +import android.os.IBinder; import android.service.intelligence.InteractionSessionId; import android.service.intelligence.InteractionContext; import android.service.intelligence.SnapshotData; +import android.view.autofill.AutofillId; import android.view.intelligence.ContentCaptureEvent; import java.util.List; @@ -40,4 +42,9 @@ oneway interface IIntelligenceService { void onActivitySnapshot(in InteractionSessionId sessionId, in SnapshotData snapshotData); + + void onAutofillRequest(in InteractionSessionId sessionId, in IBinder autofillManagerClient, + int autofilSessionId, in AutofillId focusedId); + + void onDestroyAutofillWindowsRequest(in InteractionSessionId sessionId); } diff --git a/core/java/android/service/intelligence/IntelligenceService.java b/core/java/android/service/intelligence/IntelligenceService.java index 27569b6003c5..040e25e977e4 100644 --- a/core/java/android/service/intelligence/IntelligenceService.java +++ b/core/java/android/service/intelligence/IntelligenceService.java @@ -22,13 +22,26 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; +import android.graphics.Rect; +import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.service.intelligence.PresentationParams.SystemPopupPresentationParams; +import android.util.ArrayMap; import android.util.Log; +import android.util.Pair; +import android.view.autofill.AutofillId; +import android.view.autofill.AutofillValue; +import android.view.autofill.IAugmentedAutofillManagerClient; import android.view.intelligence.ContentCaptureEvent; +import com.android.internal.annotations.GuardedBy; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; import java.util.List; /** @@ -44,6 +57,9 @@ public abstract class IntelligenceService extends Service { private static final String TAG = "IntelligenceService"; + // TODO(b/111330312): STOPSHIP use dynamic value, or change to false + static final boolean DEBUG = true; + /** * The {@link Intent} that must be declared as handled by the service. * To be supported, the service must also require the @@ -55,6 +71,8 @@ public abstract class IntelligenceService extends Service { private Handler mHandler; + private ArrayMap<InteractionSessionId, AutofillProxy> mAutofillProxies; + private final IIntelligenceService mInterface = new IIntelligenceService.Stub() { @Override @@ -87,6 +105,20 @@ public abstract class IntelligenceService extends Service { obtainMessage(IntelligenceService::onActivitySnapshot, IntelligenceService.this, sessionId, snapshotData)); } + + @Override + public void onAutofillRequest(InteractionSessionId sessionId, IBinder client, + int autofilSessionId, AutofillId focusedId) { + mHandler.sendMessage(obtainMessage(IntelligenceService::handleOnAutofillRequest, + IntelligenceService.this, sessionId, client, autofilSessionId, focusedId)); + } + + @Override + public void onDestroyAutofillWindowsRequest(InteractionSessionId sessionId) { + mHandler.sendMessage( + obtainMessage(IntelligenceService::handleOnDestroyAutofillWindowsRequest, + IntelligenceService.this, sessionId)); + } }; @CallSuper @@ -122,10 +154,93 @@ public abstract class IntelligenceService extends Service { * @param sessionId the session's Id * @param events the events */ - // TODO(b/111276913): rename to onContentCaptureEvents + // TODO(b/111276913): rename to onContentCaptureEvents or something like that; also, pass a + // Request object so it can be extended public abstract void onContentCaptureEvent(@NonNull InteractionSessionId sessionId, @NonNull List<ContentCaptureEvent> events); + private void handleOnAutofillRequest(@NonNull InteractionSessionId sessionId, + @NonNull IBinder client, int autofillSessionId, @NonNull AutofillId focusedId) { + if (mAutofillProxies == null) { + mAutofillProxies = new ArrayMap<>(); + } + AutofillProxy proxy = mAutofillProxies.get(sessionId); + if (proxy == null) { + proxy = new AutofillProxy(sessionId, client, autofillSessionId, focusedId); + mAutofillProxies.put(sessionId, proxy); + } else { + // TODO(b/111330312): figure out if it's ok to reuse the proxy; add logging + if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId); + } + // TODO(b/111330312): set cancellation signal + final CancellationSignal cancellationSignal = null; + onFillRequest(sessionId, new FillRequest(proxy), cancellationSignal, + new FillController(proxy), new FillCallback()); + } + + /** + * Asks the service to handle an "augmented" autofill request. + * + * <p>This method is called when the "stantard" autofill service cannot handle a request, which + * typically occurs when: + * <ul> + * <li>Service does not recognize what should be autofilled. + * <li>Service does not have data to fill the request. + * <li>Service blacklisted that app (or activity) for autofill. + * <li>App disabled itself for autofill. + * </ul> + * + * <p>Differently from the standard autofill workflow, on augmented autofill the service is + * responsible to generate the autofill UI and request the Android system to autofill the + * activity when the user taps an action in that UI (through the + * {@link FillController#autofill(List)} method). + * + * <p>The service <b>MUST</b> call {@link + * FillCallback#onSuccess(android.service.intelligence.FillResponse)} as soon as possible, + * passing {@code null} when it cannot fulfill the request. + * + * @param sessionId the session's id + * @param request the request to handle. + * @param cancellationSignal signal for observing cancellation requests. The system will use + * this to notify you that the fill result is no longer needed and you should stop + * handling this fill request in order to save resources. + * @param controller object used to interact with the autofill system. + * @param callback object used to notify the result of the request. Service <b>must</b> call + * {@link FillCallback#onSuccess(android.service.intelligence.FillResponse)}. + */ + public void onFillRequest(@NonNull InteractionSessionId sessionId, @NonNull FillRequest request, + @NonNull CancellationSignal cancellationSignal, @NonNull FillController controller, + @NonNull FillCallback callback) { + } + + private void handleOnDestroyAutofillWindowsRequest(@NonNull InteractionSessionId sessionId) { + AutofillProxy proxy = null; + if (mAutofillProxies != null) { + proxy = mAutofillProxies.get(sessionId); + } + if (proxy == null) { + // TODO(b/111330312): this might be fine, in which case we should logv it + Log.w(TAG, "No proxy for session " + sessionId); + return; + } + proxy.destroy(); + mAutofillProxies.remove(sessionId); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mAutofillProxies != null) { + final int size = mAutofillProxies.size(); + pw.print("Number proxies: "); pw.println(size); + for (int i = 0; i < size; i++) { + final InteractionSessionId sessionId = mAutofillProxies.keyAt(i); + final AutofillProxy proxy = mAutofillProxies.valueAt(i); + pw.print(i); pw.print(") SessionId="); pw.print(sessionId); pw.println(":"); + proxy.dump(" ", pw); + } + } + } + /** * Notifies the service of {@link IntelligenceSnapshotData snapshot data} associated with a * session. @@ -142,4 +257,99 @@ public abstract class IntelligenceService extends Service { * @param sessionId the id of the session to destroy */ public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {} + + /** @hide */ + static final class AutofillProxy { + private final Object mLock = new Object(); + private final IAugmentedAutofillManagerClient mClient; + private final int mAutofillSessionId; + public final InteractionSessionId sessionId; + public final AutofillId focusedId; + + @GuardedBy("mLock") + private SystemPopupPresentationParams mSmartSuggestion; + + @GuardedBy("mLock") + private FillWindow mFillWindow; + + private AutofillProxy(@NonNull InteractionSessionId sessionId, @NonNull IBinder client, + int autofillSessionId, @NonNull AutofillId focusedId) { + this.sessionId = sessionId; + mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client); + mAutofillSessionId = autofillSessionId; + this.focusedId = focusedId; + // TODO(b/111330312): linkToDeath + } + + @NonNull + public SystemPopupPresentationParams getSmartSuggestionParams() { + synchronized (mLock) { + if (mSmartSuggestion != null) { + return mSmartSuggestion; + } + Rect rect; + try { + rect = mClient.getViewCoordinates(focusedId); + } catch (RemoteException e) { + Log.w(TAG, "Could not get coordinates for " + focusedId); + return null; + } + if (rect == null) { + if (DEBUG) Log.d(TAG, "getViewCoordinates(" + focusedId + ") returned null"); + return null; + } + mSmartSuggestion = new SystemPopupPresentationParams(this, rect); + return mSmartSuggestion; + } + } + + public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> pairs) + throws RemoteException { + final int size = pairs.size(); + final List<AutofillId> ids = new ArrayList<>(size); + final List<AutofillValue> values = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + final Pair<AutofillId, AutofillValue> pair = pairs.get(i); + ids.add(pair.first); + values.add(pair.second); + } + mClient.autofill(mAutofillSessionId, ids, values); + } + + public void setFillWindow(@NonNull FillWindow fillWindow) { + synchronized (mLock) { + mFillWindow = fillWindow; + } + } + + public FillWindow getFillWindow() { + synchronized (mLock) { + return mFillWindow; + } + } + + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); pw.print("afSessionId: "); pw.println(mAutofillSessionId); + pw.print(prefix); pw.print("focusedId: "); pw.println(focusedId); + pw.print(prefix); pw.print("client: "); pw.println(mClient); + final String prefix2 = prefix + " "; + if (mFillWindow != null) { + pw.print(prefix); pw.println("window:"); + mFillWindow.dump(prefix2, pw); + } + if (mSmartSuggestion != null) { + pw.print(prefix); pw.println("smartSuggestion:"); + mSmartSuggestion.dump(prefix2, pw); + } + } + + private void destroy() { + synchronized (mLock) { + if (mFillWindow != null) { + if (DEBUG) Log.d(TAG, "destroying window"); + mFillWindow.destroy(); + } + } + } + } } diff --git a/core/java/android/service/intelligence/PresentationParams.java b/core/java/android/service/intelligence/PresentationParams.java new file mode 100644 index 000000000000..c59069bbb674 --- /dev/null +++ b/core/java/android/service/intelligence/PresentationParams.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.graphics.Rect; +import android.service.intelligence.IntelligenceService.AutofillProxy; +import android.util.DebugUtils; +import android.view.View; + +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Abstraction of a "Smart Suggestion" component responsible to embed the autofill UI provided by + * the intelligence service. + * + * <p>The Smart Suggestion can embed the autofill UI in 3 distinct places: + * + * <ul> + * <li>A small area associated with suggestions (like a small strip in the top of the IME), + * returned by {@link #getSuggestionArea()} + * <li>The full area (like the full IME window), returned by {@link #getFullArea()} + * <li>A subset of the aforementioned areas, returned by {@link Area#getSubArea(Rect)} + * </ul> + * + * <p>The Smart Suggestion is represented by a {@link Area} object that contains the + * dimensions the smart suggestion window, so the service can use it to calculate the size of the + * view that will be passed to {@link FillWindow#update(Area, View, long)}. + * + * @hide + */ +@SystemApi +public abstract class PresentationParams { + + /** + * Flag indicating the Smart Suggestion is hosted in the top of its container. + */ + public static final int FLAG_HINT_GRAVITY_TOP = 0x1; + + /** + * Flag indicating the Smart Suggestion is hosted in the bottom of its container. + */ + public static final int FLAG_HINT_GRAVITY_BOTTOM = 0x2; + + /** + * Flag indicating the Smart Suggestion is hosted in the left of its container. + */ + public static final int FLAG_HINT_GRAVITY_LEFT = 0x4; + + /** + * Flag indicating the Smart Suggestion is hosted in the right of its container. + */ + public static final int FLAG_HINT_GRAVITY_RIGHT = 0x8; + + /** + * Flag indicating the Smart Suggestion is hosted by the IME. + */ + public static final int FLAG_HOST_IME = 0x10; + + /** + * Flag indicating the Smart Suggestion is hosted by the Android System as a floating popup + * window. + */ + public static final int FLAG_HOST_SYSTEM = 0x20; + + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + FLAG_HINT_GRAVITY_TOP, + FLAG_HINT_GRAVITY_BOTTOM, + FLAG_HINT_GRAVITY_LEFT, + FLAG_HINT_GRAVITY_RIGHT, + FLAG_HOST_IME, + FLAG_HOST_SYSTEM + }) + @Retention(RetentionPolicy.SOURCE) + @interface Flags {} + + + // /** @hide */ + PresentationParams() {} + + /** + * Gets the area of the suggestion strip for the given {@code metadata} + * + * @return strip dimensions, or {@code null} if the Smart Suggestion provider does not support + * suggestions strip. + */ + @Nullable + public Area getSuggestionArea() { + return null; + } + + /** + * Gets the full area for the of the Smart Suggestion provider. + * + * @return full dimensions, or {@code null} if the Smart Suggestion provider does not support + * embeding the UI on its full area. + */ + @Nullable + public Area getFullArea() { + return null; + } + + /** + * Gets flags associated with the Smart Suggestion. + * + * @return any combination of {@link #FLAG_HINT_GRAVITY_TOP}, + * {@link #FLAG_HINT_GRAVITY_BOTTOM}, {@link #FLAG_HINT_GRAVITY_LEFT}, + * {@link #FLAG_HINT_GRAVITY_RIGHT}, {@link #FLAG_HOST_IME}, or + * {@link #FLAG_HOST_SYSTEM}, + */ + public @Flags int getFlags() { + return 0; + } + + /** @hide */ + void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + final int flags = getFlags(); + if (flags > 0) { + pw.print(prefix); pw.print("flags: "); pw.println(flagsToString(flags)); + } + } + + private static String flagsToString(int flags) { + return DebugUtils.flagsToString(PresentationParams.class, "FLAG_", flags); + } + + /** + * Area associated with a {@link PresentationParams Smart Suggestions} provider. + * + * @hide + * */ + @SystemApi + public abstract static class Area { + + /** @hide */ + public final AutofillProxy proxy; + + private final Rect mBounds; + + private Area(@NonNull AutofillProxy proxy, @NonNull Rect bounds) { + this.proxy = proxy; + mBounds = bounds; + } + + /** + * Gets the area boundaries. + */ + @NonNull + public Rect getBounds() { + return mBounds; + } + + /** + * Gets a subarea limited by given boundaries. + * + * @param bounds boundaries relative to this Area. + * + * @throws {@link IllegalArgumentException} if the {@code bounds} is not fully-contained + * inside this full Area. + * + * @return new subarea, or {@code null} if the Smart Suggestion host does not support such + * subaarea. + */ + @Nullable + public Area getSubArea(@NonNull Rect bounds) { + // TODO(b/111330312): implement / check boundaries / throw IAE / add unit test + return null; + } + + @Override + public String toString() { + return mBounds.toString(); + } + } + + /** + * System-provided poup window anchored to a view. + * + * <p>Used just for debugging purposes. + * + * @hide + */ + public static final class SystemPopupPresentationParams extends PresentationParams { + private final Area mSuggestionArea; + + public SystemPopupPresentationParams(@NonNull AutofillProxy proxy, @NonNull Rect rect) { + mSuggestionArea = new Area(proxy, rect) {}; + } + + @Override + public Area getSuggestionArea() { + return mSuggestionArea; + } + + @Override + public int getFlags() { + return FLAG_HOST_SYSTEM | FLAG_HINT_GRAVITY_BOTTOM; + } + + @Override + void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + super.dump(prefix, pw); + pw.print(prefix); pw.print("area: "); pw.println(mSuggestionArea); + } + } +} diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index d8bd00281ba5..ab94f432968c 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -47,4 +47,7 @@ oneway interface INotificationListener void onNotificationEnqueuedWithChannel(in IStatusBarNotificationHolder notificationHolder, in NotificationChannel channel); void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId); void onNotificationsSeen(in List<String> keys); + void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded); + void onNotificationDirectReply(String key); + void onSuggestedReplySent(String key, in CharSequence reply, int source); } diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index c1a3c2b5f150..68da83f9e7d8 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -16,6 +16,9 @@ package android.service.notification; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -33,6 +36,7 @@ import android.util.Log; import com.android.internal.os.SomeArgs; +import java.lang.annotation.Retention; import java.util.List; /** @@ -63,6 +67,13 @@ import java.util.List; public abstract class NotificationAssistantService extends NotificationListenerService { private static final String TAG = "NotificationAssistants"; + /** @hide */ + @Retention(SOURCE) + @IntDef({SOURCE_FROM_APP, SOURCE_FROM_ASSISTANT}) + public @interface Source {} + public static final int SOURCE_FROM_APP = 0; + public static final int SOURCE_FROM_ASSISTANT = 1; + /** * The {@link Intent} that must be declared as handled by the service. */ @@ -160,6 +171,29 @@ public abstract class NotificationAssistantService extends NotificationListenerS } /** + * Implement this to know when a notification is expanded / collapsed. + * @param key the notification key + * @param isUserAction whether the expanded change is caused by user action. + * @param isExpanded whether the notification is expanded. + */ + public void onNotificationExpansionChanged( + String key, boolean isUserAction, boolean isExpanded) {} + + /** + * Implement this to know when a direct reply is sent from a notification. + * @param key the notification key + */ + public void onNotificationDirectReply(String key) {} + + /** + * Implement this to know when a suggested reply is sent. + * @param key the notification key + * @param reply the reply that is just sent + * @param source the source of the reply, e.g. SOURCE_FROM_APP + */ + public void onSuggestedReplySent(String key, CharSequence reply, @Source int source) {} + + /** * Updates a notification. N.B. this won’t cause * an existing notification to alert, but might allow a future update to * this notification to alert. @@ -255,12 +289,43 @@ public abstract class NotificationAssistantService extends NotificationListenerS mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATIONS_SEEN, args).sendToTarget(); } + + @Override + public void onNotificationExpansionChanged(String key, boolean isUserAction, + boolean isExpanded) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = key; + args.argi1 = isUserAction ? 1 : 0; + args.argi2 = isExpanded ? 1 : 0; + mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_EXPANSION_CHANGED, args) + .sendToTarget(); + } + + @Override + public void onNotificationDirectReply(String key) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = key; + mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT, args) + .sendToTarget(); + } + + @Override + public void onSuggestedReplySent(String key, CharSequence reply, int source) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = key; + args.arg2 = reply; + args.argi2 = source; + mHandler.obtainMessage(MyHandler.MSG_ON_SUGGESTED_REPLY_SENT, args).sendToTarget(); + } } private final class MyHandler extends Handler { public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1; public static final int MSG_ON_NOTIFICATION_SNOOZED = 2; public static final int MSG_ON_NOTIFICATIONS_SEEN = 3; + public static final int MSG_ON_NOTIFICATION_EXPANSION_CHANGED = 4; + public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5; + public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6; public MyHandler(Looper looper) { super(looper, null, false); @@ -305,6 +370,31 @@ public abstract class NotificationAssistantService extends NotificationListenerS onNotificationsSeen(keys); break; } + case MSG_ON_NOTIFICATION_EXPANSION_CHANGED: { + SomeArgs args = (SomeArgs) msg.obj; + String key = (String) args.arg1; + boolean isUserAction = args.argi1 == 1; + boolean isExpanded = args.argi2 == 1; + args.recycle(); + onNotificationExpansionChanged(key, isUserAction, isExpanded); + break; + } + case MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT: { + SomeArgs args = (SomeArgs) msg.obj; + String key = (String) args.arg1; + args.recycle(); + onNotificationDirectReply(key); + break; + } + case MSG_ON_SUGGESTED_REPLY_SENT: { + SomeArgs args = (SomeArgs) msg.obj; + String key = (String) args.arg1; + CharSequence reply = (CharSequence) args.arg2; + int source = args.argi2; + args.recycle(); + onSuggestedReplySent(key, reply, source); + break; + } } } } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 64eae0cf4635..756a7c6a54b0 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -1366,6 +1366,22 @@ public abstract class NotificationListenerService extends Service { } @Override + public void onNotificationExpansionChanged( + String key, boolean isUserAction, boolean isExpanded) { + // no-op in the listener + } + + @Override + public void onNotificationDirectReply(String key) { + // no-op in the listener + } + + @Override + public void onSuggestedReplySent(String key, CharSequence reply, int source) { + // no-op in the listener + } + + @Override public void onNotificationChannelModification(String pkgName, UserHandle user, NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { diff --git a/core/java/android/service/sms/FinancialSmsService.java b/core/java/android/service/sms/FinancialSmsService.java new file mode 100644 index 000000000000..5fb7249b6ecb --- /dev/null +++ b/core/java/android/service/sms/FinancialSmsService.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.sms; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.database.CursorWindow; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteCallback; +import android.os.RemoteException; + +/** + * A service to support sms messages read for financial apps. + * + * {@hide} + */ +@SystemApi +public abstract class FinancialSmsService extends Service { + + private static final String TAG = "FinancialSmsService"; + + /** + * The {@link Intent} action that must be declared as handled by a service + * in its manifest for the system to recognize it as a quota providing + * service. + */ + public static final String ACTION_FINANCIAL_SERVICE_INTENT = + "android.service.sms.action.FINANCIAL_SERVICE_INTENT"; + + /** {@hide} **/ + public static final String EXTRA_SMS_MSGS = "sms_messages"; + + private FinancialSmsServiceWrapper mWrapper; + + private void getSmsMessages(RemoteCallback callback, Bundle params) { + final Bundle data = new Bundle(); + CursorWindow smsMessages = onGetSmsMessages(params); + if (smsMessages != null) { + data.putParcelable(EXTRA_SMS_MSGS, smsMessages); + } + callback.sendResult(data); + } + + private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); + + /** @hide */ + public FinancialSmsService() { + } + + @Override + public void onCreate() { + super.onCreate(); + mWrapper = new FinancialSmsServiceWrapper(); + } + + @Override + public IBinder onBind(Intent intent) { + return mWrapper; + } + + /** + * Get sms messages for financial apps. + * + * @param params parameters passed in by the calling app. + * @return the {@code CursorWindow} with all sms messages for the app to read. + * + * {@hide} + */ + @Nullable + @SystemApi + public abstract CursorWindow onGetSmsMessages(@NonNull Bundle params); + + private final class FinancialSmsServiceWrapper extends IFinancialSmsService.Stub { + @Override + public void getSmsMessages(RemoteCallback callback, Bundle params) throws RemoteException { + mHandler.sendMessage(obtainMessage( + FinancialSmsService::getSmsMessages, + FinancialSmsService.this, + callback, params)); + } + } + +} diff --git a/core/java/android/service/sms/IFinancialSmsService.aidl b/core/java/android/service/sms/IFinancialSmsService.aidl new file mode 100644 index 000000000000..caabe5851948 --- /dev/null +++ b/core/java/android/service/sms/IFinancialSmsService.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.sms; + +import android.os.Bundle; +import android.os.RemoteCallback; + +/** + * Service used by financial apps to read sms messages. + * + * @hide + */ +oneway interface IFinancialSmsService +{ + void getSmsMessages(in RemoteCallback callback, in Bundle params); +}
\ No newline at end of file diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 6f51becfbf03..f6bb762a0bef 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -129,7 +129,7 @@ public abstract class WallpaperService extends Service { Bundle extras; boolean sync; } - + /** * The actual implementation of a wallpaper. A wallpaper service may * have multiple instances running (for example as a real wallpaper @@ -144,7 +144,7 @@ public abstract class WallpaperService extends Service { HandlerCaller mCaller; IWallpaperConnection mConnection; IBinder mWindowToken; - + boolean mInitializing = true; boolean mVisible; boolean mReportedVisible; @@ -208,7 +208,6 @@ public abstract class WallpaperService extends Service { private final Supplier<Long> mClockFunction; private final Handler mHandler; - DisplayManager mDisplayManager; Display mDisplay; private int mDisplayState; @@ -419,7 +418,7 @@ public abstract class WallpaperService extends Service { public int getDesiredMinimumHeight() { return mIWallpaperEngine.mReqHeight; } - + /** * Return whether the wallpaper is currently visible to the user, * this is the last value supplied to @@ -1015,14 +1014,6 @@ public abstract class WallpaperService extends Service { return; } - mDisplayManager = getSystemService(DisplayManager.class); - mDisplay = mDisplayManager.getDisplay(wrapper.mDisplayId); - if (mDisplay == null) { - // TODO(b/115486823) Ignore this engine. - Log.e(TAG, "Attaching to a non-existent display: " + wrapper.mDisplayId); - return; - } - mIWallpaperEngine = wrapper; mCaller = wrapper.mCaller; mConnection = wrapper.mConnection; @@ -1034,13 +1025,16 @@ public abstract class WallpaperService extends Service { mWindow.setSession(mSession); mLayout.packageName = getPackageName(); - mDisplayManager.registerDisplayListener(mDisplayListener, mCaller.getHandler()); + mIWallpaperEngine.mDisplayManager.registerDisplayListener(mDisplayListener, + mCaller.getHandler()); + mDisplay = mIWallpaperEngine.mDisplay; mDisplayState = mDisplay.getState(); if (DEBUG) Log.v(TAG, "onCreate(): " + this); onCreate(mSurfaceHolder); - + mInitializing = false; + mReportedVisible = false; updateSurface(false, false, false); } @@ -1202,8 +1196,8 @@ public abstract class WallpaperService extends Service { mDestroyed = true; - if (mDisplayManager != null) { - mDisplayManager.unregisterDisplayListener(mDisplayListener); + if (mIWallpaperEngine.mDisplayManager != null) { + mIWallpaperEngine.mDisplayManager.unregisterDisplayListener(mDisplayListener); } if (mVisible) { @@ -1272,7 +1266,9 @@ public abstract class WallpaperService extends Service { int mReqWidth; int mReqHeight; final Rect mDisplayPadding = new Rect(); - int mDisplayId; + final int mDisplayId; + final DisplayManager mDisplayManager; + final Display mDisplay; Engine mEngine; @@ -1289,7 +1285,15 @@ public abstract class WallpaperService extends Service { mReqHeight = reqHeight; mDisplayPadding.set(padding); mDisplayId = displayId; - + + // Create a display context before onCreateEngine. + mDisplayManager = getSystemService(DisplayManager.class); + mDisplay = mDisplayManager.getDisplay(mDisplayId); + + if (mDisplay == null) { + // Ignore this engine. + throw new IllegalArgumentException("Cannot find display with id" + mDisplayId); + } Message msg = mCaller.obtainMessage(DO_ATTACH); mCaller.sendMessage(msg); } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 2cf0262a1d28..8cb18b255589 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -485,7 +485,7 @@ public class StaticLayout extends Layout { * @deprecated Use {@link Builder} instead. */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117521430) public StaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint, int outerwidth, Alignment align, TextDirectionHeuristic textDir, diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index b970c256e467..85b6b889be33 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -46,6 +46,7 @@ import android.text.style.EasyEditSpan; import android.text.style.ForegroundColorSpan; import android.text.style.LeadingMarginSpan; import android.text.style.LineBackgroundSpan; +import android.text.style.LineHeightSpan; import android.text.style.LocaleSpan; import android.text.style.ParagraphStyle; import android.text.style.QuoteSpan; @@ -733,7 +734,9 @@ public class TextUtils { /** @hide */ public static final int LINE_BACKGROUND_SPAN = 27; /** @hide */ - public static final int LAST_SPAN = LINE_BACKGROUND_SPAN; + public static final int LINE_HEIGHT_SPAN = 28; + /** @hide */ + public static final int LAST_SPAN = LINE_HEIGHT_SPAN; /** * Flatten a CharSequence and whatever styles can be copied across processes @@ -928,6 +931,10 @@ public class TextUtils { readSpan(p, sp, new LineBackgroundSpan.Standard(p)); break; + case LINE_HEIGHT_SPAN: + readSpan(p, sp, new LineHeightSpan.Standard(p)); + break; + default: throw new RuntimeException("bogus span encoding " + kind); } diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 562ae7ada90a..bab4bc362c0d 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -18,8 +18,8 @@ package android.text.format; import android.util.TimeFormatException; +import libcore.timezone.ZoneInfoDB; import libcore.util.ZoneInfo; -import libcore.util.ZoneInfoDB; import java.io.IOException; import java.util.Locale; diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java index 2742ae0416a2..a5d5af2433fe 100644 --- a/core/java/android/text/style/LineHeightSpan.java +++ b/core/java/android/text/style/LineHeightSpan.java @@ -20,7 +20,10 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Px; import android.graphics.Paint; +import android.os.Parcel; +import android.text.ParcelableSpan; import android.text.TextPaint; +import android.text.TextUtils; import com.android.internal.util.Preconditions; @@ -71,7 +74,7 @@ public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan { * covers only part of the paragraph. * </p> */ - class Standard implements LineHeightSpan { + class Standard implements LineHeightSpan, ParcelableSpan { private final @Px int mHeight; /** @@ -82,6 +85,48 @@ public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan { mHeight = height; } + /** + * Constructor called from {@link TextUtils} to restore the span from a parcel + */ + public Standard(Parcel src) { + mHeight = src.readInt(); + } + + /** + * Returns the line height specified by this span. + */ + @Px + public int getHeight() { + return mHeight; + } + + @Override + public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + @Override + public int getSpanTypeIdInternal() { + return TextUtils.LINE_HEIGHT_SPAN; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + @Override + public void writeToParcelInternal(@NonNull Parcel dest, int flags) { + dest.writeInt(mHeight); + } + @Override public void chooseHeight(@NonNull CharSequence text, int start, int end, int spanstartv, int lineHeight, diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index f4dad625fbc6..eef7ea232d43 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -29,6 +29,7 @@ import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.text.style.URLSpan; +import android.util.Log; import android.util.Patterns; import android.webkit.WebView; import android.widget.TextView; @@ -72,6 +73,9 @@ import java.util.regex.Pattern; */ public class Linkify { + + private static final String LOG_TAG = "Linkify"; + /** * Bit field indicating that web URLs should be matched in methods that * take an options mask @@ -310,6 +314,11 @@ public class Linkify { */ private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask, @Nullable Context context, @Nullable UrlSpanFactory urlSpanFactory) { + if (text != null && containsUnsupportedCharacters(text.toString())) { + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + return false; + } + if (mask == 0) { return false; } @@ -356,6 +365,29 @@ public class Linkify { } /** + * Returns true if the specified text contains at least one unsupported character for applying + * links. Also logs the error. + * + * @param text the text to apply links to + * @hide + */ + public static boolean containsUnsupportedCharacters(String text) { + if (text.contains("\u202C")) { + Log.e(LOG_TAG, "Unsupported character for applying links: u202C"); + return true; + } + if (text.contains("\u202D")) { + Log.e(LOG_TAG, "Unsupported character for applying links: u202D"); + return true; + } + if (text.contains("\u202E")) { + Log.e(LOG_TAG, "Unsupported character for applying links: u202E"); + return true; + } + return false; + } + + /** * Scans the text of the provided TextView and turns all occurrences of * the link types indicated in the mask into clickable links. If matches * are found the movement method for the TextView is set to @@ -560,6 +592,11 @@ public class Linkify { @Nullable String defaultScheme, @Nullable String[] schemes, @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter, @Nullable UrlSpanFactory urlSpanFactory) { + if (spannable != null && containsUnsupportedCharacters(spannable.toString())) { + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + return false; + } + final String[] schemesCopy; if (defaultScheme == null) defaultScheme = ""; if (schemes == null || schemes.length < 1) { diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 21c4252a0a7e..57d55bf31375 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -24,7 +24,7 @@ import android.os.SystemClock; import libcore.timezone.CountryTimeZones; import libcore.timezone.CountryTimeZones.TimeZoneMapping; import libcore.timezone.TimeZoneFinder; -import libcore.util.ZoneInfoDB; +import libcore.timezone.ZoneInfoDB; import java.io.PrintWriter; import java.text.SimpleDateFormat; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 308a00020db9..dace388b66f6 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -96,8 +96,9 @@ interface IWindowManager */ void overridePendingAppTransitionMultiThumbFuture( IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback startedCallback, - boolean scaleUp); - void overridePendingAppTransitionRemote(in RemoteAnimationAdapter remoteAnimationAdapter); + boolean scaleUp, int displayId); + void overridePendingAppTransitionRemote(in RemoteAnimationAdapter remoteAnimationAdapter, + int displayId); void executeAppTransition(); /** @@ -294,9 +295,11 @@ interface IWindowManager void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled); /** - * Device has a software navigation bar (separate from the status bar). + * Device has a software navigation bar (separate from the status bar) on specific display. + * + * @param displayId the id of display to check if there is a software navigation bar. */ - boolean hasNavigationBar(); + boolean hasNavigationBar(int displayId); /** * Get the position of the nav bar diff --git a/core/java/android/view/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java index dc1e505ef36d..5f6bc2352131 100644 --- a/core/java/android/view/InputApplicationHandle.java +++ b/core/java/android/view/InputApplicationHandle.java @@ -16,6 +16,8 @@ package android.view; +import android.os.IBinder; + /** * Functions as a handle for an application that can receive input. * Enables the native input dispatcher to refer indirectly to the window manager's @@ -28,19 +30,18 @@ public final class InputApplicationHandle { @SuppressWarnings("unused") private long ptr; - // The window manager's application window token. - public final Object appWindowToken; - // Application name. public String name; // Dispatching timeout. public long dispatchingTimeoutNanos; + public IBinder token; + private native void nativeDispose(); - public InputApplicationHandle(Object appWindowToken) { - this.appWindowToken = appWindowToken; + public InputApplicationHandle(IBinder token) { + this.token = token; } @Override diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 621ee89fac45..92e0009bc21a 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -17,6 +17,7 @@ package android.view; import android.graphics.Region; +import android.os.IBinder; import android.view.IWindow; import android.view.InputChannel; @@ -37,8 +38,8 @@ public final class InputWindowHandle { // The client window. public final IWindow clientWindow; - // The input channel associated with the window. - public InputChannel inputChannel; + // The token assosciated with the window. + public IBinder token; // The window name. public String name; @@ -56,6 +57,8 @@ public final class InputWindowHandle { public int frameRight; public int frameBottom; + public int surfaceInset; + // Global scaling factor applied to touch events when they are dispatched // to the window public float scaleFactor; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e0232a74038f..0eaef5aa3c53 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3373,9 +3373,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * |-------|-------|-------|-------| * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK - * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT - * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED - * 1 PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE + * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED + * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED * |-------|-------|-------|-------| */ @@ -3396,28 +3395,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods * should be called. * - * The idea is to call notifyNodeAdded() after the view is layout and visible, then call - * notifyNodeRemoved() when it's gone (without known when it was removed from the parent). - * - * TODO(b/111276913): the current algortighm could probably be optimized and some of them - * removed + * The idea is to call notifyAppeared() after the view is layout and visible, then call + * notifyDisappeared() when it's gone (without known when it was removed from the parent). */ - private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT = 0x10; - private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED = 0x20; - private static final int PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE = 0x40; + private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; + private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; /* End of masks for mPrivateFlags4 */ - private static final int CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED = 1; - private static final int CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED = 0; - - @IntDef(flag = true, prefix = { "CONTENT_CAPTURE_NOTIFICATION_TYPE_" }, value = { - CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED, - CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED - }) - @Retention(RetentionPolicy.SOURCE) - private @interface ContentCaptureNotificationType {} - /** @hide */ protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; /** @hide */ @@ -8933,63 +8918,61 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Helper used to notify the {@link IntelligenceManager} when the view is removed or * added, based on whether it's laid out and visible, and without knowing if the parent removed * it from the view hierarchy. + * + * <p>This method is called from many places (visibility changed, view laid out, view attached + * or detached to/from window, etc...) and hence must contain the logic to call the manager, as + * described below: + * + * <ol> + * <li>It should only be called when content capture is enabled for the view. + * <li>It must call viewAppeared() before viewDisappeared() + * <li>viewAppearead() can only be called when the view is visible and laidout + * <li>It should not call the same event twice. + * </ol> */ - // TODO(b/111276913): make sure the current algorithm covers all cases. For example, it should - // probably be called every time notifyEnterOrExitForAutoFillIfNeeded() is called as well. - private void notifyNodeAddedOrRemovedForContentCaptureIfNeeded( - @ContentCaptureNotificationType int type) { - if (type != CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED - && type != CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED) { - // Sanity check so it does not screw up the flags - Log.wtf(CONTENT_CAPTURE_LOG_TAG, "notifyNodeAddedOrRemovedForContentCaptureIfNeeded(): " - + "invalid type " + type + " for " + this); - return; - } - - if (!isImportantForContentCapture()) return; + private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { final IntelligenceManager im = mContext.getSystemService(IntelligenceManager.class); if (im == null || !im.isContentCaptureEnabled()) return; - // Make sure event is notified just once, and reset the - // PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE flag - boolean ignoreNotification = false; - if (type == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { - if ((mPrivateFlags4 & PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE) - == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { - ignoreNotification = true; - } else { - mPrivateFlags4 |= PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE; - } - } else { - if ((mPrivateFlags4 & PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE) - == CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED) { - ignoreNotification = true; - } else { - mPrivateFlags4 &= ~PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE; - } - } - if (ignoreNotification) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { - // TODO(b/111276913): remove this log statement if the algorithm is not improved - // (right now it's called too many times when the activity is stopped and/or views - // disappear - Log.v(CONTENT_CAPTURE_LOG_TAG, "notifyNodeAddedOrRemovedForContentCaptureIfNeeded(" - + type + "): ignoring repeated notification on " + this); - } - return; - } + // NOTE: isImportantForContentCapture() is more expensive than im.isContentCaptureEnabled() + if (!isImportantForContentCapture()) return; - if (type == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { + if (appeared) { + if (!isLaidOut() || !isVisibleToUser() + || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { + if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { + Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" + + isLaidOut() + ", visible=" + isVisibleToUser() + + ": alreadyNotifiedAppeared=" + + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)); + } + return; + } + // All good: notify the manager... final ViewStructure structure = im.newViewStructure(this); onProvideContentCaptureStructure(structure, /* flags= */ 0); im.notifyViewAppeared(structure); - mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED; + // ...and set the flags + mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; + mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; } else { - if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED) == 0) { - return; // skip initial notification + if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 + || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { + if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { + Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + + ": notifiedAppeared=" + + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) + + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 + & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); + } + return; } + // All good: notify the manager... im.notifyViewDisappeared(getAutofillId()); + // ...and set the flags + mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; + mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; } } @@ -12896,6 +12879,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void dispatchStartTemporaryDetach() { mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; notifyEnterOrExitForAutoFillIfNeeded(false); + notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); onStartTemporaryDetach(); } @@ -12922,6 +12906,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyFocusChangeToInputMethodManager(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); + notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } /** @@ -13503,9 +13488,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } } - notifyNodeAddedOrRemovedForContentCaptureIfNeeded(isVisible - ? CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED - : CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED); + + notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); } /** @@ -19076,6 +19060,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, needGlobalAttributesUpdate(false); notifyEnterOrExitForAutoFillIfNeeded(true); + notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } @UnsupportedAppUsage @@ -19125,8 +19110,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyEnterOrExitForAutoFillIfNeeded(false); - notifyNodeAddedOrRemovedForContentCaptureIfNeeded( - CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED); + notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** @@ -21432,12 +21416,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyEnterOrExitForAutoFillIfNeeded(true); } - if ((mViewFlags & VISIBILITY_MASK) == VISIBLE - && (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT) == 0) { - notifyNodeAddedOrRemovedForContentCaptureIfNeeded( - CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED); - mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT; - } + notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } private boolean hasParentWantsFocus() { @@ -23151,26 +23130,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Modifies the input matrix such that it maps view-local coordinates to * on-screen coordinates. * - * @param m input matrix to modify - * @hide + * @param matrix input matrix to modify */ - @UnsupportedAppUsage - public void transformMatrixToGlobal(Matrix m) { + public void transformMatrixToGlobal(Matrix matrix) { final ViewParent parent = mParent; if (parent instanceof View) { final View vp = (View) parent; - vp.transformMatrixToGlobal(m); - m.preTranslate(-vp.mScrollX, -vp.mScrollY); + vp.transformMatrixToGlobal(matrix); + matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); } else if (parent instanceof ViewRootImpl) { final ViewRootImpl vr = (ViewRootImpl) parent; - vr.transformMatrixToGlobal(m); - m.preTranslate(0, -vr.mCurScrollY); + vr.transformMatrixToGlobal(matrix); + matrix.preTranslate(0, -vr.mCurScrollY); } - m.preTranslate(mLeft, mTop); + matrix.preTranslate(mLeft, mTop); if (!hasIdentityMatrix()) { - m.preConcat(getMatrix()); + matrix.preConcat(getMatrix()); } } @@ -23178,26 +23155,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Modifies the input matrix such that it maps on-screen coordinates to * view-local coordinates. * - * @param m input matrix to modify - * @hide + * @param matrix input matrix to modify */ - @UnsupportedAppUsage - public void transformMatrixToLocal(Matrix m) { + public void transformMatrixToLocal(Matrix matrix) { final ViewParent parent = mParent; if (parent instanceof View) { final View vp = (View) parent; - vp.transformMatrixToLocal(m); - m.postTranslate(vp.mScrollX, vp.mScrollY); + vp.transformMatrixToLocal(matrix); + matrix.postTranslate(vp.mScrollX, vp.mScrollY); } else if (parent instanceof ViewRootImpl) { final ViewRootImpl vr = (ViewRootImpl) parent; - vr.transformMatrixToLocal(m); - m.postTranslate(0, vr.mCurScrollY); + vr.transformMatrixToLocal(matrix); + matrix.postTranslate(0, vr.mCurScrollY); } - m.postTranslate(-mLeft, -mTop); + matrix.postTranslate(-mLeft, -mTop); if (!hasIdentityMatrix()) { - m.postConcat(getInverseMatrix()); + matrix.postConcat(getInverseMatrix()); } } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 767cd33c2625..d03d97e1b219 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -393,7 +393,7 @@ public class ViewConfiguration { case HAS_PERMANENT_MENU_KEY_AUTODETECT: { IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); try { - sHasPermanentMenuKey = !wm.hasNavigationBar(); + sHasPermanentMenuKey = !wm.hasNavigationBar(context.getDisplayId()); sHasPermanentMenuKeySet = true; } catch (RemoteException ex) { sHasPermanentMenuKey = false; diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index d4c7069cdbf4..9227249fc6b1 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -202,6 +202,14 @@ public final class AutofillManager { public static final String EXTRA_RESTORE_SESSION_TOKEN = "android.view.autofill.extra.RESTORE_SESSION_TOKEN"; + /** + * Internal extra used to pass a binder to the {@link IAugmentedAutofillManagerClient}. + * + * @hide + */ + public static final String EXTRA_AUGMENTED_AUTOFILL_CLIENT = + "android.view.autofill.extra.AUGMENTED_AUTOFILL_CLIENT"; + private static final String SESSION_ID_TAG = "android:sessionId"; private static final String STATE_TAG = "android:state"; private static final String LAST_AUTOFILLED_DATA_TAG = "android:lastAutoFilledData"; @@ -370,6 +378,9 @@ public final class AutofillManager { private Cleaner mServiceClientCleaner; @GuardedBy("mLock") + private IAugmentedAutofillManagerClient mAugmentedAutofillServiceClient; + + @GuardedBy("mLock") private AutofillCallback mCallback; private final Context mContext; @@ -1664,6 +1675,8 @@ public final class AutofillManager { final IAutoFillManager service = mService; final IAutoFillManagerClient serviceClient = mServiceClient; mServiceClientCleaner = Cleaner.create(this, () -> { + // TODO(b/111330312): call service to also remove reference to + // mAugmentedAutofillServiceClient try { service.removeClient(serviceClient, userId); } catch (RemoteException e) { @@ -1808,6 +1821,7 @@ public final class AutofillManager { if ((flags & SET_STATE_FLAG_RESET_CLIENT) != 0) { // Reset connection to system mServiceClient = null; + mAugmentedAutofillServiceClient = null; if (mServiceClientCleaner != null) { mServiceClientCleaner.clean(); mServiceClientCleaner = null; @@ -2054,6 +2068,29 @@ public final class AutofillManager { } } + /** + * Gets a {@link AugmentedAutofillManagerClient} for this {@link AutofillManagerClient}. + * + * <p>These are 2 distinct objects because we need to restrict what the Augmented Autofill + * service can do (which is defined by {@code IAugmentedAutofillManagerClient.aidl}). + */ + private void getAugmentedAutofillClient(@NonNull IResultReceiver result) { + synchronized (mLock) { + if (mAugmentedAutofillServiceClient == null) { + mAugmentedAutofillServiceClient = new AugmentedAutofillManagerClient(this); + } + final Bundle resultData = new Bundle(); + resultData.putBinder(EXTRA_AUGMENTED_AUTOFILL_CLIENT, + mAugmentedAutofillServiceClient.asBinder()); + + try { + result.send(0, resultData); + } catch (RemoteException e) { + Log.w(TAG, "Could not send AugmentedAutofillClient back: " + e); + } + } + } + /** @hide */ public void requestHideFillUi() { requestHideFillUi(mIdShownFillUi, true); @@ -2801,7 +2838,7 @@ public final class AutofillManager { private static final class AutofillManagerClient extends IAutoFillManagerClient.Stub { private final WeakReference<AutofillManager> mAfm; - AutofillManagerClient(AutofillManager autofillManager) { + private AutofillManagerClient(AutofillManager autofillManager) { mAfm = new WeakReference<>(autofillManager); } @@ -2904,6 +2941,50 @@ public final class AutofillManager { afm.post(() -> afm.setSessionFinished(newState)); } } + + @Override + public void getAugmentedAutofillClient(IResultReceiver result) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + afm.post(() -> afm.getAugmentedAutofillClient(result)); + } + } + } + + private static final class AugmentedAutofillManagerClient + extends IAugmentedAutofillManagerClient.Stub { + private final WeakReference<AutofillManager> mAfm; + + private AugmentedAutofillManagerClient(AutofillManager autofillManager) { + mAfm = new WeakReference<>(autofillManager); + } + + @Override + public Rect getViewCoordinates(@NonNull AutofillId id) { + // TODO(b/111330312): use handler / callback? + final AutofillManager afm = mAfm.get(); + if (afm == null) return null; + + final View view = afm.getClient().autofillClientFindViewByAutofillIdTraversal(id); + // TODO(b/111330312): optimize (for example, use temp rect from attach info) and + // fix (for example, take system status bar height into account) logic below + final int[] location = new int[2]; + view.getLocationOnScreen(location); + final Rect rect = new Rect(location[0], location[1], location[0] + view.getWidth(), + location[1] + view.getHeight()); + if (sVerbose) { + Log.v(TAG, "Coordinates for " + id + ": " + rect); + } + return rect; + } + + @Override + public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + afm.post(() -> afm.autofill(sessionId, ids, values)); + } + } } /** diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl new file mode 100644 index 000000000000..67cd0bf87b99 --- /dev/null +++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.autofill; + +import java.util.List; + +import android.graphics.Rect; +import android.view.autofill.AutofillId; +import android.view.autofill.AutofillValue; + +/** + * Object running in the application process and responsible to provide the functionalities + * required by an Augmented Autofill service. + * + * @hide + */ +interface IAugmentedAutofillManagerClient { + Rect getViewCoordinates(in AutofillId id); + void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values); +} diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index 0ff7a0bdb963..63394b42eb5a 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -27,6 +27,8 @@ import android.view.autofill.AutofillValue; import android.view.autofill.IAutofillWindowPresenter; import android.view.KeyEvent; +import com.android.internal.os.IResultReceiver; + /** * Object running in the application process and responsible for autofilling it. * @@ -93,8 +95,18 @@ oneway interface IAutoFillManagerClient { /** * Marks the state of the session as finished. + * * @param newState STATE_FINISHED (because the autofill service returned a null * FillResponse) or STATE_UNKNOWN (because the session was removed). */ void setSessionFinished(int newState); + + /** + * Gets a reference to the binder object that can be used by the Augmented Autofill service. + * + * @param receiver, whose AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT extra will contain + * the reference. + */ + void getAugmentedAutofillClient(in IResultReceiver result); + } diff --git a/core/java/android/view/intelligence/IIntelligenceManager.aidl b/core/java/android/view/intelligence/IIntelligenceManager.aidl index 2f128de1f53d..7518ff53b638 100644 --- a/core/java/android/view/intelligence/IIntelligenceManager.aidl +++ b/core/java/android/view/intelligence/IIntelligenceManager.aidl @@ -38,7 +38,8 @@ oneway interface IIntelligenceManager { /** * Finishes a session. */ - void finishSession(int userId, in InteractionSessionId sessionId); + void finishSession(int userId, in InteractionSessionId sessionId, + in List<ContentCaptureEvent> events); /** * Sends a batch of events diff --git a/core/java/android/view/intelligence/IntelligenceManager.java b/core/java/android/view/intelligence/IntelligenceManager.java index dfa52d94f4a1..2f3b4ef56aa1 100644 --- a/core/java/android/view/intelligence/IntelligenceManager.java +++ b/core/java/android/view/intelligence/IntelligenceManager.java @@ -39,7 +39,6 @@ import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.intelligence.ContentCaptureEvent.EventType; -import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.internal.util.Preconditions; @@ -47,10 +46,18 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; /** * TODO(b/111276913): add javadocs / implement */ +/* + * NOTE: all methods in this class should return right away, or do the real work in a handler + * thread. + * + * Hence, the only field that must be thread-safe is mEnabled, which is called at the beginning + * of every method. + */ @SystemService(Context.INTELLIGENCE_MANAGER_SERVICE) public final class IntelligenceManager { @@ -97,48 +104,48 @@ public final class IntelligenceManager { private static final String BG_THREAD_NAME = "intel_svc_streamer_thread"; /** - * Maximum number of events that are delayed for an app. - * - * <p>If the session is not started after the limit is reached, it's discarded. + * Maximum number of events that are buffered before sent to the app. */ - private static final int MAX_DELAYED_SIZE = 20; + // TODO(b/111276913): use settings + private static final int MAX_BUFFER_SIZE = 100; + @NonNull + private final AtomicBoolean mDisabled = new AtomicBoolean(); + + @NonNull private final Context mContext; @Nullable private final IIntelligenceManager mService; - private final Object mLock = new Object(); - @Nullable - @GuardedBy("mLock") private InteractionSessionId mId; - @GuardedBy("mLock") private int mState = STATE_UNKNOWN; - @GuardedBy("mLock") + @Nullable private IBinder mApplicationToken; - // TODO(b/111276913): replace by an interface name implemented by Activity, similar to - // AutofillClient - @GuardedBy("mLock") + @Nullable private ComponentName mComponentName; - // TODO(b/111276913): create using maximum batch size as capacity /** * List of events held to be sent as a batch. */ - @GuardedBy("mLock") - private final ArrayList<ContentCaptureEvent> mEvents = new ArrayList<>(); + @Nullable + private ArrayList<ContentCaptureEvent> mEvents; + // TODO(b/111276913): use UI Thread directly (as calls are one-way) or a shared thread / handler + // held at the Application level private final Handler mHandler; /** @hide */ public IntelligenceManager(@NonNull Context context, @Nullable IIntelligenceManager service) { mContext = Preconditions.checkNotNull(context, "context cannot be null"); + if (VERBOSE) { + Log.v(TAG, "Constructor for " + context.getPackageName()); + } mService = service; - // TODO(b/111276913): use an existing bg thread instead... final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME); bgThread.start(); @@ -149,102 +156,100 @@ public final class IntelligenceManager { public void onActivityCreated(@NonNull IBinder token, @NonNull ComponentName componentName) { if (!isContentCaptureEnabled()) return; - synchronized (mLock) { - if (mState != STATE_UNKNOWN) { - // TODO(b/111276913): revisit this scenario - Log.w(TAG, "ignoring onActivityStarted(" + token + ") while on state " - + getStateAsString(mState)); - return; - } - mState = STATE_WAITING_FOR_SERVER; - mId = new InteractionSessionId(); - mApplicationToken = token; - mComponentName = componentName; + mHandler.sendMessage(obtainMessage(IntelligenceManager::handleStartSession, this, + token, componentName)); + } - if (VERBOSE) { - Log.v(TAG, "onActivityCreated(): token=" + token + ", act=" - + getActivityDebugNameLocked() + ", id=" + mId); - } - final int flags = 0; // TODO(b/111276913): get proper flags - - try { - mService.startSession(mContext.getUserId(), mApplicationToken, componentName, - mId, flags, new IResultReceiver.Stub() { - @Override - public void send(int resultCode, Bundle resultData) - throws RemoteException { - synchronized (mLock) { - mState = resultCode; - if (VERBOSE) { - Log.v(TAG, "onActivityStarted() result: code=" + resultCode - + ", id=" + mId - + ", state=" + getStateAsString(mState)); - } - } - } - }); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName) { + if (mState != STATE_UNKNOWN) { + // TODO(b/111276913): revisit this scenario + Log.w(TAG, "ignoring handleStartSession(" + token + ") while on state " + + getStateAsString(mState)); + return; } - } + mState = STATE_WAITING_FOR_SERVER; + mId = new InteractionSessionId(); + mApplicationToken = token; + mComponentName = componentName; - //TODO(b/111276913): should buffer event (and call service on handler thread), instead of - // calling right away - private void sendEvent(@NonNull ContentCaptureEvent event) { - mHandler.sendMessage(obtainMessage(IntelligenceManager::handleSendEvent, this, event)); + if (VERBOSE) { + Log.v(TAG, "handleStartSession(): token=" + token + ", act=" + + getActivityDebugName() + ", id=" + mId); + } + final int flags = 0; // TODO(b/111276913): get proper flags + + try { + mService.startSession(mContext.getUserId(), mApplicationToken, componentName, + mId, flags, new IResultReceiver.Stub() { + @Override + public void send(int resultCode, Bundle resultData) { + handleSessionStarted(resultCode); + } + }); + } catch (RemoteException e) { + Log.w(TAG, "Error starting session for " + componentName.flattenToShortString() + ": " + + e); + } } - private void handleSendEvent(@NonNull ContentCaptureEvent event) { - - //TODO(b/111276913): make a copy and don't use lock - synchronized (mLock) { - mEvents.add(event); - final int numberEvents = mEvents.size(); - if (mState != STATE_ACTIVE) { - if (numberEvents >= MAX_DELAYED_SIZE) { - // Typically happens on system apps that are started before the system service - // is ready (like com.android.settings/.FallbackHome) - //TODO(b/111276913): try to ignore session while system is not ready / boot - // not complete instead. Similarly, the manager service should return right away - // when the user does not have a service set - if (VERBOSE) { - Log.v(TAG, "Closing session for " + getActivityDebugNameLocked() - + " after " + numberEvents + " delayed events and state " - + getStateAsString(mState)); - } - // TODO(b/111276913): blacklist activity / use special flag to indicate that - // when it's launched again - resetStateLocked(); - return; - } + private void handleSessionStarted(int resultCode) { + mState = resultCode; + mDisabled.set(mState == STATE_DISABLED); + if (VERBOSE) { + Log.v(TAG, "onActivityStarted() result: code=" + resultCode + ", id=" + mId + + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()); + } + } - if (VERBOSE) { - Log.v(TAG, "Delaying " + numberEvents + " events for " - + getActivityDebugNameLocked() + " while on state " - + getStateAsString(mState)); - } - return; + private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { + if (mEvents == null) { + if (VERBOSE) { + Log.v(TAG, "Creating buffer for " + MAX_BUFFER_SIZE + " events"); } + mEvents = new ArrayList<>(MAX_BUFFER_SIZE); + } + mEvents.add(event); + final int numberEvents = mEvents.size(); + if (numberEvents < MAX_BUFFER_SIZE && !forceFlush) { + // Buffering events, return right away... + return; + } - if (mId == null) { - // Sanity check - should not happen - Log.wtf(TAG, "null session id for " + mComponentName); - return; + if (mState != STATE_ACTIVE) { + // Callback from startSession hasn't been called yet - typically happens on system + // apps that are started before the system service + // TODO(b/111276913): try to ignore session while system is not ready / boot + // not complete instead. Similarly, the manager service should return right away + // when the user does not have a service set + if (VERBOSE) { + Log.v(TAG, "Closing session for " + getActivityDebugName() + + " after " + numberEvents + " delayed events and state " + + getStateAsString(mState)); } + handleResetState(); + // TODO(b/111276913): blacklist activity / use special flag to indicate that + // when it's launched again + return; + } - //TODO(b/111276913): right now we're sending sending right away (unless not ready), but - // we should hold the events and flush later. - try { - if (DEBUG) { - Log.d(TAG, "Sending " + numberEvents + " event(s) for " - + getActivityDebugNameLocked()); - } - mService.sendEvents(mContext.getUserId(), mId, mEvents); - mEvents.clear(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + if (mId == null) { + // Sanity check - should not happen + Log.wtf(TAG, "null session id for " + getActivityDebugName()); + return; + } + + try { + if (DEBUG) { + Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName()); } + mService.sendEvents(mContext.getUserId(), mId, mEvents); + // TODO(b/111276913): decide whether we should clear or set it to null, as each has + // its own advantages: clearing will save extra allocations while the session is + // active, while setting to null would save memory if there's no more event coming. + mEvents.clear(); + } catch (RemoteException e) { + Log.w(TAG, "Error sending " + numberEvents + " for " + getActivityDebugName() + + ": " + e); } } @@ -256,41 +261,54 @@ public final class IntelligenceManager { public void onActivityLifecycleEvent(@EventType int type) { if (!isContentCaptureEnabled()) return; if (VERBOSE) { - Log.v(TAG, "onActivityLifecycleEvent() for " + getActivityDebugNameLocked() + Log.v(TAG, "onActivityLifecycleEvent() for " + getActivityDebugName() + ": " + ContentCaptureEvent.getTypeAsString(type)); } - sendEvent(new ContentCaptureEvent(type)); + mHandler.sendMessage(obtainMessage(IntelligenceManager::handleSendEvent, this, + new ContentCaptureEvent(type), /* forceFlush= */ true)); } /** @hide */ public void onActivityDestroyed() { if (!isContentCaptureEnabled()) return; - synchronized (mLock) { - //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote - // id) and send it to the cache of batched commands + //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote + // id) and send it to the cache of batched commands + if (VERBOSE) { + Log.v(TAG, "onActivityDestroyed(): state=" + getStateAsString(mState) + + ", mId=" + mId); + } - if (VERBOSE) { - Log.v(TAG, "onActivityDestroyed(): state=" + getStateAsString(mState) - + ", mId=" + mId); - } + mHandler.sendMessage(obtainMessage(IntelligenceManager::handleFinishSession, this)); + } - try { - mService.finishSession(mContext.getUserId(), mId); - resetStateLocked(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + private void handleFinishSession() { + //TODO(b/111276913): right now both the ContentEvents and lifecycle sessions are sent + // to system_server, so it's ok to call both in sequence here. But once we split + // them so the events are sent directly to the service, we need to make sure they're + // sent in order. + try { + if (DEBUG) { + Log.d(TAG, "Finishing session " + mId + " with " + + (mEvents == null ? 0 : mEvents.size()) + " event(s) for " + + getActivityDebugName()); } + + mService.finishSession(mContext.getUserId(), mId, mEvents); + } catch (RemoteException e) { + Log.e(TAG, "Error finishing session " + mId + " for " + getActivityDebugName() + + ": " + e); + } finally { + handleResetState(); } } - @GuardedBy("mLock") - private void resetStateLocked() { + private void handleResetState() { mState = STATE_UNKNOWN; mId = null; mApplicationToken = null; mComponentName = null; - mEvents.clear(); + mEvents = null; } /** @@ -309,8 +327,11 @@ public final class IntelligenceManager { if (!(node instanceof ViewNode.ViewStructureImpl)) { throw new IllegalArgumentException("Invalid node class: " + node.getClass()); } - sendEvent(new ContentCaptureEvent(TYPE_VIEW_APPEARED) - .setViewNode(((ViewNode.ViewStructureImpl) node).mNode)); + + mHandler.sendMessage(obtainMessage(IntelligenceManager::handleSendEvent, this, + new ContentCaptureEvent(TYPE_VIEW_APPEARED) + .setViewNode(((ViewNode.ViewStructureImpl) node).mNode), + /* forceFlush= */ false)); } /** @@ -325,7 +346,9 @@ public final class IntelligenceManager { Preconditions.checkNotNull(id); if (!isContentCaptureEnabled()) return; - sendEvent(new ContentCaptureEvent(TYPE_VIEW_DISAPPEARED).setAutofillId(id)); + mHandler.sendMessage(obtainMessage(IntelligenceManager::handleSendEvent, this, + new ContentCaptureEvent(TYPE_VIEW_DISAPPEARED).setAutofillId(id), + /* forceFlush= */ false)); } /** @@ -339,10 +362,12 @@ public final class IntelligenceManager { public void notifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text, int flags) { Preconditions.checkNotNull(id); + if (!isContentCaptureEnabled()) return; - sendEvent(new ContentCaptureEvent(TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id) - .setText(text)); + mHandler.sendMessage(obtainMessage(IntelligenceManager::handleSendEvent, this, + new ContentCaptureEvent(TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id) + .setText(text), /* forceFlush= */ false)); } /** @@ -384,14 +409,11 @@ public final class IntelligenceManager { * Checks whether content capture is enabled for this activity. */ public boolean isContentCaptureEnabled() { - //TODO(b/111276913): properly implement by checking if it was explicitly disabled by - // service, or if service is not set - // (and probably renamign to isEnabledLocked() - return mService != null && mState != STATE_DISABLED; + return mService != null && !mDisabled.get(); } /** - * Called by apps to explicitly enabled or disable content capture. + * Called by apps to explicitly enable or disable content capture. * * <p><b>Note: </b> this call is not persisted accross reboots, so apps should typically call * it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}. @@ -504,25 +526,36 @@ public final class IntelligenceManager { public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.println("IntelligenceManager"); final String prefix2 = prefix + " "; - synchronized (mLock) { - pw.print(prefix2); pw.print("mContext: "); pw.println(mContext); + pw.print(prefix2); pw.print("mContext: "); pw.println(mContext); + pw.print(prefix2); pw.print("user: "); pw.println(mContext.getUserId()); + if (mService != null) { pw.print(prefix2); pw.print("mService: "); pw.println(mService); - pw.print(prefix2); pw.print("user: "); pw.println(mContext.getUserId()); - pw.print(prefix2); pw.print("enabled: "); pw.println(isContentCaptureEnabled()); + } + pw.print(prefix2); pw.print("mDisabled: "); pw.println(mDisabled.get()); + pw.print(prefix2); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled()); + if (mId != null) { pw.print(prefix2); pw.print("id: "); pw.println(mId); - pw.print(prefix2); pw.print("state: "); pw.print(mState); pw.print(" ("); - pw.print(getStateAsString(mState)); pw.println(")"); + } + pw.print(prefix2); pw.print("state: "); pw.print(mState); pw.print(" ("); + pw.print(getStateAsString(mState)); pw.println(")"); + if (mApplicationToken != null) { pw.print(prefix2); pw.print("app token: "); pw.println(mApplicationToken); + } + if (mComponentName != null) { pw.print(prefix2); pw.print("component name: "); - pw.println(mComponentName == null ? "null" : mComponentName.flattenToShortString()); + pw.println(mComponentName.flattenToShortString()); + } + if (mEvents != null) { final int numberEvents = mEvents.size(); - pw.print(prefix2); pw.print("batched events: "); pw.println(numberEvents); - if (numberEvents > 0) { + pw.print(prefix2); pw.print("batched events: "); pw.print(numberEvents); + pw.print('/'); pw.println(MAX_BUFFER_SIZE); + if (VERBOSE && numberEvents > 0) { + final String prefix3 = prefix2 + " "; for (int i = 0; i < numberEvents; i++) { final ContentCaptureEvent event = mEvents.get(i); - pw.println(i); pw.print(": "); event.dump(pw); pw.println(); + pw.print(prefix3); pw.print(i); pw.print(": "); event.dump(pw); + pw.println(); } - } } } @@ -530,8 +563,7 @@ public final class IntelligenceManager { /** * Gets a string that can be used to identify the activity on logging statements. */ - @GuardedBy("mLock") - private String getActivityDebugNameLocked() { + private String getActivityDebugName() { return mComponentName == null ? mContext.getPackageName() : mComponentName.flattenToShortString(); } diff --git a/core/java/android/view/intelligence/ViewNode.java b/core/java/android/view/intelligence/ViewNode.java index cc78e6b4aa6d..ea57461f0933 100644 --- a/core/java/android/view/intelligence/ViewNode.java +++ b/core/java/android/view/intelligence/ViewNode.java @@ -238,6 +238,8 @@ public final class ViewNode extends AssistStructure.ViewNode { @Override public void setText(CharSequence text, int selectionStart, int selectionEnd) { + // TODO(b/111276913): temporarily setting directly; should be done on superclass instead + mNode.mText = text; // TODO(b/111276913): implement or move to superclass } diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java new file mode 100644 index 000000000000..8df83c0e5dff --- /dev/null +++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textclassifier; + +import android.annotation.NonNull; +import android.app.Person; +import android.text.TextUtils; +import android.util.ArrayMap; + +import com.android.internal.annotations.VisibleForTesting; + +import com.google.android.textclassifier.ActionsSuggestionsModel; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Helper class for action suggestions. + * + * @hide + */ +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public final class ActionsSuggestionsHelper { + private static final int USER_LOCAL = 0; + private static final int FIRST_NON_LOCAL_USER = 1; + + private ActionsSuggestionsHelper() {} + + /** + * Converts the messages to a list of native messages object that the model can understand. + * <p> + * User id encoding - local user is represented as 0, Other users are numbered according to + * how far before they spoke last time in the conversation. For example, considering this + * conversation: + * <ul> + * <li> User A: xxx + * <li> Local user: yyy + * <li> User B: zzz + * </ul> + * User A will be encoded as 2, user B will be encoded as 1 and local user will be encoded as 0. + */ + @NonNull + public static ActionsSuggestionsModel.ConversationMessage[] toNativeMessages( + @NonNull List<ConversationActions.Message> messages) { + List<ConversationActions.Message> messagesWithText = + messages.stream() + .filter(message -> !TextUtils.isEmpty(message.getText())) + .collect(Collectors.toCollection(ArrayList::new)); + if (messagesWithText.isEmpty()) { + return new ActionsSuggestionsModel.ConversationMessage[0]; + } + int size = messagesWithText.size(); + // If the last message (the most important one) does not have the Person object, we will + // just use the last message and consider this message is sent from a remote user. + ConversationActions.Message lastMessage = messages.get(size - 1); + boolean useLastMessageOnly = lastMessage.getAuthor() == null; + if (useLastMessageOnly) { + return new ActionsSuggestionsModel.ConversationMessage[]{ + new ActionsSuggestionsModel.ConversationMessage( + FIRST_NON_LOCAL_USER, + lastMessage.getText().toString())}; + } + + // Encode the messages in the reverse order, stop whenever the Person object is missing. + Deque<ActionsSuggestionsModel.ConversationMessage> nativeMessages = new ArrayDeque<>(); + PersonEncoder personEncoder = new PersonEncoder(); + for (int i = size - 1; i >= 0; i--) { + ConversationActions.Message message = messagesWithText.get(i); + if (message.getAuthor() == null) { + break; + } + nativeMessages.push(new ActionsSuggestionsModel.ConversationMessage( + personEncoder.encode(message.getAuthor()), + message.getText().toString())); + } + return nativeMessages.toArray( + new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]); + } + + private static final class PersonEncoder { + private final Map<Person, Integer> mMapping = new ArrayMap<>(); + private int mNextUserId = FIRST_NON_LOCAL_USER; + + private int encode(Person person) { + if (ConversationActions.Message.PERSON_USER_LOCAL.equals(person)) { + return USER_LOCAL; + } + Integer result = mMapping.get(person); + if (result == null) { + mMapping.put(person, mNextUserId); + result = mNextUserId; + mNextUserId++; + } + return result; + } + } +} diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java index 5fcf22771ec1..1a7b91127a7b 100644 --- a/core/java/android/view/textclassifier/ConversationActions.java +++ b/core/java/android/view/textclassifier/ConversationActions.java @@ -345,6 +345,16 @@ public final class ConversationActions implements Parcelable { /** Represents a message in the conversation. */ public static final class Message implements Parcelable { + /** + * Represents the local user. + * + * @see Builder#setAuthor(Person) + */ + public static final Person PERSON_USER_LOCAL = + new Person.Builder() + .setKey("text-classifier-conversation-actions-local-user") + .build(); + @Nullable private final Person mAuthor; @Nullable @@ -446,7 +456,11 @@ public final class ConversationActions implements Parcelable { @Nullable private Bundle mExtras; - /** Sets the person who composed this message. */ + /** + * Sets the person who composed this message. + * <p> + * Use {@link #PERSON_USER_LOCAL} to represent the local user. + */ @NonNull public Builder setAuthor(@Nullable Person author) { mAuthor = author; diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index f6c3d770d2a8..e0910c0b37b7 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -105,7 +105,7 @@ public final class TextClassification implements Parcelable { /** * @hide */ - static final TextClassification EMPTY = new TextClassification.Builder().build(); + public static final TextClassification EMPTY = new TextClassification.Builder().build(); private static final String LOG_TAG = "TextClassification"; // TODO(toki): investigate a way to derive this based on device properties. diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java index 524f70939398..a2536cbd911c 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -90,6 +90,11 @@ public interface TextClassifier { String TYPE_DATE_TIME = "datetime"; /** Flight number in IATA format. */ String TYPE_FLIGHT_NUMBER = "flight"; + /** + * Word that users may be interested to look up for meaning. + * @hide + */ + String TYPE_DICTIONARY = "dictionary"; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -103,6 +108,7 @@ public interface TextClassifier { TYPE_DATE, TYPE_DATE_TIME, TYPE_FLIGHT_NUMBER, + TYPE_DICTIONARY }) @interface EntityType {} diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 798a8208e240..8e14dfdb7ee3 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -40,9 +40,9 @@ import android.os.UserManager; import android.provider.Browser; import android.provider.CalendarContract; import android.provider.ContactsContract; -import android.text.TextUtils; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; @@ -269,17 +269,17 @@ public final class TextClassifierImpl implements TextClassifier { final ZonedDateTime refTime = ZonedDateTime.now(); final Collection<String> entitiesToIdentify = request.getEntityConfig() != null ? request.getEntityConfig().resolveEntityListModifications( - getEntitiesForHints(request.getEntityConfig().getHints())) + getEntitiesForHints(request.getEntityConfig().getHints())) : mSettings.getEntityListDefault(); final AnnotatorModel annotatorImpl = getAnnotatorImpl(request.getDefaultLocales()); final AnnotatorModel.AnnotatedSpan[] annotations = annotatorImpl.annotate( - textString, - new AnnotatorModel.AnnotationOptions( - refTime.toInstant().toEpochMilli(), - refTime.getZone().getId(), - concatenateLocales(request.getDefaultLocales()))); + textString, + new AnnotatorModel.AnnotationOptions( + refTime.toInstant().toEpochMilli(), + refTime.getZone().getId(), + concatenateLocales(request.getDefaultLocales()))); for (AnnotatorModel.AnnotatedSpan span : annotations) { final AnnotatorModel.ClassificationResult[] results = span.getClassification(); @@ -373,20 +373,13 @@ public final class TextClassifierImpl implements TextClassifier { // Actions model is optional, fallback if it is not available. return mFallback.suggestConversationActions(request); } - List<ActionsSuggestionsModel.ConversationMessage> nativeMessages = new ArrayList<>(); - for (ConversationActions.Message message : request.getConversation()) { - if (TextUtils.isEmpty(message.getText())) { - continue; - } - // TODO: We need to map the Person object to user id. - int userId = 1; - nativeMessages.add( - new ActionsSuggestionsModel.ConversationMessage( - userId, message.getText().toString())); + ActionsSuggestionsModel.ConversationMessage[] nativeMessages = + ActionsSuggestionsHelper.toNativeMessages(request.getConversation()); + if (nativeMessages.length == 0) { + return mFallback.suggestConversationActions(request); } ActionsSuggestionsModel.Conversation nativeConversation = - new ActionsSuggestionsModel.Conversation(nativeMessages.toArray( - new ActionsSuggestionsModel.ConversationMessage[0])); + new ActionsSuggestionsModel.Conversation(nativeMessages); ActionsSuggestionsModel.ActionSuggestion[] nativeSuggestions = actionsImpl.suggestActions(nativeConversation, null); @@ -523,10 +516,10 @@ public final class TextClassifierImpl implements TextClassifier { final TextClassification.Builder builder = new TextClassification.Builder() .setText(classifiedText); - final int size = classifications.length; + final int typeCount = classifications.length; AnnotatorModel.ClassificationResult highestScoringResult = - size > 0 ? classifications[0] : null; - for (int i = 0; i < size; i++) { + typeCount > 0 ? classifications[0] : null; + for (int i = 0; i < typeCount; i++) { builder.setEntityType(classifications[i].getCollection(), classifications[i].getScore()); if (classifications[i].getScore() > highestScoringResult.getScore()) { @@ -534,9 +527,12 @@ public final class TextClassifierImpl implements TextClassifier { } } + // TODO: Make this configurable. + final float foreignTextThreshold = typeCount == 0 ? 0.5f : 0.7f; boolean isPrimaryAction = true; for (LabeledIntent labeledIntent : IntentFactory.create( - mContext, classifiedText, referenceTime, highestScoringResult)) { + mContext, classifiedText, isForeignText(classifiedText, foreignTextThreshold), + referenceTime, highestScoringResult)) { final RemoteAction action = labeledIntent.asRemoteAction(mContext); if (action == null) { continue; @@ -558,6 +554,42 @@ public final class TextClassifierImpl implements TextClassifier { return builder.setId(createId(text, start, end)).build(); } + private boolean isForeignText(String text, float threshold) { + // TODO: Revisit this algorithm. + try { + final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text); + if (langResults.length <= 0) { + return false; + } + + LangIdModel.LanguageResult highestScoringResult = langResults[0]; + for (int i = 1; i < langResults.length; i++) { + if (langResults[i].getScore() > highestScoringResult.getScore()) { + highestScoringResult = langResults[i]; + } + } + if (highestScoringResult.getScore() < threshold) { + return false; + } + // TODO: Remove + Log.d(LOG_TAG, String.format("Language detected: <%s:%s>", + highestScoringResult.getLanguage(), highestScoringResult.getScore())); + + final Locale detected = new Locale(highestScoringResult.getLanguage()); + final LocaleList deviceLocales = LocaleList.getDefault(); + final int size = deviceLocales.size(); + for (int i = 0; i < size; i++) { + if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) { + return false; + } + } + return true; + } catch (Throwable t) { + Log.e(LOG_TAG, "Error detecting foreign text. Ignored.", t); + } + return false; + } + @Override public void dump(@NonNull IndentingPrintWriter printWriter) { synchronized (mLock) { @@ -608,7 +640,8 @@ public final class TextClassifierImpl implements TextClassifier { /** * Helper class to store the information from which RemoteActions are built. */ - private static final class LabeledIntent { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public static final class LabeledIntent { static final int DEFAULT_REQUEST_CODE = 0; @@ -643,7 +676,8 @@ public final class TextClassifierImpl implements TextClassifier { return mDescription; } - Intent getIntent() { + @VisibleForTesting + public Intent getIntent() { return mIntent; } @@ -687,7 +721,8 @@ public final class TextClassifierImpl implements TextClassifier { /** * Creates intents based on the classification type. */ - static final class IntentFactory { + @VisibleForTesting + public static final class IntentFactory { private static final long MIN_EVENT_FUTURE_MILLIS = TimeUnit.MINUTES.toMillis(5); private static final long DEFAULT_EVENT_DURATION = TimeUnit.HOURS.toMillis(1); @@ -698,53 +733,70 @@ public final class TextClassifierImpl implements TextClassifier { public static List<LabeledIntent> create( Context context, String text, + boolean foreignText, @Nullable Instant referenceTime, @Nullable AnnotatorModel.ClassificationResult classification) { final String type = classification != null ? classification.getCollection().trim().toLowerCase(Locale.ENGLISH) - : null; + : ""; text = text.trim(); + final List<LabeledIntent> actions; switch (type) { case TextClassifier.TYPE_EMAIL: - return createForEmail(context, text); + actions = createForEmail(context, text); + break; case TextClassifier.TYPE_PHONE: - return createForPhone(context, text); + actions = createForPhone(context, text); + break; case TextClassifier.TYPE_ADDRESS: - return createForAddress(context, text); + actions = createForAddress(context, text); + break; case TextClassifier.TYPE_URL: - return createForUrl(context, text); - case TextClassifier.TYPE_DATE: + actions = createForUrl(context, text); + break; + case TextClassifier.TYPE_DATE: // fall through case TextClassifier.TYPE_DATE_TIME: if (classification.getDatetimeResult() != null) { final Instant parsedTime = Instant.ofEpochMilli( classification.getDatetimeResult().getTimeMsUtc()); - return createForDatetime(context, type, referenceTime, parsedTime); + actions = createForDatetime(context, type, referenceTime, parsedTime); } else { - return new ArrayList<>(); + actions = new ArrayList<>(); } + break; case TextClassifier.TYPE_FLIGHT_NUMBER: - return createForFlight(context, text); + actions = createForFlight(context, text); + break; + case TextClassifier.TYPE_DICTIONARY: + actions = createForDictionary(context, text); + break; default: - return new ArrayList<>(); + actions = new ArrayList<>(); + break; + } + if (foreignText) { + insertTranslateAction(actions, context, text); } + return actions; } @NonNull private static List<LabeledIntent> createForEmail(Context context, String text) { - return Arrays.asList( - new LabeledIntent( - context.getString(com.android.internal.R.string.email), - context.getString(com.android.internal.R.string.email_desc), - new Intent(Intent.ACTION_SENDTO) - .setData(Uri.parse(String.format("mailto:%s", text))), - LabeledIntent.DEFAULT_REQUEST_CODE), - new LabeledIntent( - context.getString(com.android.internal.R.string.add_contact), - context.getString(com.android.internal.R.string.add_contact_desc), - new Intent(Intent.ACTION_INSERT_OR_EDIT) - .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE) - .putExtra(ContactsContract.Intents.Insert.EMAIL, text), - text.hashCode())); + final List<LabeledIntent> actions = new ArrayList<>(); + actions.add(new LabeledIntent( + context.getString(com.android.internal.R.string.email), + context.getString(com.android.internal.R.string.email_desc), + new Intent(Intent.ACTION_SENDTO) + .setData(Uri.parse(String.format("mailto:%s", text))), + LabeledIntent.DEFAULT_REQUEST_CODE)); + actions.add(new LabeledIntent( + context.getString(com.android.internal.R.string.add_contact), + context.getString(com.android.internal.R.string.add_contact_desc), + new Intent(Intent.ACTION_INSERT_OR_EDIT) + .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE) + .putExtra(ContactsContract.Intents.Insert.EMAIL, text), + text.hashCode())); + return actions; } @NonNull @@ -801,12 +853,14 @@ public final class TextClassifierImpl implements TextClassifier { if (Uri.parse(text).getScheme() == null) { text = "http://" + text; } - return Arrays.asList(new LabeledIntent( + final List<LabeledIntent> actions = new ArrayList<>(); + actions.add(new LabeledIntent( context.getString(com.android.internal.R.string.browse), context.getString(com.android.internal.R.string.browse_desc), new Intent(Intent.ACTION_VIEW, Uri.parse(text)) .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()), LabeledIntent.DEFAULT_REQUEST_CODE)); + return actions; } @NonNull @@ -828,12 +882,14 @@ public final class TextClassifierImpl implements TextClassifier { @NonNull private static List<LabeledIntent> createForFlight(Context context, String text) { - return Arrays.asList(new LabeledIntent( + final List<LabeledIntent> actions = new ArrayList<>(); + actions.add(new LabeledIntent( context.getString(com.android.internal.R.string.view_flight), context.getString(com.android.internal.R.string.view_flight_desc), new Intent(Intent.ACTION_WEB_SEARCH) .putExtra(SearchManager.QUERY, text), text.hashCode())); + return actions; } @NonNull @@ -864,5 +920,27 @@ public final class TextClassifierImpl implements TextClassifier { parsedTime.toEpochMilli() + DEFAULT_EVENT_DURATION), parsedTime.hashCode()); } + + private static void insertTranslateAction( + List<LabeledIntent> actions, Context context, String text) { + actions.add(new LabeledIntent( + context.getString(com.android.internal.R.string.translate), + context.getString(com.android.internal.R.string.translate_desc), + new Intent(Intent.ACTION_TRANSLATE) + // TODO: Probably better to introduce a "translate" scheme instead of + // using EXTRA_TEXT. + .putExtra(Intent.EXTRA_TEXT, text), + text.hashCode())); + } + + @NonNull + private static List<LabeledIntent> createForDictionary(Context context, String text) { + return Arrays.asList(new LabeledIntent( + context.getString(com.android.internal.R.string.define), + context.getString(com.android.internal.R.string.define_desc), + new Intent(Intent.ACTION_DEFINE) + .putExtra(Intent.EXTRA_TEXT, text), + text.hashCode())); + } } } diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java index 02aee508787e..1e42c414a365 100644 --- a/core/java/android/view/textclassifier/TextLinks.java +++ b/core/java/android/view/textclassifier/TextLinks.java @@ -59,7 +59,7 @@ public final class TextLinks implements Parcelable { */ @Retention(RetentionPolicy.SOURCE) @IntDef({STATUS_LINKS_APPLIED, STATUS_NO_LINKS_FOUND, STATUS_NO_LINKS_APPLIED, - STATUS_DIFFERENT_TEXT}) + STATUS_DIFFERENT_TEXT, STATUS_UNSUPPORTED_CHARACTER}) public @interface Status {} /** Links were successfully applied to the text. */ @@ -74,6 +74,9 @@ public final class TextLinks implements Parcelable { /** The specified text does not match the text used to generate the links. */ public static final int STATUS_DIFFERENT_TEXT = 3; + /** The specified text contains unsupported characters. */ + public static final int STATUS_UNSUPPORTED_CHARACTER = 4; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({APPLY_STRATEGY_IGNORE, APPLY_STRATEGY_REPLACE}) diff --git a/core/java/android/view/textclassifier/TextLinksParams.java b/core/java/android/view/textclassifier/TextLinksParams.java index be4c3bcdff67..8af423300406 100644 --- a/core/java/android/view/textclassifier/TextLinksParams.java +++ b/core/java/android/view/textclassifier/TextLinksParams.java @@ -107,6 +107,13 @@ public final class TextLinksParams { Preconditions.checkNotNull(textLinks); final String textString = text.toString(); + + if (Linkify.containsUnsupportedCharacters(textString)) { + // Do not apply links to text containing unsupported characters. + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + return TextLinks.STATUS_UNSUPPORTED_CHARACTER; + } + if (!textString.startsWith(textLinks.getText())) { return TextLinks.STATUS_DIFFERENT_TEXT; } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 4f1417ed23bb..414cb8f30fc7 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -410,6 +410,9 @@ public class WebView extends AbsoluteLayout if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) { setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES); } + if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { + setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES); + } if (context == null) { throw new IllegalArgumentException("Invalid context argument"); diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 12cc54d7241e..c21182ca597f 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -106,9 +106,9 @@ public class ImageView extends View { private boolean mHaveFrame = false; @UnsupportedAppUsage private boolean mAdjustViewBounds = false; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private int mMaxWidth = Integer.MAX_VALUE; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private int mMaxHeight = Integer.MAX_VALUE; // these are applied to the drawable @@ -1331,9 +1331,17 @@ public class ImageView extends View { } } - /** @hide */ - @UnsupportedAppUsage - public void animateTransform(Matrix matrix) { + /** + * Applies a temporary transformation {@link Matrix} to the view's drawable when it is drawn. + * Allows custom scaling, translation, and perspective distortion during an animation. + * + * This method is a lightweight analogue of {@link ImageView#setImageMatrix(Matrix)} to use + * only during animations as this matrix will be cleared after the next drawable + * update or view's bounds change. + * + * @param matrix The transformation parameters in matrix form. + */ + public void animateTransform(@Nullable Matrix matrix) { if (mDrawable == null) { return; } @@ -1341,6 +1349,7 @@ public class ImageView extends View { final int vwidth = getWidth() - mPaddingLeft - mPaddingRight; final int vheight = getHeight() - mPaddingTop - mPaddingBottom; mDrawable.setBounds(0, 0, vwidth, vheight); + mDrawMatrix = null; } else { mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight); if (mDrawMatrix == null) { diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 6cb0eaa7f47d..4caf28881edc 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -31,6 +31,7 @@ import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.TextUtils; +import android.text.util.Linkify; import android.util.Log; import android.view.ActionMode; import android.view.textclassifier.SelectionEvent; @@ -687,17 +688,6 @@ public final class SelectionActionModeHelper { mTokenIterator = SelectionSessionLogger.getTokenIterator(textView.getTextLocale()); } - @TextClassifier.WidgetType - private static String getWidetType(TextView textView) { - if (textView.isTextEditable()) { - return TextClassifier.WIDGET_TYPE_EDITTEXT; - } - if (textView.isTextSelectable()) { - return TextClassifier.WIDGET_TYPE_TEXTVIEW; - } - return TextClassifier.WIDGET_TYPE_UNSELECTABLE_TEXTVIEW; - } - public void logSelectionStarted( TextClassifier classificationSession, CharSequence text, int index, @@ -1045,7 +1035,12 @@ public final class SelectionActionModeHelper { trimText(); final TextClassification classification; - if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) { + if (Linkify.containsUnsupportedCharacters(mText)) { + // Do not show smart actions for text containing unsupported characters. + android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); + classification = TextClassification.EMPTY; + } else if (mContext.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.P) { final TextClassification.Request request = new TextClassification.Request.Builder( mTrimmedText, mRelativeStart, mRelativeEnd) diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 35be7669a4d8..85d851a3116c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -10942,6 +10942,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { if (mLayout == null) { + if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + Log.w(LOG_TAG, "onProvideContentCaptureStructure(): calling assumeLayout()"); + } assumeLayout(); } Layout layout = mLayout; @@ -12265,13 +12268,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Returns the current {@link TextDirectionHeuristic}. - * - * @return the current {@link TextDirectionHeuristic}. - * @hide + * Returns resolved {@link TextDirectionHeuristic} that will be used for text layout. + * The {@link TextDirectionHeuristic} that is used by TextView is only available after + * {@link #getTextDirection()} and {@link #getLayoutDirection()} is resolved. Therefore the + * return value may not be the same as the one TextView uses if the View's layout direction is + * not resolved or detached from parent root view. */ - @UnsupportedAppUsage - protected TextDirectionHeuristic getTextDirectionHeuristic() { + public TextDirectionHeuristic getTextDirectionHeuristic() { if (hasPasswordTransformationMethod()) { // passwords fields should be LTR return TextDirectionHeuristics.LTR; diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index e2b8f7dca680..5d08a259dace 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -309,9 +309,6 @@ public class PackageHelper { } else if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { prefer = RECOMMEND_INSTALL_INTERNAL; checkBoth = false; - } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { - prefer = RECOMMEND_INSTALL_EXTERNAL; - checkBoth = false; } else if (params.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { prefer = RECOMMEND_INSTALL_INTERNAL; checkBoth = false; diff --git a/core/java/com/android/internal/os/KernelCpuProcStringReader.java b/core/java/com/android/internal/os/KernelCpuProcStringReader.java index 22435ae7647a..b3aec0c2a561 100644 --- a/core/java/com/android/internal/os/KernelCpuProcStringReader.java +++ b/core/java/com/android/internal/os/KernelCpuProcStringReader.java @@ -25,6 +25,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.nio.CharBuffer; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; @@ -59,6 +60,7 @@ public class KernelCpuProcStringReader { private static final String PROC_UID_FREQ_TIME = "/proc/uid_time_in_state"; private static final String PROC_UID_ACTIVE_TIME = "/proc/uid_concurrent_active_time"; private static final String PROC_UID_CLUSTER_TIME = "/proc/uid_concurrent_policy_time"; + private static final String PROC_UID_USER_SYS_TIME = "/proc/uid_cputime/show_uid_stat"; private static final KernelCpuProcStringReader FREQ_TIME_READER = new KernelCpuProcStringReader(PROC_UID_FREQ_TIME); @@ -66,19 +68,25 @@ public class KernelCpuProcStringReader { new KernelCpuProcStringReader(PROC_UID_ACTIVE_TIME); private static final KernelCpuProcStringReader CLUSTER_TIME_READER = new KernelCpuProcStringReader(PROC_UID_CLUSTER_TIME); + private static final KernelCpuProcStringReader USER_SYS_TIME_READER = + new KernelCpuProcStringReader(PROC_UID_USER_SYS_TIME); - public static KernelCpuProcStringReader getFreqTimeReaderInstance() { + static KernelCpuProcStringReader getFreqTimeReaderInstance() { return FREQ_TIME_READER; } - public static KernelCpuProcStringReader getActiveTimeReaderInstance() { + static KernelCpuProcStringReader getActiveTimeReaderInstance() { return ACTIVE_TIME_READER; } - public static KernelCpuProcStringReader getClusterTimeReaderInstance() { + static KernelCpuProcStringReader getClusterTimeReaderInstance() { return CLUSTER_TIME_READER; } + static KernelCpuProcStringReader getUserSysTimeReaderInstance() { + return USER_SYS_TIME_READER; + } + private int mErrors = 0; private final Path mFile; private char[] mBuf; @@ -164,12 +172,12 @@ public class KernelCpuProcStringReader { // ReentrantReadWriteLock allows lock downgrading. mReadLock.lock(); return new ProcFileIterator(total); - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { mErrors++; Slog.w(TAG, "File not found. It's normal if not implemented: " + mFile); } catch (IOException e) { mErrors++; - Slog.e(TAG, "Error reading: " + mFile, e); + Slog.e(TAG, "Error reading " + mFile, e); } finally { StrictMode.setThreadPolicyMask(oldMask); mWriteLock.unlock(); @@ -193,6 +201,11 @@ public class KernelCpuProcStringReader { mSize = size; } + /** @return Whether there are more lines in the iterator. */ + public boolean hasNextLine() { + return mPos < mSize; + } + /** * Fetches the next line. Note that all subsequent return values share the same char[] * under the hood. @@ -214,44 +227,6 @@ public class KernelCpuProcStringReader { return CharBuffer.wrap(mBuf, start, i - start); } - /** - * Fetches the next line, converts all numbers into long, and puts into the given long[]. - * To avoid GC, caller should try to use the same array for all calls. All non-numeric - * chars are treated as delimiters. All numbers are non-negative. - * - * @param array An array to store the parsed numbers. - * @return The number of elements written to the given array. -1 if there is no more line. - */ - public int nextLineAsArray(long[] array) { - CharBuffer buf = nextLine(); - if (buf == null) { - return -1; - } - int count = 0; - long num = -1; - char c; - - while (buf.remaining() > 0 && count < array.length) { - c = buf.get(); - if (num < 0) { - if (isNumber(c)) { - num = c - '0'; - } - } else { - if (isNumber(c)) { - num = num * 10 + c - '0'; - } else { - array[count++] = num; - num = -1; - } - } - } - if (num >= 0) { - array[count++] = num; - } - return count; - } - /** Total size of the proc file in chars. */ public int size() { return mSize; @@ -262,8 +237,63 @@ public class KernelCpuProcStringReader { mReadLock.unlock(); } - private boolean isNumber(char c) { - return c >= '0' && c <= '9'; + + } + + /** + * Converts all numbers in the CharBuffer into longs, and puts into the given long[]. + * + * Space and colon are treated as delimiters. All other chars are not allowed. All numbers + * are non-negative. To avoid GC, caller should try to use the same array for all calls. + * + * This method also resets the given buffer to the original position before return so that + * it can be read again. + * + * @param buf The char buffer to be converted. + * @param array An array to store the parsed numbers. + * @return The number of elements written to the given array. -1 if buf is null, -2 if buf + * contains invalid char, -3 if any number overflows. + */ + public static int asLongs(CharBuffer buf, long[] array) { + if (buf == null) { + return -1; + } + final int initialPos = buf.position(); + int count = 0; + long num = -1; + char c; + + while (buf.remaining() > 0 && count < array.length) { + c = buf.get(); + if (!(isNumber(c) || c == ' ' || c == ':')) { + buf.position(initialPos); + return -2; + } + if (num < 0) { + if (isNumber(c)) { + num = c - '0'; + } + } else { + if (isNumber(c)) { + num = num * 10 + c - '0'; + if (num < 0) { + buf.position(initialPos); + return -3; + } + } else { + array[count++] = num; + num = -1; + } + } + } + if (num >= 0) { + array[count++] = num; } + buf.position(initialPos); + return count; + } + + private static boolean isNumber(char c) { + return c >= '0' && c <= '9'; } } diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java index 826cd89f1d01..2e901e4520e6 100644 --- a/core/java/com/android/internal/os/KernelCpuThreadReader.java +++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java @@ -103,10 +103,9 @@ public class KernelCpuThreadReader { /** * Default predicate for what UIDs to check for when getting processes. This filters to only - * select system UIDs (1000-1999) + * select UID 1000 (the {@code system} user) */ - private static final Predicate<Integer> DEFAULT_UID_PREDICATE = - uid -> 1000 <= uid && uid < 2000; + private static final Predicate<Integer> DEFAULT_UID_PREDICATE = uid -> uid == 1000; /** * Do not report any threads that have a total CPU usage (across all frequencies) less than or diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java new file mode 100644 index 000000000000..7021b5781347 --- /dev/null +++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java @@ -0,0 +1,776 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import static com.android.internal.os.KernelCpuProcStringReader.asLongs; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.StrictMode; +import android.os.SystemClock; +import android.util.IntArray; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.KernelCpuProcStringReader.ProcFileIterator; + +import java.io.BufferedReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Reads per-UID CPU time proc files. Concrete implementations are all nested inside. + * + * This class uses a throttler to reject any {@link #readDelta} or {@link #readAbsolute} call + * within {@link #mMinTimeBetweenRead}. The throttler can be enable / disabled via a param in + * the constructor. + * + * This class and its subclasses are NOT thread-safe and NOT designed to be accessed by more than + * one caller since each caller has its own view of delta. + * + * @param <T> The type of CPU time for the callback. + */ +public abstract class KernelCpuUidTimeReader<T> { + protected static final boolean DEBUG = false; + private static final long DEFAULT_MIN_TIME_BETWEEN_READ = 1000L; // In milliseconds + + final String mTag = this.getClass().getSimpleName(); + final SparseArray<T> mLastTimes = new SparseArray<>(); + final KernelCpuProcStringReader mReader; + final boolean mThrottle; + private long mMinTimeBetweenRead = DEFAULT_MIN_TIME_BETWEEN_READ; + private long mLastReadTimeMs = 0; + + /** + * Callback interface for processing each line of the proc file. + * + * @param <T> The type of CPU time for the callback function. + */ + public interface Callback<T> { + /** + * @param uid UID of the app + * @param time Time spent. The exact data structure depends on subclass implementation. + */ + void onUidCpuTime(int uid, T time); + } + + KernelCpuUidTimeReader(KernelCpuProcStringReader reader, boolean throttle) { + mReader = reader; + mThrottle = throttle; + } + + /** + * Reads the proc file, calling into the callback with a delta of time for each UID. + * + * @param cb The callback to invoke for each line of the proc file. If null,the data is + * consumed and subsequent calls to readDelta will provide a fresh delta. + */ + public void readDelta(@Nullable Callback<T> cb) { + if (!mThrottle) { + readDeltaImpl(cb); + return; + } + final long currTimeMs = SystemClock.elapsedRealtime(); + if (currTimeMs < mLastReadTimeMs + mMinTimeBetweenRead) { + if (DEBUG) { + Slog.d(mTag, "Throttle readDelta"); + } + return; + } + readDeltaImpl(cb); + mLastReadTimeMs = currTimeMs; + } + + /** + * Reads the proc file, calling into the callback with cumulative time for each UID. + * + * @param cb The callback to invoke for each line of the proc file. It cannot be null. + */ + public void readAbsolute(Callback<T> cb) { + if (!mThrottle) { + readAbsoluteImpl(cb); + return; + } + final long currTimeMs = SystemClock.elapsedRealtime(); + if (currTimeMs < mLastReadTimeMs + mMinTimeBetweenRead) { + if (DEBUG) { + Slog.d(mTag, "Throttle readAbsolute"); + } + return; + } + readAbsoluteImpl(cb); + mLastReadTimeMs = currTimeMs; + } + + abstract void readDeltaImpl(@Nullable Callback<T> cb); + + abstract void readAbsoluteImpl(Callback<T> callback); + + /** + * Removes the UID from internal accounting data. This method, overridden in + * {@link KernelCpuUidUserSysTimeReader}, also removes the UID from the kernel module. + * + * @param uid The UID to remove. + * @see KernelCpuUidUserSysTimeReader#removeUid(int) + */ + public void removeUid(int uid) { + mLastTimes.delete(uid); + } + + /** + * Removes UIDs in a given range from internal accounting data. This method, overridden in + * {@link KernelCpuUidUserSysTimeReader}, also removes the UIDs from the kernel module. + * + * @param startUid the first uid to remove. + * @param endUid the last uid to remove. + * @see KernelCpuUidUserSysTimeReader#removeUidsInRange(int, int) + */ + public void removeUidsInRange(int startUid, int endUid) { + if (endUid < startUid) { + Slog.e(mTag, "start UID " + startUid + " > end UID " + endUid); + return; + } + mLastTimes.put(startUid, null); + mLastTimes.put(endUid, null); + final int firstIndex = mLastTimes.indexOfKey(startUid); + final int lastIndex = mLastTimes.indexOfKey(endUid); + mLastTimes.removeAtRange(firstIndex, lastIndex - firstIndex + 1); + } + + /** + * Set the minimum time in milliseconds between reads. If throttle is not enabled, this method + * has no effect. + * + * @param minTimeBetweenRead The minimum time in milliseconds. + */ + public void setThrottle(long minTimeBetweenRead) { + if (mThrottle && minTimeBetweenRead >= 0) { + mMinTimeBetweenRead = minTimeBetweenRead; + } + } + + /** + * Reads /proc/uid_cputime/show_uid_stat which has the line format: + * + * uid: user_time_micro_seconds system_time_micro_seconds power_in_milli-amp-micro_seconds + * + * This provides the time a UID's processes spent executing in user-space and kernel-space. + * The file contains a monotonically increasing count of time for a single boot. This class + * maintains the previous results of a call to {@link #readDelta} in order to provide a proper + * delta. + */ + public static class KernelCpuUidUserSysTimeReader extends KernelCpuUidTimeReader<long[]> { + private static final String REMOVE_UID_PROC_FILE = "/proc/uid_cputime/remove_uid_range"; + + // [uid, user_time, system_time, (maybe) power_in_milli-amp-micro_seconds] + private final long[] mBuffer = new long[4]; + // A reusable array to hold [user_time, system_time] for the callback. + private final long[] mUsrSysTime = new long[2]; + + public KernelCpuUidUserSysTimeReader(boolean throttle) { + super(KernelCpuProcStringReader.getUserSysTimeReaderInstance(), throttle); + } + + @VisibleForTesting + public KernelCpuUidUserSysTimeReader(KernelCpuProcStringReader reader, boolean throttle) { + super(reader, throttle); + } + + @Override + void readDeltaImpl(@Nullable Callback<long[]> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (iter == null) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) < 3) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + final int uid = (int) mBuffer[0]; + long[] lastTimes = mLastTimes.get(uid); + if (lastTimes == null) { + lastTimes = new long[2]; + mLastTimes.put(uid, lastTimes); + } + final long currUsrTimeUs = mBuffer[1]; + final long currSysTimeUs = mBuffer[2]; + mUsrSysTime[0] = currUsrTimeUs - lastTimes[0]; + mUsrSysTime[1] = currSysTimeUs - lastTimes[1]; + + if (mUsrSysTime[0] < 0 || mUsrSysTime[1] < 0) { + Slog.e(mTag, "Negative user/sys time delta for UID=" + uid + + "\nPrev times: u=" + lastTimes[0] + " s=" + lastTimes[1] + + " Curr times: u=" + currUsrTimeUs + " s=" + currSysTimeUs); + } else if (mUsrSysTime[0] > 0 || mUsrSysTime[1] > 0) { + if (cb != null) { + cb.onUidCpuTime(uid, mUsrSysTime); + } + } + lastTimes[0] = currUsrTimeUs; + lastTimes[1] = currSysTimeUs; + } + } + } + + @Override + void readAbsoluteImpl(Callback<long[]> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (iter == null) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) < 3) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + mUsrSysTime[0] = mBuffer[1]; // User time in microseconds + mUsrSysTime[1] = mBuffer[2]; // System time in microseconds + cb.onUidCpuTime((int) mBuffer[0], mUsrSysTime); + } + } + } + + @Override + public void removeUid(int uid) { + super.removeUid(uid); + removeUidsFromKernelModule(uid, uid); + } + + @Override + public void removeUidsInRange(int startUid, int endUid) { + super.removeUidsInRange(startUid, endUid); + removeUidsFromKernelModule(startUid, endUid); + } + + /** + * Removes UIDs in a given range from the kernel module and internal accounting data. Only + * {@link BatteryStatsImpl} and its child processes should call this, as the change on + * Kernel is + * visible system wide. + * + * @param startUid the first uid to remove + * @param endUid the last uid to remove + */ + private void removeUidsFromKernelModule(int startUid, int endUid) { + Slog.d(mTag, "Removing uids " + startUid + "-" + endUid); + final int oldMask = StrictMode.allowThreadDiskWritesMask(); + try (FileWriter writer = new FileWriter(REMOVE_UID_PROC_FILE)) { + writer.write(startUid + "-" + endUid); + writer.flush(); + } catch (IOException e) { + Slog.e(mTag, "failed to remove uids " + startUid + " - " + endUid + + " from uid_cputime module", e); + } finally { + StrictMode.setThreadPolicyMask(oldMask); + } + } + } + + /** + * Reads /proc/uid_time_in_state which has the format: + * + * uid: [freq1] [freq2] [freq3] ... + * [uid1]: [time in freq1] [time in freq2] [time in freq3] ... + * [uid2]: [time in freq1] [time in freq2] [time in freq3] ... + * ... + * + * This provides the times a UID's processes spent executing at each different cpu frequency. + * The file contains a monotonically increasing count of time for a single boot. This class + * maintains the previous results of a call to {@link #readDelta} in order to provide a proper + * delta. + */ + public static class KernelCpuUidFreqTimeReader extends KernelCpuUidTimeReader<long[]> { + private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state"; + // We check the existence of proc file a few times (just in case it is not ready yet when we + // start reading) and if it is not available, we simply ignore further read requests. + private static final int MAX_ERROR_COUNT = 5; + + private final Path mProcFilePath; + private long[] mBuffer; + private long[] mCurTimes; + private long[] mDeltaTimes; + private long[] mCpuFreqs; + + private int mFreqCount = 0; + private int mErrors = 0; + private boolean mPerClusterTimesAvailable; + private boolean mAllUidTimesAvailable = true; + + public KernelCpuUidFreqTimeReader(boolean throttle) { + this(UID_TIMES_PROC_FILE, KernelCpuProcStringReader.getFreqTimeReaderInstance(), + throttle); + } + + @VisibleForTesting + public KernelCpuUidFreqTimeReader(String procFile, KernelCpuProcStringReader reader, + boolean throttle) { + super(reader, throttle); + mProcFilePath = Paths.get(procFile); + } + + /** + * @return Whether per-cluster times are available. + */ + public boolean perClusterTimesAvailable() { + return mPerClusterTimesAvailable; + } + + /** + * @return Whether all-UID times are available. + */ + public boolean allUidTimesAvailable() { + return mAllUidTimesAvailable; + } + + /** + * @return A map of all UIDs to their CPU time-in-state array in milliseconds. + */ + public SparseArray<long[]> getAllUidCpuFreqTimeMs() { + return mLastTimes; + } + + /** + * Reads a list of CPU frequencies from /proc/uid_time_in_state. Uses a given PowerProfile + * to determine if per-cluster times are available. + * + * @param powerProfile The PowerProfile to compare against. + * @return A long[] of CPU frequencies in Hz. + */ + public long[] readFreqs(@NonNull PowerProfile powerProfile) { + checkNotNull(powerProfile); + if (mCpuFreqs != null) { + // No need to read cpu freqs more than once. + return mCpuFreqs; + } + if (!mAllUidTimesAvailable) { + return null; + } + final int oldMask = StrictMode.allowThreadDiskReadsMask(); + try (BufferedReader reader = Files.newBufferedReader(mProcFilePath)) { + if (readFreqs(reader.readLine()) == null) { + return null; + } + } catch (IOException e) { + if (++mErrors >= MAX_ERROR_COUNT) { + mAllUidTimesAvailable = false; + } + Slog.e(mTag, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); + return null; + } finally { + StrictMode.setThreadPolicyMask(oldMask); + } + // Check if the freqs in the proc file correspond to per-cluster freqs. + final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs(); + final int numClusters = powerProfile.getNumCpuClusters(); + if (numClusterFreqs.size() == numClusters) { + mPerClusterTimesAvailable = true; + for (int i = 0; i < numClusters; ++i) { + if (numClusterFreqs.get(i) != powerProfile.getNumSpeedStepsInCpuCluster(i)) { + mPerClusterTimesAvailable = false; + break; + } + } + } else { + mPerClusterTimesAvailable = false; + } + Slog.i(mTag, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable); + return mCpuFreqs; + } + + private long[] readFreqs(String line) { + if (line == null) { + return null; + } + final String[] lineArray = line.split(" "); + if (lineArray.length <= 1) { + Slog.wtf(mTag, "Malformed freq line: " + line); + return null; + } + mFreqCount = lineArray.length - 1; + mCpuFreqs = new long[mFreqCount]; + mCurTimes = new long[mFreqCount]; + mDeltaTimes = new long[mFreqCount]; + mBuffer = new long[mFreqCount + 1]; + for (int i = 0; i < mFreqCount; ++i) { + mCpuFreqs[i] = Long.parseLong(lineArray[i + 1], 10); + } + return mCpuFreqs; + } + + @Override + void readDeltaImpl(@Nullable Callback<long[]> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (!checkPrecondition(iter)) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) != mBuffer.length) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + final int uid = (int) mBuffer[0]; + long[] lastTimes = mLastTimes.get(uid); + if (lastTimes == null) { + lastTimes = new long[mFreqCount]; + mLastTimes.put(uid, lastTimes); + } + copyToCurTimes(); + boolean notify = false; + boolean valid = true; + for (int i = 0; i < mFreqCount; i++) { + // Unit is 10ms. + mDeltaTimes[i] = mCurTimes[i] - lastTimes[i]; + if (mDeltaTimes[i] < 0) { + Slog.e(mTag, "Negative delta from freq time proc: " + mDeltaTimes[i]); + valid = false; + } + notify |= mDeltaTimes[i] > 0; + } + if (notify && valid) { + System.arraycopy(mCurTimes, 0, lastTimes, 0, mFreqCount); + if (cb != null) { + cb.onUidCpuTime(uid, mDeltaTimes); + } + } + } + } + } + + @Override + void readAbsoluteImpl(Callback<long[]> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (!checkPrecondition(iter)) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) != mBuffer.length) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + copyToCurTimes(); + cb.onUidCpuTime((int) mBuffer[0], mCurTimes); + } + } + } + + private void copyToCurTimes() { + for (int i = 0; i < mFreqCount; i++) { + mCurTimes[i] = mBuffer[i + 1] * 10; + } + } + + private boolean checkPrecondition(ProcFileIterator iter) { + if (iter == null || !iter.hasNextLine()) { + // Error logged in KernelCpuProcStringReader. + return false; + } + CharBuffer line = iter.nextLine(); + if (mCpuFreqs != null) { + return true; + } + return readFreqs(line.toString()) != null; + } + + /** + * Extracts no. of cpu clusters and no. of freqs in each of these clusters from the freqs + * read from the proc file. + * + * We need to assume that freqs in each cluster are strictly increasing. + * For e.g. if the freqs read from proc file are: 12, 34, 15, 45, 12, 15, 52. Then it means + * there are 3 clusters: (12, 34), (15, 45), (12, 15, 52) + * + * @return an IntArray filled with no. of freqs in each cluster. + */ + private IntArray extractClusterInfoFromProcFileFreqs() { + final IntArray numClusterFreqs = new IntArray(); + int freqsFound = 0; + for (int i = 0; i < mFreqCount; ++i) { + freqsFound++; + if (i + 1 == mFreqCount || mCpuFreqs[i + 1] <= mCpuFreqs[i]) { + numClusterFreqs.add(freqsFound); + freqsFound = 0; + } + } + return numClusterFreqs; + } + } + + /** + * Reads /proc/uid_concurrent_active_time and reports CPU active time to BatteryStats to + * compute {@link PowerProfile#POWER_CPU_ACTIVE}. + * + * /proc/uid_concurrent_active_time has the following format: + * cpus: n + * uid0: time0a, time0b, ..., time0n, + * uid1: time1a, time1b, ..., time1n, + * uid2: time2a, time2b, ..., time2n, + * ... + * where n is the total number of cpus (num_possible_cpus) + * timeXn means the CPU time that a UID X spent running concurrently with n other processes. + * + * The file contains a monotonically increasing count of time for a single boot. This class + * maintains the previous results of a call to {@link #readDelta} in order to provide a + * proper delta. + */ + public static class KernelCpuUidActiveTimeReader extends KernelCpuUidTimeReader<Long> { + private int mCores = 0; + private long[] mBuffer; + + public KernelCpuUidActiveTimeReader(boolean throttle) { + super(KernelCpuProcStringReader.getActiveTimeReaderInstance(), throttle); + } + + @VisibleForTesting + public KernelCpuUidActiveTimeReader(KernelCpuProcStringReader reader, boolean throttle) { + super(reader, throttle); + } + + @Override + void readDeltaImpl(@Nullable Callback<Long> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (!checkPrecondition(iter)) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) != mBuffer.length) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + int uid = (int) mBuffer[0]; + long cpuActiveTime = sumActiveTime(mBuffer); + if (cpuActiveTime > 0) { + long delta = cpuActiveTime - mLastTimes.get(uid, 0L); + if (delta > 0) { + mLastTimes.put(uid, cpuActiveTime); + if (cb != null) { + cb.onUidCpuTime(uid, delta); + } + } else if (delta < 0) { + Slog.e(mTag, "Negative delta from active time proc: " + delta); + } + } + } + } + } + + @Override + void readAbsoluteImpl(Callback<Long> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (!checkPrecondition(iter)) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) != mBuffer.length) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + long cpuActiveTime = sumActiveTime(mBuffer); + if (cpuActiveTime > 0) { + cb.onUidCpuTime((int) mBuffer[0], cpuActiveTime); + } + } + } + } + + private static long sumActiveTime(long[] times) { + // UID is stored at times[0]. + double sum = 0; + for (int i = 1; i < times.length; i++) { + sum += (double) times[i] * 10 / i; // Unit is 10ms. + } + return (long) sum; + } + + private boolean checkPrecondition(ProcFileIterator iter) { + if (iter == null || !iter.hasNextLine()) { + // Error logged in KernelCpuProcStringReader. + return false; + } + CharBuffer line = iter.nextLine(); + if (mCores > 0) { + return true; + } + + String str = line.toString(); + if (!str.startsWith("cpus:")) { + Slog.wtf(mTag, "Malformed uid_concurrent_active_time line: " + line); + return false; + } + int cores = Integer.parseInt(str.substring(5).trim(), 10); + if (cores <= 0) { + Slog.wtf(mTag, "Malformed uid_concurrent_active_time line: " + line); + return false; + } + mCores = cores; + mBuffer = new long[mCores + 1]; // UID is stored at mBuffer[0]. + return true; + } + } + + + /** + * Reads /proc/uid_concurrent_policy_time and reports CPU cluster times to BatteryStats to + * compute cluster power. See {@link PowerProfile#getAveragePowerForCpuCluster(int)}. + * + * /proc/uid_concurrent_policy_time has the following format: + * policyX: x policyY: y policyZ: z... + * uid1, time1a, time1b, ..., time1n, + * uid2, time2a, time2b, ..., time2n, + * ... + * The first line lists all policies (i.e. clusters) followed by # cores in each policy. + * Each uid is followed by x time entries corresponding to the time it spent on clusterX + * running concurrently with 0, 1, 2, ..., x - 1 other processes, then followed by y, z, ... + * time entries. + * + * The file contains a monotonically increasing count of time for a single boot. This class + * maintains the previous results of a call to {@link #readDelta} in order to provide a + * proper delta. + */ + public static class KernelCpuUidClusterTimeReader extends KernelCpuUidTimeReader<long[]> { + private int mNumClusters; + private int mNumCores; + private int[] mCoresOnClusters; // # cores on each cluster. + private long[] mBuffer; // To store data returned from ProcFileIterator. + private long[] mCurTime; + private long[] mDeltaTime; + + public KernelCpuUidClusterTimeReader(boolean throttle) { + super(KernelCpuProcStringReader.getClusterTimeReaderInstance(), throttle); + } + + @VisibleForTesting + public KernelCpuUidClusterTimeReader(KernelCpuProcStringReader reader, boolean throttle) { + super(reader, throttle); + } + + @Override + void readDeltaImpl(@Nullable Callback<long[]> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (!checkPrecondition(iter)) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) != mBuffer.length) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + int uid = (int) mBuffer[0]; + long[] lastTimes = mLastTimes.get(uid); + if (lastTimes == null) { + lastTimes = new long[mNumClusters]; + mLastTimes.put(uid, lastTimes); + } + sumClusterTime(); + boolean valid = true; + boolean notify = false; + for (int i = 0; i < mNumClusters; i++) { + mDeltaTime[i] = mCurTime[i] - lastTimes[i]; + if (mDeltaTime[i] < 0) { + Slog.e(mTag, "Negative delta from cluster time proc: " + mDeltaTime[i]); + valid = false; + } + notify |= mDeltaTime[i] > 0; + } + if (notify && valid) { + System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters); + if (cb != null) { + cb.onUidCpuTime(uid, mDeltaTime); + } + } + } + } + } + + @Override + void readAbsoluteImpl(Callback<long[]> cb) { + try (ProcFileIterator iter = mReader.open(!mThrottle)) { + if (!checkPrecondition(iter)) { + return; + } + CharBuffer buf; + while ((buf = iter.nextLine()) != null) { + if (asLongs(buf, mBuffer) != mBuffer.length) { + Slog.wtf(mTag, "Invalid line: " + buf.toString()); + continue; + } + sumClusterTime(); + cb.onUidCpuTime((int) mBuffer[0], mCurTime); + } + } + } + + private void sumClusterTime() { + // UID is stored at mBuffer[0]. + int core = 1; + for (int i = 0; i < mNumClusters; i++) { + double sum = 0; + for (int j = 1; j <= mCoresOnClusters[i]; j++) { + sum += (double) mBuffer[core++] * 10 / j; // Unit is 10ms. + } + mCurTime[i] = (long) sum; + } + } + + private boolean checkPrecondition(ProcFileIterator iter) { + if (iter == null || !iter.hasNextLine()) { + // Error logged in KernelCpuProcStringReader. + return false; + } + CharBuffer line = iter.nextLine(); + if (mNumClusters > 0) { + return true; + } + // Parse # cores in clusters. + String[] lineArray = line.toString().split(" "); + if (lineArray.length % 2 != 0) { + Slog.wtf(mTag, "Malformed uid_concurrent_policy_time line: " + line); + return false; + } + int[] clusters = new int[lineArray.length / 2]; + int cores = 0; + for (int i = 0; i < clusters.length; i++) { + if (!lineArray[i * 2].startsWith("policy")) { + Slog.wtf(mTag, "Malformed uid_concurrent_policy_time line: " + line); + return false; + } + clusters[i] = Integer.parseInt(lineArray[i * 2 + 1], 10); + cores += clusters[i]; + } + mNumClusters = clusters.length; + mNumCores = cores; + mCoresOnClusters = clusters; + mBuffer = new long[cores + 1]; + mCurTime = new long[mNumClusters]; + mDeltaTime = new long[mNumClusters]; + return true; + } + } + +} diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 9a7094accfae..69ba07090284 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -66,7 +66,7 @@ interface IStatusBarService void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded); void onNotificationDirectReplied(String key); void onNotificationSmartRepliesAdded(in String key, in int replyCount); - void onNotificationSmartReplySent(in String key, in int replyIndex); + void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply, boolean generatedByAssistant); void onNotificationSettingsViewed(String key); void setSystemUiVisibility(int vis, int mask, String cause); diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index 5da587bea22e..344d7ef8c83f 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -63,7 +63,7 @@ public class XmlUtils { public static final int convertValueToList(CharSequence value, String[] options, int defaultValue) { - if (null != value) { + if (!TextUtils.isEmpty(value)) { for (int i = 0; i < options.length; i++) { if (value.equals(options[i])) return i; @@ -79,8 +79,9 @@ public class XmlUtils { { boolean result = false; - if (null == value) + if (TextUtils.isEmpty(value)) { return defaultValue; + } if (value.equals("1") || value.equals("true") @@ -94,8 +95,9 @@ public class XmlUtils { public static final int convertValueToInt(CharSequence charSeq, int defaultValue) { - if (null == charSeq) + if (TextUtils.isEmpty(charSeq)) { return defaultValue; + } String nm = charSeq.toString(); @@ -138,7 +140,7 @@ public class XmlUtils { } public static int convertValueToUnsignedInt(String value, int defaultValue) { - if (null == value) { + if (TextUtils.isEmpty(value)) { return defaultValue; } @@ -1674,7 +1676,7 @@ public class XmlUtils { public static boolean readBooleanAttribute(XmlPullParser in, String name, boolean defaultValue) { final String value = in.getAttributeValue(null, name); - if (value == null) { + if (TextUtils.isEmpty(value)) { return defaultValue; } else { return Boolean.parseBoolean(value); @@ -1711,7 +1713,7 @@ public class XmlUtils { public static byte[] readByteArrayAttribute(XmlPullParser in, String name) { final String value = in.getAttributeValue(null, name); - if (value != null) { + if (!TextUtils.isEmpty(value)) { return Base64.decode(value, Base64.DEFAULT); } else { return null; diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 15745e929c4b..849585004bc3 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Environment; import android.os.Process; +import android.os.SystemProperties; import android.os.storage.StorageManager; import android.permission.PermissionManager.SplitPermissionInfo; import android.text.TextUtils; @@ -930,6 +931,16 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); } } + // If the storage model feature flag is disabled, we need to fiddle + // around with permission definitions to return us to pre-Q behavior. + // STOPSHIP(b/112545973): remove once feature enabled by default + if (!SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)) { + if (newPermissions.contains(android.Manifest.permission.READ_MEDIA_AUDIO) || + newPermissions.contains(android.Manifest.permission.READ_MEDIA_VIDEO) || + newPermissions.contains(android.Manifest.permission.READ_MEDIA_IMAGES)) { + return; + } + } if (!newPermissions.isEmpty()) { mSplitPermissions.add(new SplitPermissionInfo(splitPerm, newPermissions, targetSdk)); } diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index eada69097d05..bc1d5cc7e1c6 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -1450,8 +1450,8 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), REG_JNI(register_android_hardware_location_ActivityRecognitionHardware), - REG_JNI(register_android_media_AudioRecord), REG_JNI(register_android_media_AudioSystem), + REG_JNI(register_android_media_AudioRecord), REG_JNI(register_android_media_AudioTrack), REG_JNI(register_android_media_JetPlayer), REG_JNI(register_android_media_MicrophoneInfo), diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index 68f5bef18de1..ed6a84b35670 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -64,11 +64,10 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j jint tileModeX, jint tileModeY) { const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); sk_sp<SkImage> image; - sk_sp<SkColorFilter> colorFilter; if (jbitmap) { // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. - image = android::bitmap::toBitmap(env, jbitmap).makeImage(&colorFilter); + image = android::bitmap::toBitmap(env, jbitmap).makeImage(); } if (!image.get()) { @@ -81,9 +80,6 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j if (matrix) { shader = shader->makeWithLocalMatrix(*matrix); } - if(colorFilter) { - shader = shader->makeWithColorFilter(colorFilter); - } ThrowIAE_IfNull(env, shader.get()); return reinterpret_cast<jlong>(shader.release()); diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index e02741fc12c8..719cf74a451d 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -514,14 +514,14 @@ static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobjec sp<ANativeWindow> anw; if ((anw = getNativeWindow(env, surface)) == NULL) { - jniThrowException(env, "java/lang/UnsupportedOperationException;", + jniThrowException(env, "java/lang/UnsupportedOperationException", "Could not retrieve native window from surface."); return BAD_VALUE; } int32_t usage = 0; status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage); if(err != NO_ERROR) { - jniThrowException(env, "java/lang/UnsupportedOperationException;", + jniThrowException(env, "java/lang/UnsupportedOperationException", "Error while querying surface usage bits"); OVERRIDE_SURFACE_ERROR(err); return err; @@ -542,7 +542,7 @@ static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA); if(err != NO_ERROR) { - jniThrowException(env, "java/lang/UnsupportedOperationException;", + jniThrowException(env, "java/lang/UnsupportedOperationException", "Error while disconnecting surface"); OVERRIDE_SURFACE_ERROR(err); return err; diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp index 5887fa7a0841..10005ddcb5ef 100644 --- a/core/jni/android_hardware_input_InputApplicationHandle.cpp +++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp @@ -22,6 +22,7 @@ #include <utils/threads.h> #include "android_hardware_input_InputApplicationHandle.h" +#include "android_util_Binder.h" namespace android { @@ -29,6 +30,7 @@ static struct { jfieldID ptr; jfieldID name; jfieldID dispatchingTimeoutNanos; + jfieldID token; } gInputApplicationHandleClassInfo; static Mutex gHandleMutex; @@ -75,6 +77,15 @@ bool NativeInputApplicationHandle::updateInfo() { mInfo->dispatchingTimeout = env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos); + jobject tokenObj = env->GetObjectField(obj, + gInputApplicationHandleClassInfo.token); + if (tokenObj) { + mInfo->token = ibinderForJavaObject(env, tokenObj); + env->DeleteLocalRef(tokenObj); + } else { + mInfo->token.clear(); + } + env->DeleteLocalRef(obj); return true; } @@ -153,6 +164,9 @@ int register_android_server_InputApplicationHandle(JNIEnv* env) { clazz, "dispatchingTimeoutNanos", "J"); + GET_FIELD_ID(gInputApplicationHandleClassInfo.token, clazz, + "token", "Landroid/os/IBinder;"); + return 0; } diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index 6ecb5de35ae1..76920f57ed08 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -21,19 +21,19 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/threads.h> -#include <android_view_InputChannel.h> #include <android/graphics/Region.h> #include <ui/Region.h> #include "android_hardware_input_InputWindowHandle.h" #include "android_hardware_input_InputApplicationHandle.h" +#include "android_util_Binder.h" namespace android { static struct { jfieldID ptr; jfieldID inputApplicationHandle; - jfieldID inputChannel; + jfieldID token; jfieldID name; jfieldID layoutParamsFlags; jfieldID layoutParamsType; @@ -42,6 +42,7 @@ static struct { jfieldID frameTop; jfieldID frameRight; jfieldID frameBottom; + jfieldID surfaceInset; jfieldID scaleFactor; jfieldID touchableRegion; jfieldID visible; @@ -61,9 +62,7 @@ static Mutex gHandleMutex; // --- NativeInputWindowHandle --- -NativeInputWindowHandle::NativeInputWindowHandle( - const sp<InputApplicationHandle>& inputApplicationHandle, jweak objWeak) : - InputWindowHandle(inputApplicationHandle), +NativeInputWindowHandle::NativeInputWindowHandle(jweak objWeak) : mObjWeak(objWeak) { } @@ -86,13 +85,12 @@ bool NativeInputWindowHandle::updateInfo() { mInfo.touchableRegion.clear(); - jobject inputChannelObj = env->GetObjectField(obj, - gInputWindowHandleClassInfo.inputChannel); - if (inputChannelObj) { - mInfo.inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); - env->DeleteLocalRef(inputChannelObj); + jobject tokenObj = env->GetObjectField(obj, + gInputWindowHandleClassInfo.token); + if (tokenObj) { + mInfo.token = ibinderForJavaObject(env, tokenObj); } else { - mInfo.inputChannel.clear(); + mInfo.token.clear(); } jstring nameObj = jstring(env->GetObjectField(obj, @@ -120,7 +118,9 @@ bool NativeInputWindowHandle::updateInfo() { gInputWindowHandleClassInfo.frameRight); mInfo.frameBottom = env->GetIntField(obj, gInputWindowHandleClassInfo.frameBottom); - mInfo.scaleFactor = env->GetFloatField(obj, + mInfo.surfaceInset = env->GetIntField(obj, + gInputWindowHandleClassInfo.surfaceInset); + mInfo.globalScaleFactor = env->GetFloatField(obj, gInputWindowHandleClassInfo.scaleFactor); jobject regionObj = env->GetObjectField(obj, @@ -155,6 +155,18 @@ bool NativeInputWindowHandle::updateInfo() { mInfo.displayId = env->GetIntField(obj, gInputWindowHandleClassInfo.displayId); + jobject inputApplicationHandleObj = env->GetObjectField(obj, + gInputWindowHandleClassInfo.inputApplicationHandle); + if (inputApplicationHandleObj) { + sp<InputApplicationHandle> inputApplicationHandle = + android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); + if (inputApplicationHandle != nullptr) { + inputApplicationHandle->updateInfo(); + mInfo.applicationInfo = *(inputApplicationHandle->getInfo()); + } + env->DeleteLocalRef(inputApplicationHandleObj); + } + env->DeleteLocalRef(obj); return true; } @@ -175,14 +187,8 @@ sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( if (ptr) { handle = reinterpret_cast<NativeInputWindowHandle*>(ptr); } else { - jobject inputApplicationHandleObj = env->GetObjectField(inputWindowHandleObj, - gInputWindowHandleClassInfo.inputApplicationHandle); - sp<InputApplicationHandle> inputApplicationHandle = - android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); - env->DeleteLocalRef(inputApplicationHandleObj); - jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj); - handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak); + handle = new NativeInputWindowHandle(objWeak); handle->incStrong((void*)android_server_InputWindowHandle_getHandle); env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr, reinterpret_cast<jlong>(handle)); @@ -236,8 +242,8 @@ int register_android_server_InputWindowHandle(JNIEnv* env) { clazz, "inputApplicationHandle", "Landroid/view/InputApplicationHandle;"); - GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz, - "inputChannel", "Landroid/view/InputChannel;"); + GET_FIELD_ID(gInputWindowHandleClassInfo.token, clazz, + "token", "Landroid/os/IBinder;"); GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz, "name", "Ljava/lang/String;"); @@ -263,6 +269,9 @@ int register_android_server_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz, "frameBottom", "I"); + GET_FIELD_ID(gInputWindowHandleClassInfo.surfaceInset, clazz, + "surfaceInset", "I"); + GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz, "scaleFactor", "F"); diff --git a/core/jni/android_hardware_input_InputWindowHandle.h b/core/jni/android_hardware_input_InputWindowHandle.h index 2be267e958ec..54b89f5b7918 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.h +++ b/core/jni/android_hardware_input_InputWindowHandle.h @@ -26,8 +26,7 @@ namespace android { class NativeInputWindowHandle : public InputWindowHandle { public: - NativeInputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle, - jweak objWeak); + NativeInputWindowHandle(jweak objWeak); virtual ~NativeInputWindowHandle(); jobject getInputWindowHandleObjLocalRef(JNIEnv* env); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 7410b5235060..adab8e2bae39 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -175,6 +175,17 @@ static struct { jmethodID postRecordConfigEventFromNative; } gAudioPolicyEventHandlerMethods; +// +// JNI Initialization for OpenSLES routing +// +jmethodID gMidAudioTrackRoutingProxy_ctor; +jmethodID gMidAudioTrackRoutingProxy_release; +jmethodID gMidAudioRecordRoutingProxy_ctor; +jmethodID gMidAudioRecordRoutingProxy_release; + +jclass gClsAudioTrackRoutingProxy; +jclass gClsAudioRecordRoutingProxy; + static Mutex gLock; enum AudioError { @@ -2017,6 +2028,39 @@ android_media_AudioSystem_setSurroundFormatEnabled(JNIEnv *env, jobject thiz, return (jint)nativeToJavaStatus(status); } +static jint android_media_AudioSystem_get_FCC_8(JNIEnv *env, jobject thiz) { + return FCC_8; +} + +static jint +android_media_AudioSystem_setAssistantUid(JNIEnv *env, jobject thiz, jint uid) +{ + status_t status = AudioSystem::setAssistantUid(uid); + return (jint)nativeToJavaStatus(status); +} + +static jint +android_media_AudioSystem_setA11yServicesUids(JNIEnv *env, jobject thiz, jintArray uids) { + std::vector<uid_t> nativeUidsVector; + + if (uids != nullptr) { + jsize len = env->GetArrayLength(uids); + + if (len > 0) { + int *nativeUids = nullptr; + nativeUids = env->GetIntArrayElements(uids, 0); + if (nativeUids != nullptr) { + for (size_t i = 0; i < len; i++) { + nativeUidsVector.push_back(nativeUids[i]); + } + env->ReleaseIntArrayElements(uids, nativeUids, 0); + } + } + } + status_t status = AudioSystem::setA11yServicesUids(nativeUidsVector); + return (jint)nativeToJavaStatus(status); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { @@ -2077,9 +2121,10 @@ static const JNINativeMethod gMethods[] = { {"getMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioSystem_getMicrophones}, {"getSurroundFormats", "(Ljava/util/Map;Z)I", (void *)android_media_AudioSystem_getSurroundFormats}, {"setSurroundFormatEnabled", "(IZ)I", (void *)android_media_AudioSystem_setSurroundFormatEnabled}, + {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid}, + {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids}, }; - static const JNINativeMethod gEventHandlerMethods[] = { {"native_setup", "(Ljava/lang/Object;)V", @@ -2089,8 +2134,15 @@ static const JNINativeMethod gEventHandlerMethods[] = { (void *)android_media_AudioSystem_eventHandlerFinalize}, }; +static const JNINativeMethod gGetFCC8Methods[] = { + {"native_get_FCC_8", "()I", (void *)android_media_AudioSystem_get_FCC_8}, +}; + int register_android_media_AudioSystem(JNIEnv *env) { + // This needs to be done before hooking up methods AudioTrackRoutingProxy (below) + RegisterMethodsOrDie(env, kClassPathName, gGetFCC8Methods, NELEM(gGetFCC8Methods)); + jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z"); @@ -2247,6 +2299,28 @@ int register_android_media_AudioSystem(JNIEnv *env) gAudioAttributesFields.mFormattedTags = GetFieldIDOrDie(env, audioAttributesClass, "mFormattedTags", "Ljava/lang/String;"); + // AudioTrackRoutingProxy methods + gClsAudioTrackRoutingProxy = + android::FindClassOrDie(env, "android/media/AudioTrackRoutingProxy"); + // make sure this reference doesn't get deleted + gClsAudioTrackRoutingProxy = (jclass)env->NewGlobalRef(gClsAudioTrackRoutingProxy); + + gMidAudioTrackRoutingProxy_ctor = + android::GetMethodIDOrDie(env, gClsAudioTrackRoutingProxy, "<init>", "(J)V"); + gMidAudioTrackRoutingProxy_release = + android::GetMethodIDOrDie(env, gClsAudioTrackRoutingProxy, "native_release", "()V"); + + // AudioRecordRoutingProxy + gClsAudioRecordRoutingProxy = + android::FindClassOrDie(env, "android/media/AudioRecordRoutingProxy"); + // make sure this reference doesn't get deleted + gClsAudioRecordRoutingProxy = (jclass)env->NewGlobalRef(gClsAudioRecordRoutingProxy); + + gMidAudioRecordRoutingProxy_ctor = + android::GetMethodIDOrDie(env, gClsAudioRecordRoutingProxy, "<init>", "(J)V"); + gMidAudioRecordRoutingProxy_release = + android::GetMethodIDOrDie(env, gClsAudioRecordRoutingProxy, "native_release", "()V"); + AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback); RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index bf22dd21516b..04f0a53dd53b 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -1226,10 +1226,6 @@ static void android_media_AudioTrack_disableDeviceCallback( pJniStorage->mDeviceCallback.clear(); } -static jint android_media_AudioTrack_get_FCC_8(JNIEnv *env, jobject thiz) { - return FCC_8; -} - // Pass through the arguments to the AudioFlinger track implementation. static jint android_media_AudioTrack_apply_volume_shaper(JNIEnv *env, jobject thiz, jobject jconfig, jobject joperation) { @@ -1351,7 +1347,6 @@ static const JNINativeMethod gMethods[] = { {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId}, {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback}, {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback}, - {"native_get_FCC_8", "()I", (void *)android_media_AudioTrack_get_FCC_8}, {"native_applyVolumeShaper", "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I", (void *)android_media_AudioTrack_apply_volume_shaper}, diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 7de8020c4d32..d917536b1715 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -550,6 +550,10 @@ message GlobalSettingsProto { } optional MultiSim multi_sim = 76; + // Whether we've enabled native flags health check on this device. Takes effect on + // reboot. The value "1" enables native flags health check; otherwise it's disabled. + optional SettingProto native_flags_health_check_enabled = 144 [ (android.privacy).dest = DEST_AUTOMATIC ]; + message Netstats { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -987,5 +991,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 144; + // Next tag = 145; } diff --git a/core/proto/android/stats/devicepolicy/Android.bp b/core/proto/android/stats/devicepolicy/Android.bp new file mode 100644 index 000000000000..6ae54e23117d --- /dev/null +++ b/core/proto/android/stats/devicepolicy/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +java_library_static { + name: "devicepolicyprotosnano", + proto: { + type: "nano", + }, + srcs: [ + "*.proto", + ], + java_version: "1.8", + target: { + android: { + jarjar_rules: "jarjar-rules.txt", + }, + host: { + static_libs: ["libprotobuf-java-nano"], + } + }, + no_framework_libs: true, +} diff --git a/core/proto/android/stats/devicepolicy/device_policy.proto b/core/proto/android/stats/devicepolicy/device_policy.proto new file mode 100644 index 000000000000..af30cf3f9941 --- /dev/null +++ b/core/proto/android/stats/devicepolicy/device_policy.proto @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +package android.stats.devicepolicy; +option java_multiple_files = true; + +message StringList { + repeated string string_value = 1; +} diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto new file mode 100644 index 000000000000..8fbea12a8fb9 --- /dev/null +++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +package android.stats.devicepolicy; +option java_multiple_files = true; + +/** + * Id for device policy features. + */ +enum EventId { + SET_PASSWORD_QUALITY = 1; + SET_PASSWORD_MINIMUM_LENGTH = 2; + SET_PASSWORD_MINIMUM_NUMERIC = 3; + SET_PASSWORD_MINIMUM_NON_LETTER = 4; + SET_PASSWORD_MINIMUM_LETTERS = 5; + SET_PASSWORD_MINIMUM_LOWER_CASE = 6; + SET_PASSWORD_MINIMUM_UPPER_CASE = 7; + SET_PASSWORD_MINIMUM_SYMBOLS = 8; + SET_KEYGUARD_DISABLED_FEATURES = 9; + LOCK_NOW = 10; + WIPE_DATA_WITH_REASON = 11; + ADD_USER_RESTRICTION = 12; + REMOVE_USER_RESTRICTION = 13; + SET_SECURE_SETTING = 14; + SET_SECURITY_LOGGING_ENABLED = 15; + RETRIEVE_SECURITY_LOGS = 16; + RETRIEVE_PRE_REBOOT_SECURITY_LOGS = 17; + SET_PERMISSION_POLICY = 18; + SET_PERMISSION_GRANT_STATE = 19; + INSTALL_KEY_PAIR = 20; + INSTALL_CA_CERT = 21; + ON_CHOOSE_KEY_ALIAS = 22; + REMOVE_KEY_PAIR = 23; + UNINSTALL_CA_CERTS = 24; + SET_CERT_INSTALLER_PACKAGE = 25; + SET_ALWAYS_ON_VPN_PACKAGE = 26; + SET_PERMITTED_INPUT_METHODS = 27; + SET_PERMITTED_ACCESSIBILITY_SERVICES = 28; + SET_SCREEN_CAPTURE_DISABLE = 29; + SET_CAMERA_DISABLED = 30; + QUERY_SUMMARY_FOR_USER = 31; + QUERY_SUMMARY = 32; + QUERY_DETAILS = 33; + REBOOT = 34; + SET_MASTER_VOLUME_MUTED = 35; + SET_AUTO_TIME_REQUIRED = 36; + SET_KEYGUARD_DISABLED = 37; + SET_STATUS_BAR_DISABLED = 38; + SET_ORGANIZATION_COLOR = 39; + SET_PROFILE_NAME = 40; + SET_USER_ICON = 41; + SET_DEVICE_OWNER_LOCKSCREEN_INFO = 42; + SET_SHORT_SUPPORT_MESSAGE = 43; + SET_LONG_SUPPORT_MESSAGE = 44; + SET_CROSS_PROFILE_CONTACTS_SEARCH_DISABLED = 45; + SET_CROSS_PROFILE_CALLER_DISABLED = 46; + SET_BLUETOOTH_CONTACT_SHARING_DISABLED = 47; + ADD_CROSS_PROFILE_INTENT_FILTER = 48; + ADD_CROSS_PROFILE_WIDGET_PROVIDER = 49; + SET_SYSTEM_UPDATE_POLICY = 50; + SET_LOCKTASK_PACKAGES = 51; + ADD_PERSISTENT_PREFERRED_ACTIVITY = 52; + REQUEST_BUGREPORT = 53; + GET_WIFI_MAC_ADDRESS = 54; + REQUEST_QUIET_MODE_ENABLED = 55; + WORK_PROFILE_LOCATION_CHANGED = 56; + DO_USER_INFO_CLICKED = 57; + TRANSFER_OWNERSHIP = 58; + GENERATE_KEY_PAIR = 59; + SET_KEY_PAIR_CERTIFICATE = 60; + SET_KEEP_UNINSTALLED_PACKAGES = 61; + SET_APPLICATION_RESTRICTIONS = 62; + SET_APPLICATION_HIDDEN = 63; + ENABLE_SYSTEM_APP = 64; + ENABLE_SYSTEM_APP_WITH_INTENT = 65; + INSTALL_EXISTING_PACKAGE = 66; + SET_UNINSTALL_BLOCKED = 67; + SET_PACKAGES_SUSPENDED = 68; + ON_LOCK_TASK_MODE_ENTERING = 69; + ADD_CROSS_PROFILE_CALENDAR_PACKAGE = 70; + REMOVE_CROSS_PROFILE_CALENDAR_PACKAGE = 71; + GET_USER_PASSWORD_COMPLEXITY_LEVEL = 72; + INSTALL_SYSTEM_UPDATE = 73; + INSTALL_SYSTEM_UPDATE_ERROR = 74; + IS_MANAGED_KIOSK = 75; + IS_UNATTENDED_MANAGED_KIOSK = 76; + PROVISIONING_TO_COMP = 77; + PROVISIONING_FORCED_DO = 78; + + // existing Tron logs to be migrated to WestWorld + PROVISIONING_ENTRY_POINT_NFC = 79; + PROVISIONING_ENTRY_POINT_QR_CODE = 80; + PROVISIONING_ENTRY_POINT_ZERO_TOUCH = 81; + PROVISIONING_ENTRY_POINT_ADB = 82; + PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE = 83; + PROVISIONING_DPC_PACKAGE_NAME = 84; + PROVISIONING_DPC_INSTALLED_BY_PACKAGE = 85; + PROVISIONING_PROVISIONING_ACTIVITY_TIME_MS = 86; + PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS = 87; + PROVISIONING_ENCRYPT_DEVICE_ACTIVITY_TIME_MS = 88; + PROVISIONING_WEB_ACTIVITY_TIME_MS = 89; + PROVISIONING_TRAMPOLINE_ACTIVITY_TIME_MS = 90; + PROVISIONING_POST_ENCRYPTION_ACTIVITY_TIME_MS = 91; + PROVISIONING_FINALIZATION_ACTIVITY_TIME_MS = 92; + PROVISIONING_NETWORK_TYPE = 93; + PROVISIONING_ACTION = 94; + PROVISIONING_EXTRAS = 95; + PROVISIONING_COPY_ACCOUNT_TASK_MS = 96; + PROVISIONING_CREATE_PROFILE_TASK_MS = 97; + PROVISIONING_START_PROFILE_TASK_MS = 98; + PROVISIONING_DOWNLOAD_PACKAGE_TASK_MS = 99; + PROVISIONING_INSTALL_PACKAGE_TASK_MS = 100; + PROVISIONING_CANCELLED = 101; + PROVISIONING_ERROR = 102; + PROVISIONING_COPY_ACCOUNT_STATUS = 103; + PROVISIONING_TOTAL_TASK_TIME_MS = 104; + PROVISIONING_SESSION_STARTED = 105; + PROVISIONING_SESSION_COMPLETED = 106; + PROVISIONING_TERMS_ACTIVITY_TIME_MS = 107; + PROVISIONING_TERMS_COUNT = 108; + PROVISIONING_TERMS_READ = 109; +} diff --git a/core/proto/android/stats/devicepolicy/jarjar-rules.txt b/core/proto/android/stats/devicepolicy/jarjar-rules.txt new file mode 100644 index 000000000000..40043a861ceb --- /dev/null +++ b/core/proto/android/stats/devicepolicy/jarjar-rules.txt @@ -0,0 +1 @@ +rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1 diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e064423a9bb9..8c5b6f4765fb 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -794,7 +794,8 @@ <permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:label="@string/permlab_sdcardRead" android:description="@string/permdesc_sdcardRead" - android:protectionLevel="normal" /> + android:protectionLevel="dangerous" + android:permissionFlags="removed" /> <!-- Allows an application to write to external storage. <p class="note"><strong>Note:</strong> If <em>both</em> your <a @@ -814,7 +815,8 @@ <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:label="@string/permlab_sdcardWrite" android:description="@string/permdesc_sdcardWrite" - android:protectionLevel="normal" /> + android:protectionLevel="dangerous" + android:permissionFlags="removed" /> <!-- Runtime permission controlling access to the user's shared aural media collection. --> @@ -831,12 +833,6 @@ android:description="@string/permdesc_audioRead" android:protectionLevel="dangerous" /> - <!-- Allows an application to modify the user's shared audio collection. --> - <permission android:name="android.permission.WRITE_MEDIA_AUDIO" - android:label="@string/permlab_audioWrite" - android:description="@string/permdesc_audioWrite" - android:protectionLevel="dangerous" /> - <!-- Runtime permission controlling access to the user's shared visual media collection, including images and videos. --> <permission-group android:name="android.permission-group.MEDIA_VISUAL" @@ -852,24 +848,12 @@ android:description="@string/permdesc_imagesRead" android:protectionLevel="dangerous" /> - <!-- Allows an application to modify the user's shared images collection. --> - <permission android:name="android.permission.WRITE_MEDIA_IMAGES" - android:label="@string/permlab_imagesWrite" - android:description="@string/permdesc_imagesWrite" - android:protectionLevel="dangerous" /> - <!-- Allows an application to read the user's shared video collection. --> <permission android:name="android.permission.READ_MEDIA_VIDEO" android:label="@string/permlab_videoRead" android:description="@string/permdesc_videoRead" android:protectionLevel="dangerous" /> - <!-- Allows an application to modify the user's shared video collection. --> - <permission android:name="android.permission.WRITE_MEDIA_VIDEO" - android:label="@string/permlab_videoWrite" - android:description="@string/permdesc_videoWrite" - android:protectionLevel="dangerous" /> - <!-- Allows an application to access any geographic locations persisted in the user's shared collection. --> <permission android:name="android.permission.ACCESS_MEDIA_LOCATION" @@ -3024,6 +3008,13 @@ <permission android:name="android.permission.BIND_TV_INPUT" android:protectionLevel="signature|privileged" /> + <!-- Must be required by an {@link android.service.sms.FinancialSmsService} + to ensure that only the system can bind to it. + @hide This is not a third-party API (intended for OEMs and system apps). + --> + <permission android:name="android.permission.BIND_FINANCIAL_SMS_SERVICE" + android:protectionLevel="signature" /> + <!-- @SystemApi Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider} to ensure that only the system can bind to it. diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml index 3c9f6eecc7d6..c024dbed56c0 100644 --- a/core/res/res/layout/notification_material_action.xml +++ b/core/res/res/layout/notification_material_action.xml @@ -16,16 +16,14 @@ --> <Button xmlns:android="http://schemas.android.com/apk/res/android" - style="@android:style/Widget.Material.Light.Button.Borderless.Small" + style="@android:style/NotificationAction" android:id="@+id/action0" android:layout_width="wrap_content" android:layout_height="48dp" android:layout_gravity="center" android:gravity="start|center_vertical" android:layout_marginStart="4dp" - android:textColor="@color/notification_default_color" android:singleLine="true" android:textAlignment="viewStart" android:ellipsize="end" - android:background="@drawable/notification_material_action_background" /> diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml index 07559f439933..425801991927 100644 --- a/core/res/res/layout/notification_material_action_list.xml +++ b/core/res/res/layout/notification_material_action_list.xml @@ -18,6 +18,7 @@ android:id="@+id/actions_container" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="@dimen/notification_action_list_margin_top" android:layout_gravity="bottom"> <com.android.internal.widget.NotificationActionListLayout android:id="@+id/actions" @@ -27,6 +28,7 @@ android:orientation="horizontal" android:gravity="center_vertical" android:visibility="gone" + android:background="@color/notification_action_list_background_color" > <!-- actions will be added here --> </com.android.internal.widget.NotificationActionListLayout> diff --git a/core/res/res/layout/notification_material_action_tombstone.xml b/core/res/res/layout/notification_material_action_tombstone.xml index 9fa7c6a28020..f16572486df1 100644 --- a/core/res/res/layout/notification_material_action_tombstone.xml +++ b/core/res/res/layout/notification_material_action_tombstone.xml @@ -16,7 +16,7 @@ --> <Button xmlns:android="http://schemas.android.com/apk/res/android" - style="@android:style/Widget.Material.Light.Button.Borderless.Small" + style="@android:style/NotificationTombstoneAction" android:id="@+id/action0" android:layout_width="wrap_content" android:layout_height="48dp" diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml index 9de8842ae5da..a2ad3b90e464 100644 --- a/core/res/res/values-night/values.xml +++ b/core/res/res/values-night/values.xml @@ -20,7 +20,7 @@ <!-- Color palette --> <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> <item name="colorSecondary">@color/secondary_device_default_settings</item> - <item name="colorAccent">@color/white</item> + <item name="colorAccent">@color/accent_device_default_dark</item> <item name="colorError">@color/error_color_device_default_dark</item> <item name="colorControlNormal">?attr/textColorPrimary</item> <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 605662a91db2..6c4861b34429 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7941,6 +7941,11 @@ <!-- Uri that specifies a settings Slice for this wallpaper. --> <attr name="settingsSliceUri" /> + <!-- Indicates that this wallpaper service can support multiple engines to render on each + surface independently. An example use case is a multi-display set-up where the + wallpaper service can render surfaces to each of the connected displays. --> + <attr name="supportsMultipleDisplays" format="boolean" /> + </declare-styleable> <!-- Use <code>dream</code> as the root tag of the XML resource that diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 6fc0f5b33a36..18d1d5dbdbe3 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2148,6 +2148,21 @@ <attr name="visibleToInstantApps" /> <!-- The code for this component is located in the given split. --> <attr name="splitName" /> + <!-- If true, and this is an {@link android.R.attr#isolatedProcess} service, the service + will be spawned from an Application Zygote, instead of the regular Zygote. + <p> + The Application Zygote will pre-initialize the application's class loader, + and call a static callback into the application to allow it to perform + application-specific preloads (such as loading a shared library). Therefore, + spawning from the Application Zygote will typically reduce the service + launch time and reduce its memory usage. The downside of using this flag + is that you will have an additional process (the app zygote itself) that + is taking up memory. Whether actual memory usage is improved therefore strongly + depends on the number of isolated services that an application starts, + and how much memory those services save by preloading. Therefore, it is + recommended to measure memory usage under typical workloads to determine + whether it makes sense to use this flag. --> + <attr name="useAppZygote" format="boolean" /> </declare-styleable> <!-- The <code>receiver</code> tag declares an diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 4122cf02ad20..16c074484e2c 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -146,10 +146,14 @@ <color name="notification_default_color">#757575</color> <!-- Gray 600 --> + <color name="notification_action_button_text_color">@color/notification_default_color</color> + <color name="notification_progress_background_color">@color/secondary_text_material_light</color> <color name="notification_action_list">#ffeeeeee</color> + <color name="notification_action_list_background_color">@null</color> + <!-- Keyguard colors --> <color name="keyguard_avatar_frame_color">#ffffffff</color> <color name="keyguard_avatar_frame_shadow_color">#80000000</color> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index e902989094f2..f7b9961c39e8 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -200,6 +200,9 @@ <!-- The height of the notification action list --> <dimen name="notification_action_list_height">60dp</dimen> + <!-- The margin of the notification action list at the top --> + <dimen name="notification_action_list_margin_top">0dp</dimen> + <!-- The height of the notification action list --> <dimen name="notification_action_emphasized_height">48dp</dimen> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 73dae0801b8e..63cac5172f8a 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2920,6 +2920,8 @@ <public name="shell" /> <public name="interactiveUiTimeout" /> <public name="importantForContentCapture" /> + <public name="supportsMultipleDisplays" /> + <public name="useAppZygote" /> </public-group> <public-group type="drawable" first-id="0x010800b4"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 200c35d67b17..bd6d97622a4d 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1586,22 +1586,14 @@ <string name="permdesc_readSyncStats">Allows an app to read the sync stats for an account, including the history of sync events and how much data is synced. </string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] --> - <string name="permlab_sdcardRead" product="nosdcard">read the contents of your USB storage</string> - <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_sdcardRead" product="default">read the contents of your SD card</string> + <string name="permlab_sdcardRead">read the contents of your shared storage</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] --> - <string name="permdesc_sdcardRead" product="nosdcard">Allows the app to read the contents of your USB storage.</string> - <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_sdcardRead" product="default">Allows the app to read the contents of your SD card.</string> + <string name="permdesc_sdcardRead">Allows the app to read the contents of your shared storage.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] --> - <string name="permlab_sdcardWrite" product="nosdcard">modify or delete the contents of your USB storage</string> - <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_sdcardWrite" product="default">modify or delete the contents of your SD card</string> + <string name="permlab_sdcardWrite">modify or delete the contents of your shared storage</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] --> - <string name="permdesc_sdcardWrite" product="nosdcard">Allows the app to write to the USB storage.</string> - <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_sdcardWrite" product="default">Allows the app to write to the SD card.</string> + <string name="permdesc_sdcardWrite">Allows the app to write the contents of your shared storage.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_use_sip">make/receive SIP calls</string> @@ -2989,6 +2981,18 @@ <!-- Accessibility description for an item in the text selection menu to track a flight [CHAR LIMIT=NONE] --> <string name="view_flight_desc">Track selected flight</string> + <!-- Label for item in the text selection menu to translate selected text with a translation app. Should be a verb. [CHAR LIMIT=30] --> + <string name="translate">Translate</string> + + <!-- Accessibility description for an item in the text selection menu to translate selected text with a translation app. [CHAR LIMIT=NONE] --> + <string name="translate_desc">Translate selected text</string> + + <!-- Label for item in the text selection menu to define selected text with a dictionary app. Should be a verb. [CHAR LIMIT=30] --> + <string name="define">Define</string> + + <!-- Accessibility description for an item in the text selection menu to define selected text with a dictionary app. Should be a verb. [CHAR LIMIT=NONE] --> + <string name="define_desc">Define selected text</string> + <!-- If the device is getting low on internal storage, a notification is shown to the user. This is the title of that notification. --> <string name="low_internal_storage_view_title">Storage space running out</string> <!-- If the device is getting low on internal storage, a notification is shown to the user. This is the message of that notification. --> @@ -3867,10 +3871,8 @@ <string name="action_mode_done">Done</string> <!-- Strings for MasterClearReceiver. --> - <!-- Text for progress dialog while erasing USB storage volume [CHAR LIMIT=NONE] --> - <string name="progress_erasing" product="nosdcard">Erasing USB storage\u2026</string> - <!-- Text for progress dialog while erasing SD card [CHAR LIMIT=NONE] --> - <string name="progress_erasing" product="default">Erasing SD card\u2026</string> + <!-- Text for progress dialog while erasing the shared storage volume [CHAR LIMIT=NONE] --> + <string name="progress_erasing">Erasing shared storage\u2026</string> <!-- Text for WebView's text selection Action Mode --> <!-- ActionBar action to share the current selection [CHAR LIMIT=10] --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index bd53936b596d..18f7e4821a07 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1526,10 +1526,22 @@ please see styles_device_defaults.xml. <item name="gravity">top</item> </style> - <!-- Colored bordered ink button --> + <!-- The style for normal action button on notification --> + <style name="NotificationAction" parent="Widget.Material.Light.Button.Borderless.Small"> + <item name="textColor">@color/notification_action_button_text_color</item> + <item name="background">@drawable/notification_material_action_background</item> + </style> + + <!-- The style for emphasized action button on notification: Colored bordered ink button --> <style name="NotificationEmphasizedAction" parent="Widget.Material.Button"> <item name="background">@drawable/btn_notification_emphasized</item> <item name="stateListAnimator">@anim/flat_button_state_list_anim_material</item> </style> + <!-- The style for disabled action button on notification --> + <style name="NotificationTombstoneAction" parent="NotificationAction"> + <item name="textColor">#555555</item> + </style> + + </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 82c9ff314138..9264f90f8901 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -574,6 +574,10 @@ <java-symbol type="string" name="add_calendar_event_desc" /> <java-symbol type="string" name="view_flight" /> <java-symbol type="string" name="view_flight_desc" /> + <java-symbol type="string" name="translate" /> + <java-symbol type="string" name="translate_desc" /> + <java-symbol type="string" name="define" /> + <java-symbol type="string" name="define_desc" /> <java-symbol type="string" name="textSelectionCABTitle" /> <java-symbol type="string" name="BaMmi" /> <java-symbol type="string" name="CLIRDefaultOffNextCallOff" /> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index f60d8d0adcdd..3b650e5ff777 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1316,6 +1316,12 @@ <service android:name="android.os.BinderThreadPriorityService" android:process=":BinderThreadPriorityService" /> + <!-- Used by BinderWorkSourceTest --> + <service android:name="android.os.BinderWorkSourceService" + android:process=":BinderWorkSourceService" /> + <service android:name="android.os.BinderWorkSourceNestedService" + android:process=":BinderWorkSourceNestedService" /> + <!-- Application components used for search manager tests --> <activity android:name="android.app.activity.SearchableActivity" diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index a317c99bfdfa..8ac9451deaf6 100644 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -364,9 +364,7 @@ public class PackageManagerTests extends AndroidTestCase { private int getInstallLoc(int flags, int expInstallLocation, long pkgLen) { // Flags explicitly over ride everything else. - if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) { - return INSTALL_LOC_SD; - } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) { + if ((flags & PackageManager.INSTALL_INTERNAL) != 0) { return INSTALL_LOC_INT; } // Manifest option takes precedence next @@ -437,8 +435,6 @@ public class PackageManagerTests extends AndroidTestCase { int rLoc = getInstallLoc(flags, expInstallLocation, pkgLen); if (rLoc == INSTALL_LOC_INT) { - assertFalse( - (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0); assertEquals(appInstallPath, srcPath); assertEquals(appInstallPath, publicSrcPath); assertStartsWith("Native library should point to shared lib directory", @@ -461,8 +457,6 @@ public class PackageManagerTests extends AndroidTestCase { } } } else if (rLoc == INSTALL_LOC_SD) { - assertFalse("The application should not be installed forward locked", - (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0); assertTrue("Application flags (" + info.flags + ") should contain FLAG_EXTERNAL_STORAGE", (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); @@ -845,31 +839,10 @@ public class PackageManagerTests extends AndroidTestCase { } @LargeTest - public void testReplaceFailSdcard() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - sampleReplaceFromRawResource(PackageManager.INSTALL_EXTERNAL); - } - - @LargeTest public void testReplaceNormalInternal() throws Exception { sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING); } - @LargeTest - public void testReplaceSdcard() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING - | PackageManager.INSTALL_EXTERNAL); - } - /* -------------- Delete tests --- */ private static class DeleteObserver extends IPackageDeleteObserver.Stub { private CountDownLatch mLatch = new CountDownLatch(1); @@ -1015,31 +988,12 @@ public class PackageManagerTests extends AndroidTestCase { deleteFromRawResource(0, 0); } - @LargeTest - public void testDeleteSdcard() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, 0); - } @LargeTest public void testDeleteNormalInternalRetainData() throws Exception { deleteFromRawResource(0, PackageManager.DELETE_KEEP_DATA); } - @LargeTest - public void testDeleteSdcardRetainData() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA); - } - void cleanUpInstall(InstallParams ip) throws Exception { if (ip == null) { return; @@ -1104,60 +1058,6 @@ public class PackageManagerTests extends AndroidTestCase { 0, true, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED); } - /* - * Install a package on internal flash via PackageManager install flag. Replace - * the package via flag to install on sdcard. Make sure the new flag overrides - * the old install location. - */ - @LargeTest - public void testReplaceFlagInternalSdcard() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = 0; - int rFlags = PackageManager.INSTALL_EXTERNAL; - InstallParams ip = sampleInstallFromRawResource(iFlags, false); - GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); - int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; - try { - invokeInstallPackage(ip.packageURI, replaceFlags, receiver, true); - assertInstall(ip.pkg, rFlags, ip.pkg.installLocation); - } catch (Exception e) { - failStr("Failed with exception : " + e); - } finally { - cleanUpInstall(ip); - } - } - - /* - * Install a package on sdcard via PackageManager install flag. Replace - * the package with no flags or manifest option and make sure the old - * install location is retained. - */ - @LargeTest - public void testReplaceFlagSdcardInternal() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = PackageManager.INSTALL_EXTERNAL; - int rFlags = 0; - InstallParams ip = sampleInstallFromRawResource(iFlags, false); - GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); - int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; - try { - invokeInstallPackage(ip.packageURI, replaceFlags, receiver, true); - assertInstall(ip.pkg, iFlags, ip.pkg.installLocation); - } catch (Exception e) { - failStr("Failed with exception : " + e); - } finally { - cleanUpInstall(ip); - } - } - @LargeTest public void testManifestInstallLocationReplaceInternalSdcard() throws Exception { // Do not run on devices with emulated external storage. @@ -1375,34 +1275,6 @@ public class PackageManagerTests extends AndroidTestCase { } @LargeTest - public void testMoveAppExternalToExternal() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int installFlags = PackageManager.INSTALL_EXTERNAL; - int moveFlags = PackageManager.MOVE_EXTERNAL_MEDIA; - boolean fail = true; - int result = PackageManager.MOVE_FAILED_INVALID_LOCATION; - sampleMoveFromRawResource(installFlags, moveFlags, fail, result); - } - - @LargeTest - public void testMoveAppExternalToInternal() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int installFlags = PackageManager.INSTALL_EXTERNAL; - int moveFlags = PackageManager.MOVE_INTERNAL; - boolean fail = false; - int result = PackageManager.MOVE_SUCCEEDED; - sampleMoveFromRawResource(installFlags, moveFlags, fail, result); - } - - @LargeTest public void testMoveAppFailInternalToExternalDelete() throws Exception { // Do not run on devices with emulated external storage. if (Environment.isExternalStorageEmulated()) { @@ -1458,19 +1330,6 @@ public class PackageManagerTests extends AndroidTestCase { } /* - * Install an app on sdcard. - */ - @LargeTest - public void testFlagE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true); - } - - /* * Install an app with both internal and manifest option set. * should install on internal. */ @@ -1506,59 +1365,6 @@ public class PackageManagerTests extends AndroidTestCase { false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); } - /* - * Install an app with both external and manifest option set. - * should install externally. - */ - @LargeTest - public void testFlagEManifestI() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - installFromRawResource("install.apk", R.raw.install_loc_internal, - PackageManager.INSTALL_EXTERNAL, - true, - false, -1, - PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } - - /* - * Install an app with both external and manifest preference for - * preferExternal. Should install externally. - */ - @LargeTest - public void testFlagEManifestE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - installFromRawResource("install.apk", R.raw.install_loc_sdcard, - PackageManager.INSTALL_EXTERNAL, - true, - false, -1, - PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } - - /* - * Install an app with both external and manifest preference for - * auto. should install on external media. - */ - @LargeTest - public void testFlagEManifestA() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - installFromRawResource("install.apk", R.raw.install_loc_auto, - PackageManager.INSTALL_EXTERNAL, - true, - false, -1, - PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } /* * The following test functions verify install location for existing apps. @@ -1586,75 +1392,6 @@ public class PackageManagerTests extends AndroidTestCase { -1); } - @LargeTest - public void testFlagIExistingE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = PackageManager.INSTALL_EXTERNAL; - int rFlags = PackageManager.INSTALL_INTERNAL | PackageManager.INSTALL_REPLACE_EXISTING; - // First install. - installFromRawResource("install.apk", R.raw.install, - iFlags, - false, - false, -1, - -1); - // Replace now - installFromRawResource("install.apk", R.raw.install, - rFlags, - true, - false, -1, - -1); - } - - @LargeTest - public void testFlagEExistingI() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = PackageManager.INSTALL_INTERNAL; - int rFlags = PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_REPLACE_EXISTING; - // First install. - installFromRawResource("install.apk", R.raw.install, - iFlags, - false, - false, -1, - -1); - // Replace now - installFromRawResource("install.apk", R.raw.install, - rFlags, - true, - false, -1, - -1); - } - - @LargeTest - public void testFlagEExistingE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = PackageManager.INSTALL_EXTERNAL; - int rFlags = PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_REPLACE_EXISTING; - // First install. - installFromRawResource("install.apk", R.raw.install, - iFlags, - false, - false, -1, - -1); - // Replace now - installFromRawResource("install.apk", R.raw.install, - rFlags, - true, - false, -1, - -1); - } - /* * The following set of tests verify the installation of apps with * install location attribute set to internalOnly, preferExternal and auto. @@ -1720,29 +1457,6 @@ public class PackageManagerTests extends AndroidTestCase { } @LargeTest - public void testManifestIExistingE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = PackageManager.INSTALL_EXTERNAL; - int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; - // First install. - installFromRawResource("install.apk", R.raw.install, - iFlags, - false, - false, -1, - -1); - // Replace now - installFromRawResource("install.apk", R.raw.install_loc_internal, - rFlags, - true, - false, -1, - PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); - } - - @LargeTest public void testManifestEExistingI() throws Exception { // Do not run on devices with emulated external storage. if (Environment.isExternalStorageEmulated()) { @@ -1766,29 +1480,6 @@ public class PackageManagerTests extends AndroidTestCase { } @LargeTest - public void testManifestEExistingE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = PackageManager.INSTALL_EXTERNAL; - int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; - // First install. - installFromRawResource("install.apk", R.raw.install, - iFlags, - false, - false, -1, - -1); - // Replace now - installFromRawResource("install.apk", R.raw.install_loc_sdcard, - rFlags, - true, - false, -1, - PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } - - @LargeTest public void testManifestAExistingI() throws Exception { int iFlags = PackageManager.INSTALL_INTERNAL; int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; @@ -1806,29 +1497,6 @@ public class PackageManagerTests extends AndroidTestCase { PackageInfo.INSTALL_LOCATION_AUTO); } - @LargeTest - public void testManifestAExistingE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int iFlags = PackageManager.INSTALL_EXTERNAL; - int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; - // First install. - installFromRawResource("install.apk", R.raw.install, - iFlags, - false, - false, -1, - -1); - // Replace now - installFromRawResource("install.apk", R.raw.install_loc_auto, - rFlags, - true, - false, -1, - PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } - /* * The following set of tests check install location for existing * application based on user setting. @@ -1896,42 +1564,6 @@ public class PackageManagerTests extends AndroidTestCase { setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); } - @LargeTest - public void testExistingEUserI() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int userSetting = PackageHelper.APP_INSTALL_INTERNAL; - int iFlags = PackageManager.INSTALL_EXTERNAL; - setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } - - @LargeTest - public void testExistingEUserE() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int userSetting = PackageHelper.APP_INSTALL_EXTERNAL; - int iFlags = PackageManager.INSTALL_EXTERNAL; - setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } - - @LargeTest - public void testExistingEUserA() throws Exception { - // Do not run on devices with emulated external storage. - if (Environment.isExternalStorageEmulated()) { - return; - } - - int userSetting = PackageHelper.APP_INSTALL_AUTO; - int iFlags = PackageManager.INSTALL_EXTERNAL; - setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - } - /* * The following set of tests verify that the user setting defines * the install location. diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceNestedService.java b/core/tests/coretests/src/android/os/BinderWorkSourceNestedService.java new file mode 100644 index 000000000000..dddeda3874e3 --- /dev/null +++ b/core/tests/coretests/src/android/os/BinderWorkSourceNestedService.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** +* Service used by {@link BinderWorkSourceTest}. +*/ +public class BinderWorkSourceNestedService extends Service { + private final IBinderWorkSourceNestedService.Stub mBinder = + new IBinderWorkSourceNestedService.Stub() { + + public int[] nestedCallWithWorkSourceToSet(int uidToBlame) { + final int uid = Binder.getCallingWorkSourceUid(); + if (uidToBlame != ThreadLocalWorkSource.UID_NONE) { + Binder.setCallingWorkSourceUid(uidToBlame); + } + final int nestedUid = callGetIncomingWorkSourceUid(); + return new int[] {uid, nestedUid}; + } + + public int[] nestedCall() { + final int uid = Binder.getCallingWorkSourceUid(); + final int nestedUid = callGetIncomingWorkSourceUid(); + return new int[] {uid, nestedUid}; + } + + private int callGetIncomingWorkSourceUid() { + BlockingQueue<IBinderWorkSourceService> blockingQueue = + new LinkedBlockingQueue<>(); + ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + blockingQueue.add(IBinderWorkSourceService.Stub.asInterface(service)); + } + + public void onServiceDisconnected(ComponentName name) { + } + }; + + Context context = getApplicationContext(); + context.bindService( + new Intent(context, BinderWorkSourceService.class), + mConnection, Context.BIND_AUTO_CREATE); + + final IBinderWorkSourceService service; + try { + service = blockingQueue.poll(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + if (service == null) { + throw new RuntimeException("Gave up waiting for BinderWorkSourceService"); + } + + try { + return service.getIncomingWorkSourceUid(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } finally { + context.unbindService(mConnection); + } + } + }; + + public IBinder onBind(Intent intent) { + return mBinder; + } +} diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceService.java b/core/tests/coretests/src/android/os/BinderWorkSourceService.java new file mode 100644 index 000000000000..ac8d7ab98344 --- /dev/null +++ b/core/tests/coretests/src/android/os/BinderWorkSourceService.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.app.Service; +import android.content.Intent; + +/** + * Service used by {@link BinderWorkSourceTest}. + */ +public class BinderWorkSourceService extends Service { + private final IBinderWorkSourceService.Stub mBinder = + new IBinderWorkSourceService.Stub() { + public int getIncomingWorkSourceUid() { + return Binder.getCallingWorkSourceUid(); + } + }; + + public IBinder onBind(Intent intent) { + return mBinder; + } +} diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java new file mode 100644 index 000000000000..ec178031cc45 --- /dev/null +++ b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.LargeTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test whether Binder calls work source is propagated correctly. + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +public class BinderWorkSourceTest { + private static Context sContext; + private static final int UID = 100; + private static final int SECOND_UID = 200; + private static final int UID_NONE = ThreadLocalWorkSource.UID_NONE; + + private IBinderWorkSourceService mService; + private IBinderWorkSourceNestedService mNestedService; + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IBinderWorkSourceService.Stub.asInterface(service); + } + + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + }; + + private ServiceConnection mNestedConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + mNestedService = IBinderWorkSourceNestedService.Stub.asInterface(service); + } + + public void onServiceDisconnected(ComponentName name) { + mNestedService = null; + } + }; + + @BeforeClass + public static void setUpOnce() throws Exception { + sContext = InstrumentationRegistry.getContext(); + } + + @Before + public void setUp() throws Exception { + sContext.bindService( + new Intent(sContext, BinderWorkSourceService.class), + mConnection, Context.BIND_AUTO_CREATE); + sContext.bindService( + new Intent(sContext, BinderWorkSourceNestedService.class), + mNestedConnection, Context.BIND_AUTO_CREATE); + + final long timeoutMs = System.currentTimeMillis() + 30_000; + while ((mService == null || mNestedService == null) + && System.currentTimeMillis() < timeoutMs) { + Thread.sleep(1_000); + } + assertNotNull("Gave up waiting for BinderWorkSourceService", mService); + assertNotNull("Gave up waiting for BinderWorkSourceNestedService", mNestedService); + } + + @After + public void tearDown() throws Exception { + sContext.unbindService(mConnection); + sContext.unbindService(mNestedConnection); + } + + @Test + public void setWorkSource() throws Exception { + Binder.setCallingWorkSourceUid(UID); + assertEquals(UID, mService.getIncomingWorkSourceUid()); + assertEquals(UID, Binder.getCallingWorkSourceUid()); + } + + @Test + public void clearWorkSource() throws Exception { + Binder.setCallingWorkSourceUid(UID); + Binder.clearCallingWorkSource(); + assertEquals(UID_NONE, mService.getIncomingWorkSourceUid()); + assertEquals(UID_NONE, Binder.getCallingWorkSourceUid()); + } + + @Test + public void setWorkSource_propagatedForMultipleCalls() throws Exception { + Binder.setCallingWorkSourceUid(UID); + assertEquals(UID, mService.getIncomingWorkSourceUid()); + assertEquals(UID, mService.getIncomingWorkSourceUid()); + assertEquals(UID, mService.getIncomingWorkSourceUid()); + assertEquals(UID, Binder.getCallingWorkSourceUid()); + } + + @Test + public void restoreWorkSource() throws Exception { + Binder.setCallingWorkSourceUid(UID); + long token = Binder.clearCallingWorkSource(); + Binder.restoreCallingWorkSource(token); + + assertEquals(UID, mService.getIncomingWorkSourceUid()); + assertEquals(UID, Binder.getCallingWorkSourceUid()); + } + + @Test + public void nestedSetWorkSoucePropagated() throws Exception { + Binder.setCallingWorkSourceUid(UID); + + int[] workSources = mNestedService.nestedCallWithWorkSourceToSet(SECOND_UID); + assertEquals(UID, workSources[0]); + // UID set in ested call. + assertEquals(SECOND_UID, workSources[1]); + // Initial work source restored. + assertEquals(UID, Binder.getCallingWorkSourceUid()); + } + + @Test + public void nestedSetWorkSouceDoesNotEnablePropagation() throws Exception { + int[] workSources = mNestedService.nestedCallWithWorkSourceToSet(UID); + assertEquals(UID_NONE, workSources[0]); + // UID set in ested call. + assertEquals(UID, workSources[1]); + // Initial work source restored. + assertEquals(UID_NONE, Binder.getCallingWorkSourceUid()); + } + + @Test + public void nestedSetWorkSouceNotPropagated() throws Exception { + Binder.setCallingWorkSourceUid(UID); + + int[] workSources = mNestedService.nestedCall(); + assertEquals(UID, workSources[0]); + // No UID propagated. + assertEquals(UID_NONE, workSources[1]); + // Initial work source restored. + assertEquals(UID, Binder.getCallingWorkSourceUid()); + } +} diff --git a/core/tests/coretests/src/android/os/IBinderWorkSourceNestedService.aidl b/core/tests/coretests/src/android/os/IBinderWorkSourceNestedService.aidl new file mode 100644 index 000000000000..365aebb803f6 --- /dev/null +++ b/core/tests/coretests/src/android/os/IBinderWorkSourceNestedService.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +interface IBinderWorkSourceNestedService { + int[] nestedCallWithWorkSourceToSet(int uidToBlame); + int[] nestedCall(); +} diff --git a/core/tests/coretests/src/android/os/IBinderWorkSourceService.aidl b/core/tests/coretests/src/android/os/IBinderWorkSourceService.aidl new file mode 100644 index 000000000000..05d4e829be0a --- /dev/null +++ b/core/tests/coretests/src/android/os/IBinderWorkSourceService.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +interface IBinderWorkSourceService { + int getIncomingWorkSourceUid(); +} diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 4802ebea2511..5e669e4f82b9 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -124,6 +124,7 @@ public class SettingsBackupTest { Settings.Global.AUTOFILL_LOGGING_LEVEL, Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, + Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, Settings.Global.AUTOMATIC_POWER_SAVER_MODE, Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD, Settings.Global.BATTERY_DISCHARGE_THRESHOLD, @@ -191,6 +192,10 @@ public class SettingsBackupTest { Settings.Global.DATA_ROAMING, Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, + Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD, + Settings.Global.DATA_STALL_EVALUATION_TYPE, + Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL, + Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD, Settings.Global.DEBUG_APP, Settings.Global.DEBUG_VIEW_ATTRIBUTES, Settings.Global.DEFAULT_DNS_SERVER, @@ -283,6 +288,7 @@ public class SettingsBackupTest { Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS, Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST, + Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS, Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS, Settings.Global.LOCATION_GLOBAL_KILL_SWITCH, Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED, @@ -308,6 +314,7 @@ public class SettingsBackupTest { Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, Settings.Global.MULTI_SIM_VOICE_PROMPT, + Settings.Global.NATIVE_FLAGS_HEALTH_CHECK_ENABLED, Settings.Global.NETSTATS_DEV_BUCKET_DURATION, Settings.Global.NETSTATS_DEV_DELETE_AGE, Settings.Global.NETSTATS_DEV_PERSIST_BYTES, diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java new file mode 100644 index 000000000000..f0faaf6153b1 --- /dev/null +++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textclassifier; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Person; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.google.android.textclassifier.ActionsSuggestionsModel; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.Collections; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ActionsSuggestionsHelperTest { + @Test + public void testToNativeMessages_emptyInput() { + ActionsSuggestionsModel.ConversationMessage[] conversationMessages = + ActionsSuggestionsHelper.toNativeMessages(Collections.emptyList()); + + assertThat(conversationMessages).isEmpty(); + } + + @Test + public void testToNativeMessages_noTextMessages() { + ConversationActions.Message messageWithoutText = + new ConversationActions.Message.Builder().build(); + + ActionsSuggestionsModel.ConversationMessage[] conversationMessages = + ActionsSuggestionsHelper.toNativeMessages( + Collections.singletonList(messageWithoutText)); + + assertThat(conversationMessages).isEmpty(); + } + + @Test + public void testToNativeMessages_missingPersonInFirstMessage() { + ConversationActions.Message firstMessage = + new ConversationActions.Message.Builder() + .setText("first") + .build(); + ConversationActions.Message secondMessage = + new ConversationActions.Message.Builder() + .setText("second") + .setAuthor(new Person.Builder().build()) + .build(); + ConversationActions.Message thirdMessage = + new ConversationActions.Message.Builder() + .setText("third") + .setAuthor(ConversationActions.Message.PERSON_USER_LOCAL) + .build(); + + ActionsSuggestionsModel.ConversationMessage[] conversationMessages = + ActionsSuggestionsHelper.toNativeMessages( + Arrays.asList(firstMessage, secondMessage, thirdMessage)); + + assertThat(conversationMessages).hasLength(2); + assertNativeMessage(conversationMessages[0], secondMessage.getText(), 1); + assertNativeMessage(conversationMessages[1], thirdMessage.getText(), 0); + } + + @Test + public void testToNativeMessages_missingPersonInMiddleOfConversation() { + ConversationActions.Message firstMessage = + new ConversationActions.Message.Builder() + .setText("first") + .setAuthor(new Person.Builder().setName("first").build()) + .build(); + ConversationActions.Message secondMessage = + new ConversationActions.Message.Builder() + .setText("second") + .build(); + ConversationActions.Message thirdMessage = + new ConversationActions.Message.Builder() + .setText("third") + .setAuthor(new Person.Builder().setName("third").build()) + .build(); + ConversationActions.Message fourthMessage = + new ConversationActions.Message.Builder() + .setText("fourth") + .setAuthor(new Person.Builder().setName("fourth").build()) + .build(); + + ActionsSuggestionsModel.ConversationMessage[] conversationMessages = + ActionsSuggestionsHelper.toNativeMessages( + Arrays.asList(firstMessage, secondMessage, thirdMessage, fourthMessage)); + + assertThat(conversationMessages).hasLength(2); + assertNativeMessage(conversationMessages[0], thirdMessage.getText(), 2); + assertNativeMessage(conversationMessages[1], fourthMessage.getText(), 1); + } + + @Test + public void testToNativeMessages_userIdEncoding() { + Person userA = new Person.Builder().setName("userA").build(); + Person userB = new Person.Builder().setName("userB").build(); + + ConversationActions.Message firstMessage = + new ConversationActions.Message.Builder() + .setText("first") + .setAuthor(userB) + .build(); + ConversationActions.Message secondMessage = + new ConversationActions.Message.Builder() + .setText("second") + .setAuthor(userA) + .build(); + ConversationActions.Message thirdMessage = + new ConversationActions.Message.Builder() + .setText("third") + .setAuthor(ConversationActions.Message.PERSON_USER_LOCAL) + .build(); + ConversationActions.Message fourthMessage = + new ConversationActions.Message.Builder() + .setText("fourth") + .setAuthor(userA) + .build(); + + ActionsSuggestionsModel.ConversationMessage[] conversationMessages = + ActionsSuggestionsHelper.toNativeMessages( + Arrays.asList(firstMessage, secondMessage, thirdMessage, fourthMessage)); + + assertThat(conversationMessages).hasLength(4); + assertNativeMessage(conversationMessages[0], firstMessage.getText(), 2); + assertNativeMessage(conversationMessages[1], secondMessage.getText(), 1); + assertNativeMessage(conversationMessages[2], thirdMessage.getText(), 0); + assertNativeMessage(conversationMessages[3], fourthMessage.getText(), 1); + } + + private static void assertNativeMessage( + ActionsSuggestionsModel.ConversationMessage nativeMessage, + CharSequence text, + int userId) { + assertThat(nativeMessage.getText()).isEqualTo(text.toString()); + assertThat(nativeMessage.getUserId()).isEqualTo(userId); + } +} diff --git a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java new file mode 100644 index 000000000000..018085698d0c --- /dev/null +++ b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textclassifier; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.support.test.InstrumentationRegistry; + +import androidx.annotation.Nullable; + +import com.google.common.base.Preconditions; + +import org.mockito.stubbing.Answer; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * A builder used to build a fake context for testing. + */ +// TODO: Consider making public. +final class FakeContextBuilder { + + /** + * A component name that can be used for tests. + */ + public static final ComponentName DEFAULT_COMPONENT = new ComponentName("pkg", "cls"); + + private final PackageManager mPackageManager; + private final ContextWrapper mContext; + private final Map<String, ComponentName> mComponents = new HashMap<>(); + private @Nullable ComponentName mAllIntentComponent; + + FakeContextBuilder() { + mPackageManager = mock(PackageManager.class); + when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(null); + mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) { + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + }; + } + + /** + * Sets the component name of an activity to handle the specified intent action. + * <p> + * <strong>NOTE: </strong>By default, no component is set to handle any intent. + */ + public FakeContextBuilder setIntentComponent( + String intentAction, @Nullable ComponentName component) { + Preconditions.checkNotNull(intentAction); + mComponents.put(intentAction, component); + return this; + } + + + /** + * Sets the component name of an activity to handle all intents. + * <p> + * <strong>NOTE: </strong>By default, no component is set to handle any intent. + */ + public FakeContextBuilder setAllIntentComponent(@Nullable ComponentName component) { + mAllIntentComponent = component; + return this; + } + + /** + * Builds and returns a fake context. + */ + public Context build() { + when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenAnswer( + (Answer<ResolveInfo>) invocation -> { + final String action = ((Intent) invocation.getArgument(0)).getAction(); + final ComponentName component = mComponents.containsKey(action) + ? mComponents.get(action) + : mAllIntentComponent; + return getResolveInfo(component); + }); + return mContext; + } + + /** + * Returns a component name with random package and class names. + */ + public static ComponentName newComponent() { + return new ComponentName(UUID.randomUUID().toString(), UUID.randomUUID().toString()); + } + + private static ResolveInfo getResolveInfo(ComponentName component) { + final ResolveInfo info; + if (component == null) { + info = null; + } else { + // NOTE: If something breaks in TextClassifier because we expect more fields to be set + // in here, just add them. + info = new ResolveInfo(); + info.activityInfo = new ActivityInfo(); + info.activityInfo.packageName = component.getPackageName(); + info.activityInfo.name = component.getClassName(); + info.activityInfo.exported = true; + info.activityInfo.applicationInfo = new ApplicationInfo(); + info.activityInfo.applicationInfo.icon = 0; + } + return info; + } + +} diff --git a/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java new file mode 100644 index 000000000000..bae2be352b4c --- /dev/null +++ b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.view.textclassifier; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Intent; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.google.android.textclassifier.AnnotatorModel; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class IntentFactoryTest { + + private static final String TEXT = "text"; + + @Test + public void create_typeDictionary() { + AnnotatorModel.ClassificationResult classificationResult = + new AnnotatorModel.ClassificationResult( + TextClassifier.TYPE_DICTIONARY, + 1.0f, + null, + null); + + List<TextClassifierImpl.LabeledIntent> intents = TextClassifierImpl.IntentFactory.create( + InstrumentationRegistry.getContext(), + TEXT, + false, + null, + classificationResult); + + assertThat(intents).hasSize(1); + TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0); + Intent intent = labeledIntent.getIntent(); + assertThat(intent.getAction()).isEqualTo(Intent.ACTION_DEFINE); + assertThat(intent.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(TEXT); + } +} diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java index 46aa5b484c5f..a3f69d93ad44 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java @@ -20,18 +20,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import android.content.Context; -import android.content.ContextWrapper; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; import android.os.LocaleList; import android.service.textclassifier.TextClassifierService; import android.support.test.InstrumentationRegistry; @@ -41,7 +33,6 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; @SmallTest @RunWith(AndroidJUnit4.class) @@ -78,23 +69,10 @@ public class TextClassificationManagerTest { @Test public void testCannotResolveIntent() { - final PackageManager fakePackageMgr = mock(PackageManager.class); - - ResolveInfo validInfo = mContext.getPackageManager().resolveActivity( - new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:+12122537077")), 0); - // Make packageManager fail when it gets the following intent: - ArgumentMatcher<Intent> toFailIntent = - intent -> intent.getAction().equals(Intent.ACTION_INSERT_OR_EDIT); - - when(fakePackageMgr.resolveActivity(any(Intent.class), anyInt())).thenReturn(validInfo); - when(fakePackageMgr.resolveActivity(argThat(toFailIntent), anyInt())).thenReturn(null); - - ContextWrapper fakeContext = new ContextWrapper(mContext) { - @Override - public PackageManager getPackageManager() { - return fakePackageMgr; - } - }; + Context fakeContext = new FakeContextBuilder() + .setAllIntentComponent(FakeContextBuilder.DEFAULT_COMPONENT) + .setIntentComponent(Intent.ACTION_INSERT_OR_EDIT, null) + .build(); TextClassifier fallback = TextClassifier.NO_OP; TextClassifier classifier = new TextClassifierImpl( diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index 06ba15e8e339..fbcb629f043f 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -23,9 +23,12 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import android.content.Context; +import android.content.Intent; import android.os.LocaleList; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; +import android.text.Spannable; +import android.text.SpannableString; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; @@ -52,12 +55,18 @@ public class TextClassifierTest { @Parameterized.Parameters(name = "{0}") public static Iterable<Object> textClassifierTypes() { - return Arrays.asList(LOCAL, SYSTEM); + return Arrays.asList(LOCAL); + + // TODO: The following will fail on any device that specifies a no-op TextClassifierService. + // Enable when we can set a specified TextClassifierService for testing. + // return Arrays.asList(LOCAL, SYSTEM); } @Parameterized.Parameter public String mTextClassifierType; + private static final TextClassificationConstants TC_CONSTANTS = + TextClassificationConstants.loadFromString(""); private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US"); private static final String NO_TYPE = null; @@ -74,7 +83,7 @@ public class TextClassifierTest { } @Test - public void testSmartSelection() { + public void testSuggestSelection() { if (isTextClassifierDisabled()) return; String text = "Contact me at droid@android.com"; @@ -95,7 +104,7 @@ public class TextClassifierTest { } @Test - public void testSmartSelection_url() { + public void testSuggestSelection_url() { if (isTextClassifierDisabled()) return; String text = "Visit http://www.android.com for more information"; @@ -151,7 +160,7 @@ public class TextClassifierTest { } @Test - public void testTextClassifyText_url() { + public void testClassifyText_url() { if (isTextClassifierDisabled()) return; String text = "Visit www.android.com for more information"; @@ -168,7 +177,7 @@ public class TextClassifierTest { } @Test - public void testTextClassifyText_address() { + public void testClassifyText_address() { if (isTextClassifierDisabled()) return; String text = "Brandschenkestrasse 110, Zürich, Switzerland"; @@ -182,7 +191,7 @@ public class TextClassifierTest { } @Test - public void testTextClassifyText_url_inCaps() { + public void testClassifyText_url_inCaps() { if (isTextClassifierDisabled()) return; String text = "Visit HTTP://ANDROID.COM for more information"; @@ -199,7 +208,7 @@ public class TextClassifierTest { } @Test - public void testTextClassifyText_date() { + public void testClassifyText_date() { if (isTextClassifierDisabled()) return; String text = "Let's meet on January 9, 2018."; @@ -216,7 +225,7 @@ public class TextClassifierTest { } @Test - public void testTextClassifyText_datetime() { + public void testClassifyText_datetime() { if (isTextClassifierDisabled()) return; String text = "Let's meet 2018/01/01 10:30:20."; @@ -234,6 +243,30 @@ public class TextClassifierTest { } @Test + public void testClassifyText_foreignText() { + LocaleList originalLocales = LocaleList.getDefault(); + LocaleList.setDefault(LocaleList.forLanguageTags("en")); + String foreignText = "これは日本語のテキストです"; + + Context context = new FakeContextBuilder() + .setIntentComponent(Intent.ACTION_TRANSLATE, FakeContextBuilder.DEFAULT_COMPONENT) + .build(); + TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS); + TextClassification.Request request = new TextClassification.Request.Builder( + foreignText, 0, foreignText.length()) + .setDefaultLocales(LOCALES) + .build(); + + TextClassification classification = classifier.classifyText(request); + assertEquals(1, classification.getActions().size()); + assertEquals( + context.getString(com.android.internal.R.string.translate), + classification.getActions().get(0).getTitle()); + + LocaleList.setDefault(originalLocales); + } + + @Test public void testGenerateLinks_phone() { if (isTextClassifierDisabled()) return; String text = "The number is +12122537077. See you tonight!"; @@ -296,6 +329,17 @@ public class TextClassifierTest { assertTrue(links.getLinks().isEmpty()); } + @Test + public void testApplyLinks_unsupportedCharacter() { + if (isTextClassifierDisabled()) return; + Spannable url = new SpannableString("\u202Emoc.diordna.com"); + TextLinks.Request request = new TextLinks.Request.Builder(url).build(); + assertEquals( + TextLinks.STATUS_UNSUPPORTED_CHARACTER, + mClassifier.generateLinks(request).apply(url, 0, null)); + } + + @Test(expected = IllegalArgumentException.class) public void testGenerateLinks_tooLong() { if (isTextClassifierDisabled()) { diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index 70dc6189c6c2..90758ba7c418 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -983,6 +983,19 @@ public class TextViewActivityTest { } @Test + public void testNoAssistItemForTextFieldWithUnsupportedCharacters() throws Throwable { + useSystemDefaultTextClassifier(); + final String text = "\u202Emoc.diordna.com"; + final TextView textView = mActivity.findViewById(R.id.textview); + mActivityRule.runOnUiThread(() -> textView.setText(text)); + mInstrumentation.waitForIdleSync(); + + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('.'))); + sleepForFloatingToolbarPopup(); + assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist); + } + + @Test public void testSelectionMetricsLogger_noAbandonAfterCopy() throws Throwable { final List<SelectionEvent> selectionEvents = new ArrayList<>(); final TextClassifier classifier = new TextClassifier() { diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java index 3cfc6443b15e..225515e9e3f3 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java @@ -39,6 +39,10 @@ import org.junit.runners.Suite; BatteryStatsUserLifecycleTests.class, KernelCpuProcReaderTest.class, KernelCpuProcStringReaderTest.class, + KernelCpuUidActiveTimeReaderTest.class, + KernelCpuUidClusterTimeReaderTest.class, + KernelCpuUidFreqTimeReaderTest.class, + KernelCpuUidUserSysTimeReaderTest.class, KernelMemoryBandwidthStatsTest.class, KernelSingleUidTimeReaderTest.class, KernelUidCpuFreqTimeReaderTest.class, diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java index dae9eb57e237..2663f2bc8ae1 100644 --- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java +++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java @@ -37,6 +37,7 @@ import java.io.BufferedWriter; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.CharBuffer; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; @@ -149,7 +150,7 @@ public class KernelCpuProcStringReaderTest { + "0 0 1 1 1 0 2 0 221", iter.nextLine().toString()); long[] actual = new long[43]; - iter.nextLineAsArray(actual); + KernelCpuProcStringReader.asLongs(iter.nextLine(), actual); assertArrayEquals( new long[]{50227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 721}, @@ -183,7 +184,7 @@ public class KernelCpuProcStringReaderTest { } } - /** Tests nextLineToArray functionality. */ + /** Tests reading lines, then converting to long[]. */ @Test public void testReadLineToArray() throws Exception { final long[][] data = getTestArray(800, 50); @@ -193,12 +194,32 @@ public class KernelCpuProcStringReaderTest { long[] actual = new long[50]; try (KernelCpuProcStringReader.ProcFileIterator iter = mReader.open()) { for (long[] expected : data) { - assertEquals(50, iter.nextLineAsArray(actual)); + CharBuffer cb = iter.nextLine(); + String before = cb.toString(); + assertEquals(50, KernelCpuProcStringReader.asLongs(cb, actual)); assertArrayEquals(expected, actual); + assertEquals("Buffer not reset to the pos before reading", before, cb.toString()); } } } + /** Tests error handling of converting to long[]. */ + @Test + public void testLineToArrayErrorHandling() { + long[] actual = new long[100]; + String invalidChar = "123: -1234 456"; + String overflow = "123: 999999999999999999999999999999999999999999999999999999999 123"; + CharBuffer cb = CharBuffer.wrap("----" + invalidChar + "+++", 4, 4 + invalidChar.length()); + assertEquals("Failed to report err for: " + invalidChar, -2, + KernelCpuProcStringReader.asLongs(cb, actual)); + assertEquals("Buffer not reset to the same pos before reading", invalidChar, cb.toString()); + + cb = CharBuffer.wrap("----" + overflow + "+++", 4, 4 + overflow.length()); + assertEquals("Failed to report err for: " + overflow, -3, + KernelCpuProcStringReader.asLongs(cb, actual)); + assertEquals("Buffer not reset to the pos before reading", overflow, cb.toString()); + } + /** * Tests that reading a file over the limit (1MB) will return null. */ diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java new file mode 100644 index 000000000000..adafda04d516 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.os.FileUtils; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.SparseLongArray; + +import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Random; + +/** + * Test class for {@link KernelCpuUidActiveTimeReader}. + * + * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidActiveTimeReaderTest + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class KernelCpuUidActiveTimeReaderTest { + private File mTestDir; + private File mTestFile; + private KernelCpuUidActiveTimeReader mReader; + private VerifiableCallback mCallback; + + private Random mRand = new Random(12345); + private final int mCpus = 4; + private final String mHeadline = "cpus: 4\n"; + private final int[] mUids = {0, 1, 22, 333, 4444, 55555}; + + private Context getContext() { + return InstrumentationRegistry.getContext(); + } + + @Before + public void setUp() { + mTestDir = getContext().getDir("test", Context.MODE_PRIVATE); + mTestFile = new File(mTestDir, "test.file"); + mReader = new KernelCpuUidActiveTimeReader( + new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false); + mCallback = new VerifiableCallback(); + } + + @After + public void tearDown() throws Exception { + FileUtils.deleteContents(mTestDir); + FileUtils.deleteContents(getContext().getFilesDir()); + } + + @Test + public void testReadDelta() throws Exception { + final long[][] times = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], getActiveTime(times[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that a second call will only return deltas. + mCallback.clear(); + final long[][] newTimes1 = increaseTime(times); + writeToFile(mHeadline + uidLines(mUids, newTimes1)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], getActiveTime(newTimes1[i]) - getActiveTime(times[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that there won't be a callback if the proc file values didn't change. + mCallback.clear(); + mReader.readDelta(mCallback); + mCallback.verifyNoMoreInteractions(); + + // Verify that calling with a null callback doesn't result in any crashes + mCallback.clear(); + final long[][] newTimes2 = increaseTime(newTimes1); + writeToFile(mHeadline + uidLines(mUids, newTimes2)); + mReader.readDelta(null); + mCallback.verifyNoMoreInteractions(); + + // Verify that the readDelta call will only return deltas when + // the previous call had null callback. + mCallback.clear(); + final long[][] newTimes3 = increaseTime(newTimes2); + writeToFile(mHeadline + uidLines(mUids, newTimes3)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], getActiveTime(newTimes3[i]) - getActiveTime(newTimes2[i])); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadAbsolute() throws Exception { + final long[][] times1 = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times1)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], getActiveTime(times1[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that a second call should still return absolute values + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + writeToFile(mHeadline + uidLines(mUids, times2)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], getActiveTime(times2[i])); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadDeltaDecreasedTime() throws Exception { + final long[][] times1 = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times1)); + mReader.readDelta(mCallback); + + // Verify that there should not be a callback for a particular UID if its time decreases. + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + System.arraycopy(times1[0], 0, times2[0], 0, mCpus); + times2[0][0] = 100; + writeToFile(mHeadline + uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], getActiveTime(times2[i]) - getActiveTime(times1[i])); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + + // Verify that the internal state was not modified. + mCallback.clear(); + final long[][] times3 = increaseTime(times2); + times3[0] = increaseTime(times1)[0]; + writeToFile(mHeadline + uidLines(mUids, times3)); + mReader.readDelta(mCallback); + mCallback.verify(mUids[0], getActiveTime(times3[0]) - getActiveTime(times1[0])); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], getActiveTime(times3[i]) - getActiveTime(times2[i])); + } + mCallback.verifyNoMoreInteractions(); + } + + @Test + public void testReadDeltaNegativeTime() throws Exception { + final long[][] times1 = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times1)); + mReader.readDelta(mCallback); + + // Verify that there should not be a callback for a particular UID if its time is -ve. + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + times2[0][0] *= -1; + writeToFile(mHeadline + uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], getActiveTime(times2[i]) - getActiveTime(times1[i])); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + + // Verify that the internal state was not modified. + mCallback.clear(); + final long[][] times3 = increaseTime(times2); + times3[0] = increaseTime(times1)[0]; + writeToFile(mHeadline + uidLines(mUids, times3)); + mReader.readDelta(mCallback); + mCallback.verify(mUids[0], getActiveTime(times3[0]) - getActiveTime(times1[0])); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], getActiveTime(times3[i]) - getActiveTime(times2[i])); + } + mCallback.verifyNoMoreInteractions(); + } + + private String uidLines(int[] uids, long[][] times) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < uids.length; i++) { + sb.append(uids[i]).append(':'); + for (int j = 0; j < times[i].length; j++) { + sb.append(' ').append(times[i][j] / 10); + } + sb.append('\n'); + } + return sb.toString(); + } + + private void writeToFile(String s) throws IOException { + try (BufferedWriter w = Files.newBufferedWriter(mTestFile.toPath())) { + w.write(s); + w.flush(); + } + } + + private long[][] increaseTime(long[][] original) { + long[][] newTime = new long[original.length][original[0].length]; + for (int i = 0; i < original.length; i++) { + for (int j = 0; j < original[0].length; j++) { + newTime[i][j] = original[i][j] + mRand.nextInt(10000) * 1000 + 1000; + } + } + return newTime; + } + + private long getActiveTime(long[] times) { + return times[0] + times[1] / 2 + times[2] / 3 + times[3] / 4; + } + + private class VerifiableCallback implements KernelCpuUidTimeReader.Callback<Long> { + SparseLongArray mData = new SparseLongArray(); + + public void verify(int uid, long time) { + assertEquals(time, mData.get(uid)); + mData.delete(uid); + } + + public void clear() { + mData.clear(); + } + + @Override + public void onUidCpuTime(int uid, Long time) { + mData.put(uid, time); + } + + public void verifyNoMoreInteractions() { + assertEquals(0, mData.size()); + } + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java new file mode 100644 index 000000000000..ad20d84bfc60 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.os.FileUtils; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.SparseArray; + +import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Random; + +/** + * Test class for {@link KernelCpuUidClusterTimeReader}. + * + * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidClusterTimeReaderTest + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class KernelCpuUidClusterTimeReaderTest { + private File mTestDir; + private File mTestFile; + private KernelCpuUidClusterTimeReader mReader; + private VerifiableCallback mCallback; + + private Random mRand = new Random(12345); + private final int mCpus = 6; + private final String mHeadline = "policy0: 4 policy4: 2\n"; + private final int[] mUids = {0, 1, 22, 333, 4444, 55555}; + + private Context getContext() { + return InstrumentationRegistry.getContext(); + } + + @Before + public void setUp() { + mTestDir = getContext().getDir("test", Context.MODE_PRIVATE); + mTestFile = new File(mTestDir, "test.file"); + mReader = new KernelCpuUidClusterTimeReader( + new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false); + mCallback = new VerifiableCallback(); + } + + @After + public void tearDown() throws Exception { + FileUtils.deleteContents(mTestDir); + FileUtils.deleteContents(getContext().getFilesDir()); + } + + @Test + public void testReadDelta() throws Exception { + final long[][] times1 = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times1)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], clusterTime(times1[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that a second call will only return deltas. + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + writeToFile(mHeadline + uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], subtract(clusterTime(times2[i]), clusterTime(times1[i]))); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that there won't be a callback if the proc file values didn't change. + mCallback.clear(); + mReader.readDelta(mCallback); + mCallback.verifyNoMoreInteractions(); + + // Verify that calling with a null callback doesn't result in any crashes + mCallback.clear(); + final long[][] times3 = increaseTime(times2); + writeToFile(mHeadline + uidLines(mUids, times3)); + mReader.readDelta(null); + mCallback.verifyNoMoreInteractions(); + + // Verify that the readDelta call will only return deltas when + // the previous call had null callback. + mCallback.clear(); + final long[][] times4 = increaseTime(times3); + writeToFile(mHeadline + uidLines(mUids, times4)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], subtract(clusterTime(times4[i]), clusterTime(times3[i]))); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadAbsolute() throws Exception { + final long[][] times1 = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times1)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], clusterTime(times1[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that a second call should still return absolute values + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + writeToFile(mHeadline + uidLines(mUids, times2)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], clusterTime(times2[i])); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadDeltaDecreasedTime() throws Exception { + final long[][] times1 = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times1)); + mReader.readDelta(mCallback); + + // Verify that there should not be a callback for a particular UID if its time decreases. + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + System.arraycopy(times1[0], 0, times2[0], 0, mCpus); + times2[0][0] = 100; + writeToFile(mHeadline + uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(clusterTime(times2[i]), clusterTime(times1[i]))); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + + // Verify that the internal state was not modified. + mCallback.clear(); + final long[][] times3 = increaseTime(times2); + times3[0] = increaseTime(times1)[0]; + writeToFile(mHeadline + uidLines(mUids, times3)); + mReader.readDelta(mCallback); + mCallback.verify(mUids[0], subtract(clusterTime(times3[0]), clusterTime(times1[0]))); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(clusterTime(times3[i]), clusterTime(times2[i]))); + } + mCallback.verifyNoMoreInteractions(); + } + + @Test + public void testReadDeltaNegativeTime() throws Exception { + final long[][] times1 = increaseTime(new long[mUids.length][mCpus]); + writeToFile(mHeadline + uidLines(mUids, times1)); + mReader.readDelta(mCallback); + + // Verify that there should not be a callback for a particular UID if its time decreases. + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + times2[0][0] *= -1; + writeToFile(mHeadline + uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(clusterTime(times2[i]), clusterTime(times1[i]))); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + + // Verify that the internal state was not modified. + mCallback.clear(); + final long[][] times3 = increaseTime(times2); + times3[0] = increaseTime(times1)[0]; + writeToFile(mHeadline + uidLines(mUids, times3)); + mReader.readDelta(mCallback); + mCallback.verify(mUids[0], subtract(clusterTime(times3[0]), clusterTime(times1[0]))); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(clusterTime(times3[i]), clusterTime(times2[i]))); + } + mCallback.verifyNoMoreInteractions(); + } + + private long[] clusterTime(long[] times) { + // Assumes 4 + 2 cores + return new long[]{times[0] + times[1] / 2 + times[2] / 3 + times[3] / 4, + times[4] + times[5] / 2}; + } + + private String uidLines(int[] uids, long[][] times) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < uids.length; i++) { + sb.append(uids[i]).append(':'); + for (int j = 0; j < times[i].length; j++) { + sb.append(' ').append(times[i][j] / 10); + } + sb.append('\n'); + } + return sb.toString(); + } + + private void writeToFile(String s) throws IOException { + try (BufferedWriter w = Files.newBufferedWriter(mTestFile.toPath())) { + w.write(s); + w.flush(); + } + } + + private long[][] increaseTime(long[][] original) { + long[][] newTime = new long[original.length][original[0].length]; + for (int i = 0; i < original.length; i++) { + for (int j = 0; j < original[0].length; j++) { + newTime[i][j] = original[i][j] + mRand.nextInt(10000) * 1000 + 1000; + } + } + return newTime; + } + + private long[] subtract(long[] a1, long[] a2) { + long[] val = new long[a1.length]; + for (int i = 0; i < val.length; ++i) { + val[i] = a1[i] - a2[i]; + } + return val; + } + + private class VerifiableCallback implements KernelCpuUidTimeReader.Callback<long[]> { + SparseArray<long[]> mData = new SparseArray<>(); + + public void verify(int uid, long[] cpuTimes) { + long[] array = mData.get(uid); + assertNotNull(array); + assertArrayEquals(cpuTimes, array); + mData.remove(uid); + } + + public void clear() { + mData.clear(); + } + + @Override + public void onUidCpuTime(int uid, long[] times) { + long[] array = new long[times.length]; + System.arraycopy(times, 0, array, 0, array.length); + mData.put(uid, array); + } + + public void verifyNoMoreInteractions() { + assertEquals(0, mData.size()); + } + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java new file mode 100644 index 000000000000..1d3a98a89d95 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.FileUtils; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.SparseArray; + +import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.Random; + +/** + * Test class for {@link KernelCpuUidFreqTimeReader}. + * + * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidFreqTimeReaderTest + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class KernelCpuUidFreqTimeReaderTest { + private File mTestDir; + private File mTestFile; + private KernelCpuUidFreqTimeReader mReader; + private VerifiableCallback mCallback; + @Mock + private PowerProfile mPowerProfile; + + private Random mRand = new Random(12345); + private final int[] mUids = {0, 1, 22, 333, 4444, 55555}; + + private Context getContext() { + return InstrumentationRegistry.getContext(); + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mTestDir = getContext().getDir("test", Context.MODE_PRIVATE); + mTestFile = new File(mTestDir, "test.file"); + mReader = new KernelCpuUidFreqTimeReader(mTestFile.getAbsolutePath(), + new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false); + mCallback = new VerifiableCallback(); + } + + @After + public void tearDown() throws Exception { + FileUtils.deleteContents(mTestDir); + FileUtils.deleteContents(getContext().getFilesDir()); + } + + @Test + public void testReadFreqs_perClusterTimesNotAvailable() throws Exception { + final long[][] freqs = { + {1, 12, 123, 1234}, + {1, 12, 123, 23, 123, 1234, 12345, 123456}, + {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345}, + {1, 12, 123, 23, 2345, 234567} + }; + final int[] numClusters = {2, 2, 3, 1}; + final int[][] numFreqs = {{3, 6}, {4, 5}, {3, 5, 4}, {3}}; + for (int i = 0; i < freqs.length; ++i) { + mReader = new KernelCpuUidFreqTimeReader(mTestFile.getAbsolutePath(), + new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false); + setCpuClusterFreqs(numClusters[i], numFreqs[i]); + writeToFile(freqsLine(freqs[i])); + long[] actualFreqs = mReader.readFreqs(mPowerProfile); + assertArrayEquals(freqs[i], actualFreqs); + final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", + Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); + assertFalse(errMsg, mReader.perClusterTimesAvailable()); + + // Verify that a second call won't read the proc file again + assertTrue(mTestFile.delete()); + actualFreqs = mReader.readFreqs(mPowerProfile); + assertArrayEquals(freqs[i], actualFreqs); + assertFalse(errMsg, mReader.perClusterTimesAvailable()); + } + } + + @Test + public void testReadFreqs_perClusterTimesAvailable() throws Exception { + final long[][] freqs = { + {1, 12, 123, 1234}, + {1, 12, 123, 23, 123, 1234, 12345, 123456}, + {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345, 1234567} + }; + final int[] numClusters = {1, 2, 3}; + final int[][] numFreqs = {{4}, {3, 5}, {3, 5, 4}}; + for (int i = 0; i < freqs.length; ++i) { + mReader = new KernelCpuUidFreqTimeReader(mTestFile.getAbsolutePath(), + new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false); + setCpuClusterFreqs(numClusters[i], numFreqs[i]); + writeToFile(freqsLine(freqs[i])); + long[] actualFreqs = mReader.readFreqs(mPowerProfile); + assertArrayEquals(freqs[i], actualFreqs); + final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s", + Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i])); + assertTrue(errMsg, mReader.perClusterTimesAvailable()); + + // Verify that a second call won't read the proc file again + assertTrue(mTestFile.delete()); + actualFreqs = mReader.readFreqs(mPowerProfile); + assertArrayEquals(freqs[i], actualFreqs); + assertTrue(errMsg, mReader.perClusterTimesAvailable()); + } + } + + @Test + public void testReadDelta() throws Exception { + final long[] freqs = {110, 123, 145, 167, 289, 997}; + final long[][] times = increaseTime(new long[mUids.length][freqs.length]); + + writeToFile(freqsLine(freqs) + uidLines(mUids, times)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], times[i]); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that readDelta also reads the frequencies if not already available. + assertTrue(mTestFile.delete()); + long[] actualFreqs = mReader.readFreqs(mPowerProfile); + assertArrayEquals(freqs, actualFreqs); + + // Verify that a second call will only return deltas. + mCallback.clear(); + final long[][] newTimes1 = increaseTime(times); + writeToFile(freqsLine(freqs) + uidLines(mUids, newTimes1)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], subtract(newTimes1[i], times[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that there won't be a callback if the proc file values didn't change. + mCallback.clear(); + mReader.readDelta(mCallback); + mCallback.verifyNoMoreInteractions(); + + // Verify that calling with a null callback doesn't result in any crashes + mCallback.clear(); + final long[][] newTimes2 = increaseTime(newTimes1); + writeToFile(freqsLine(freqs) + uidLines(mUids, newTimes2)); + mReader.readDelta(null); + mCallback.verifyNoMoreInteractions(); + + // Verify that the readDelta call will only return deltas when + // the previous call had null callback. + mCallback.clear(); + final long[][] newTimes3 = increaseTime(newTimes2); + writeToFile(freqsLine(freqs) + uidLines(mUids, newTimes3)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; ++i) { + mCallback.verify(mUids[i], subtract(newTimes3[i], newTimes2[i])); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadAbsolute() throws Exception { + final long[] freqs = {110, 123, 145, 167, 289, 997}; + final long[][] times1 = increaseTime(new long[mUids.length][freqs.length]); + + writeToFile(freqsLine(freqs) + uidLines(mUids, times1)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], times1[i]); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that readDelta also reads the frequencies if not already available. + assertTrue(mTestFile.delete()); + long[] actualFreqs = mReader.readFreqs(mPowerProfile); + assertArrayEquals(freqs, actualFreqs); + + // Verify that a second call should still return absolute values + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + writeToFile(freqsLine(freqs) + uidLines(mUids, times2)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], times2[i]); + } + mCallback.verifyNoMoreInteractions(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadDeltaWrongData() throws Exception { + final long[] freqs = {110, 123, 145, 167, 289, 997}; + final long[][] times1 = increaseTime(new long[mUids.length][freqs.length]); + + writeToFile(freqsLine(freqs) + uidLines(mUids, times1)); + mReader.readDelta(mCallback); + + // Verify that there should not be a callback for a particular UID if its time decreases. + mCallback.clear(); + final long[][] times2 = increaseTime(times1); + times2[0][0] = 1000; + writeToFile(freqsLine(freqs) + uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(times2[i], times1[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that the internal state was not modified. + mCallback.clear(); + final long[][] times3 = increaseTime(times2); + times3[0] = increaseTime(times1)[0]; + writeToFile(freqsLine(freqs) + uidLines(mUids, times3)); + mReader.readDelta(mCallback); + mCallback.verify(mUids[0], subtract(times3[0], times1[0])); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(times3[i], times2[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that there is no callback if any value in the proc file is -ve. + mCallback.clear(); + final long[][] times4 = increaseTime(times3); + times4[0][0] *= -1; + writeToFile(freqsLine(freqs) + uidLines(mUids, times4)); + mReader.readDelta(mCallback); + for (int i = 1; i < mUids.length; ++i) { + mCallback.verify(mUids[i], subtract(times4[i], times3[i])); + } + mCallback.verifyNoMoreInteractions(); + + // Verify that the internal state was not modified when the proc file had -ve value. + mCallback.clear(); + final long[][] times5 = increaseTime(times4); + times5[0] = increaseTime(times3)[0]; + writeToFile(freqsLine(freqs) + uidLines(mUids, times5)); + mReader.readDelta(mCallback); + mCallback.verify(mUids[0], subtract(times5[0], times3[0])); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(times5[i], times4[i])); + } + + assertTrue(mTestFile.delete()); + } + + private String freqsLine(long[] freqs) { + final StringBuilder sb = new StringBuilder(); + sb.append("uid:"); + for (int i = 0; i < freqs.length; ++i) { + sb.append(" " + freqs[i]); + } + return sb.append('\n').toString(); + } + + private void setCpuClusterFreqs(int numClusters, int... clusterFreqs) { + assertEquals(numClusters, clusterFreqs.length); + when(mPowerProfile.getNumCpuClusters()).thenReturn(numClusters); + for (int i = 0; i < numClusters; ++i) { + when(mPowerProfile.getNumSpeedStepsInCpuCluster(i)).thenReturn(clusterFreqs[i]); + } + } + + private String uidLines(int[] uids, long[][] times) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < uids.length; i++) { + sb.append(uids[i]).append(':'); + for (int j = 0; j < times[i].length; j++) { + sb.append(' ').append(times[i][j] / 10); + } + sb.append('\n'); + } + return sb.toString(); + } + + private void writeToFile(String s) throws IOException { + try (BufferedWriter w = Files.newBufferedWriter(mTestFile.toPath())) { + w.write(s); + w.flush(); + } + } + + private long[][] increaseTime(long[][] original) { + long[][] newTime = new long[original.length][original[0].length]; + for (int i = 0; i < original.length; i++) { + for (int j = 0; j < original[0].length; j++) { + newTime[i][j] = original[i][j] + mRand.nextInt(10000) * 10 + 10; + } + } + return newTime; + } + + private long[] subtract(long[] a1, long[] a2) { + long[] val = new long[a1.length]; + for (int i = 0; i < val.length; ++i) { + val[i] = a1[i] - a2[i]; + } + return val; + } + + private class VerifiableCallback implements KernelCpuUidTimeReader.Callback<long[]> { + SparseArray<long[]> mData = new SparseArray<>(); + + public void verify(int uid, long[] cpuTimes) { + long[] array = mData.get(uid); + assertNotNull(array); + assertArrayEquals(cpuTimes, array); + mData.remove(uid); + } + + public void clear() { + mData.clear(); + } + + @Override + public void onUidCpuTime(int uid, long[] times) { + long[] array = new long[times.length]; + System.arraycopy(times, 0, array, 0, array.length); + mData.put(uid, array); + } + + public void verifyNoMoreInteractions() { + assertEquals(0, mData.size()); + } + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java new file mode 100644 index 000000000000..9b4512b8b9bd --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.os.FileUtils; +import android.os.SystemClock; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.SparseArray; + +import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Random; + +/** + * Test class for {@link KernelCpuUidUserSysTimeReader}. + * + * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidUserSysTimeReaderTest + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class KernelCpuUidUserSysTimeReaderTest { + private File mTestDir; + private File mTestFile; + private KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader mReader; + private VerifiableCallback mCallback; + + private Random mRand = new Random(12345); + private final int[] mUids = {0, 1, 22, 333, 4444, 55555}; + private final long[][] mInitialTimes = new long[][]{ + {15334000, 310964000}, + {537000, 114000}, + {40000, 10000}, + {170000, 57000}, + {5377000, 867000}, + {47000, 17000} + }; + + private Context getContext() { + return InstrumentationRegistry.getContext(); + } + + @Before + public void setUp() { + mTestDir = getContext().getDir("test", Context.MODE_PRIVATE); + mTestFile = new File(mTestDir, "test.file"); + mReader = new KernelCpuUidUserSysTimeReader( + new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false); + mCallback = new VerifiableCallback(); + } + + @After + public void tearDown() throws Exception { + FileUtils.deleteContents(mTestDir); + FileUtils.deleteContents(getContext().getFilesDir()); + } + + @Test + public void testThrottler() throws Exception { + mReader = new KernelCpuUidUserSysTimeReader( + new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), true); + mReader.setThrottle(500); + + writeToFile(uidLines(mUids, mInitialTimes)); + mReader.readDelta(mCallback); + assertEquals(6, mCallback.mData.size()); + + long[][] times1 = increaseTime(mInitialTimes); + writeToFile(uidLines(mUids, times1)); + mCallback.clear(); + mReader.readDelta(mCallback); + assertEquals(0, mCallback.mData.size()); + + SystemClock.sleep(600); + + long[][] times2 = increaseTime(times1); + writeToFile(uidLines(mUids, times2)); + mCallback.clear(); + mReader.readDelta(mCallback); + assertEquals(6, mCallback.mData.size()); + + long[][] times3 = increaseTime(times2); + writeToFile(uidLines(mUids, times3)); + mCallback.clear(); + mReader.readDelta(mCallback); + assertEquals(0, mCallback.mData.size()); + } + + @Test + public void testReadDelta() throws Exception { + final long[][] times1 = mInitialTimes; + writeToFile(uidLines(mUids, times1)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], times1[i]); + } + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + + // Verify that a second call will only return deltas. + final long[][] times2 = increaseTime(times1); + writeToFile(uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(times2[i], times1[i])); + } + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + + // Verify that there won't be a callback if the proc file values didn't change. + mReader.readDelta(mCallback); + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + + // Verify that calling with a null callback doesn't result in any crashes + final long[][] times3 = increaseTime(times2); + writeToFile(uidLines(mUids, times3)); + mReader.readDelta(null); + + // Verify that the readDelta call will only return deltas when + // the previous call had null callback. + final long[][] times4 = increaseTime(times3); + writeToFile(uidLines(mUids, times4)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(times4[i], times3[i])); + } + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadDeltaWrongData() throws Exception { + final long[][] times1 = mInitialTimes; + writeToFile(uidLines(mUids, times1)); + mReader.readDelta(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], times1[i]); + } + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + + // Verify that there should not be a callback for a particular UID if its time decreases. + final long[][] times2 = increaseTime(times1); + times2[0][0] = 1000; + writeToFile(uidLines(mUids, times2)); + mReader.readDelta(mCallback); + for (int i = 1; i < mUids.length; i++) { + mCallback.verify(mUids[i], subtract(times2[i], times1[i])); + } + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + assertTrue(mTestFile.delete()); + } + + @Test + public void testReadAbsolute() throws Exception { + final long[][] times1 = mInitialTimes; + writeToFile(uidLines(mUids, times1)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], times1[i]); + } + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + + // Verify that a second call should still return absolute values + final long[][] times2 = increaseTime(times1); + writeToFile(uidLines(mUids, times2)); + mReader.readAbsolute(mCallback); + for (int i = 0; i < mUids.length; i++) { + mCallback.verify(mUids[i], times2[i]); + } + mCallback.verifyNoMoreInteractions(); + mCallback.clear(); + assertTrue(mTestFile.delete()); + } + + private String uidLines(int[] uids, long[][] times) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < uids.length; i++) { + sb.append(uids[i]).append(':'); + for (int j = 0; j < times[i].length; j++) { + sb.append(' ').append(times[i][j]); + } + sb.append('\n'); + } + return sb.toString(); + } + + private void writeToFile(String s) throws IOException { + try (BufferedWriter w = Files.newBufferedWriter(mTestFile.toPath())) { + w.write(s); + w.flush(); + } + } + + private long[][] increaseTime(long[][] original) { + long[][] newTime = new long[original.length][original[0].length]; + for (int i = 0; i < original.length; i++) { + for (int j = 0; j < original[0].length; j++) { + newTime[i][j] = original[i][j] + mRand.nextInt(1000) * 1000 + 1000; + } + } + return newTime; + } + + private long[] subtract(long[] a1, long[] a2) { + long[] val = new long[a1.length]; + for (int i = 0; i < val.length; ++i) { + val[i] = a1[i] - a2[i]; + } + return val; + } + + private class VerifiableCallback implements KernelCpuUidTimeReader.Callback<long[]> { + SparseArray<long[]> mData = new SparseArray<>(); + + public void verify(int uid, long[] cpuTimes) { + long[] array = mData.get(uid); + assertNotNull(array); + assertArrayEquals(cpuTimes, array); + mData.remove(uid); + } + + public void clear() { + mData.clear(); + } + + @Override + public void onUidCpuTime(int uid, long[] times) { + long[] array = new long[times.length]; + System.arraycopy(times, 0, array, 0, array.length); + mData.put(uid, array); + } + + public void verifyNoMoreInteractions() { + assertEquals(0, mData.size()); + } + } +} diff --git a/data/etc/platform.xml b/data/etc/platform.xml index a4c5ed2ee30f..141948f1d25c 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -201,6 +201,24 @@ <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </split-permission> + <!-- Apps holding either the legacy READ or WRITE permissions will inherit + the ability to <em>read</em> new typed permissions in the Q release; they + won't gain the ability to <em>write</em> that content. --> + <!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised --> + <split-permission name="android.permission.READ_EXTERNAL_STORAGE" + targetSdk="10000"> + <new-permission name="android.permission.READ_MEDIA_AUDIO" /> + <new-permission name="android.permission.READ_MEDIA_VIDEO" /> + <new-permission name="android.permission.READ_MEDIA_IMAGES" /> + </split-permission> + <!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised --> + <split-permission name="android.permission.WRITE_EXTERNAL_STORAGE" + targetSdk="10000"> + <new-permission name="android.permission.READ_MEDIA_AUDIO" /> + <new-permission name="android.permission.READ_MEDIA_VIDEO" /> + <new-permission name="android.permission.READ_MEDIA_IMAGES" /> + </split-permission> + <!-- This is a list of all the libraries available for application code to link against. --> diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index bf969ef15c5b..acb46b39daf5 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -652,6 +652,17 @@ public class Typeface { private @Nullable FontStyle mStyle; /** + * Returns the maximum capacity of custom fallback families. + * + * This includes the the first font family passed to the constructor. + * + * @return the maximum number of font families for the custom fallback + */ + public static @IntRange(from = 1) int getMaxCustomFallbackCount() { + return MAX_CUSTOM_FALLBACK; + } + + /** * Constructs a builder with a font family. * * @param family a family object @@ -706,8 +717,8 @@ public class Typeface { */ public CustomFallbackBuilder addCustomFallback(@NonNull FontFamily family) { Preconditions.checkNotNull(family); - Preconditions.checkArgument(mFamilies.size() < MAX_CUSTOM_FALLBACK, - "Custom fallback limit exceeded(" + MAX_CUSTOM_FALLBACK + ")"); + Preconditions.checkArgument(mFamilies.size() < getMaxCustomFallbackCount(), + "Custom fallback limit exceeded(" + getMaxCustomFallbackCount() + ")"); mFamilies.add(family); return this; } diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java index 0119a02c79cf..dea2f45e9d33 100644 --- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java +++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java @@ -670,7 +670,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback @Override public int getAlpha() { - return PixelFormat.TRANSLUCENT; + return mPaint.getAlpha(); } @Override @@ -714,10 +714,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback @Override public int getOpacity() { - if (mLayerState.mOpacityOverride != PixelFormat.UNKNOWN) { - return mLayerState.mOpacityOverride; - } - return mLayerState.getOpacity(); + return PixelFormat.TRANSLUCENT; } @Override diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index f7fb89e54ef3..2fe98b00f3a2 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -7035,40 +7035,70 @@ status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { return NO_ERROR; } -struct IdmapMatchingResources { - void Add(uint32_t targetResId, uint32_t overlayResId) { - uint8_t targetTypeid = Res_GETTYPE(targetResId); - if (typeMappings.find(targetTypeid) == typeMappings.end()) { - typeMappings.emplace(targetTypeid, std::set<std::pair<uint32_t, uint32_t>>()); +class IdmapMatchingResources; + +class IdmapTypeMapping { +public: + void add(uint32_t targetResId, uint32_t overlayResId) { + uint8_t targetTypeId = Res_GETTYPE(targetResId); + if (mData.find(targetTypeId) == mData.end()) { + mData.emplace(targetTypeId, std::set<std::pair<uint32_t, uint32_t>>()); } - auto& entries = typeMappings[targetTypeid]; + auto& entries = mData[targetTypeId]; entries.insert(std::make_pair(targetResId, overlayResId)); } - void FixPadding() { - for (auto ti = typeMappings.cbegin(); ti != typeMappings.cend(); ++ti) { - uint32_t last_seen = 0xffffffff; - size_t total_entries = 0; + bool empty() const { + return mData.empty(); + } + +private: + // resource type ID in context of target -> set of resource entries mapping target -> overlay + std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> mData; + + friend IdmapMatchingResources; +}; + +class IdmapMatchingResources { +public: + IdmapMatchingResources(std::unique_ptr<IdmapTypeMapping> tm) : mTypeMapping(std::move(tm)) { + assert(mTypeMapping); + for (auto ti = mTypeMapping->mData.cbegin(); ti != mTypeMapping->mData.cend(); ++ti) { + uint32_t lastSeen = 0xffffffff; + size_t totalEntries = 0; for (auto ei = ti->second.cbegin(); ei != ti->second.cend(); ++ei) { - assert(last_seen == 0xffffffff || last_seen < ei->first); - entryPadding[ei->first] = (last_seen == 0xffffffff) ? 0 : ei->first - last_seen - 1; - last_seen = ei->first; - total_entries += 1 + entryPadding[ei->first]; + assert(lastSeen == 0xffffffff || lastSeen < ei->first); + mEntryPadding[ei->first] = (lastSeen == 0xffffffff) ? 0 : ei->first - lastSeen - 1; + lastSeen = ei->first; + totalEntries += 1 + mEntryPadding[ei->first]; } - numberOfEntriesIncludingPadding[ti->first] = total_entries; + mNumberOfEntriesIncludingPadding[ti->first] = totalEntries; } } + const auto& getTypeMapping() const { + return mTypeMapping->mData; + } + + size_t getNumberOfEntriesIncludingPadding(uint8_t type) const { + return mNumberOfEntriesIncludingPadding.at(type); + } + + size_t getPadding(uint32_t resid) const { + return mEntryPadding.at(resid); + } + +private: // resource type ID in context of target -> set of resource entries mapping target -> overlay - std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> typeMappings; + const std::unique_ptr<IdmapTypeMapping> mTypeMapping; // resource ID in context of target -> trailing padding for that resource (call FixPadding // before use) - std::map<uint32_t, size_t> entryPadding; + std::map<uint32_t, size_t> mEntryPadding; // resource type ID in context of target -> total number of entries, including padding entries, // for that type (call FixPadding before use) - std::map<uint8_t, size_t> numberOfEntriesIncludingPadding; + std::map<uint8_t, size_t> mNumberOfEntriesIncludingPadding; }; status_t ResTable::createIdmap(const ResTable& targetResTable, @@ -7098,7 +7128,8 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, return UNKNOWN_ERROR; } - const ResTable_package* targetPackageStruct = targetResTable.mPackageGroups[0]->packages[0]->package; + const ResTable_package* targetPackageStruct = + targetResTable.mPackageGroups[0]->packages[0]->package; const size_t tmpNameSize = arraysize(targetPackageStruct->name); char16_t tmpName[tmpNameSize]; strcpy16_dtoh(tmpName, targetPackageStruct->name, tmpNameSize); @@ -7110,7 +7141,7 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, size_t forcedOverlayCount = 0u; // find the resources that exist in both packages - IdmapMatchingResources matchingResources; + auto typeMapping = std::make_unique<IdmapTypeMapping>(); for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) { const TypeList& typeList = packageGroup->types[typeIndex]; if (typeList.isEmpty()) { @@ -7144,24 +7175,25 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, ++forcedOverlayCount; } - matchingResources.Add(target_resid, overlay_resid); + typeMapping->add(target_resid, overlay_resid); } } - if (matchingResources.typeMappings.empty()) { + if (typeMapping->empty()) { ALOGE("idmap: no matching resources"); return UNKNOWN_ERROR; } - matchingResources.FixPadding(); + const IdmapMatchingResources matchingResources(std::move(typeMapping)); // write idmap *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; // magic, version, target and overlay crc *outSize += 2 * sizeof(uint16_t); // target package id, type count - const auto typesEnd = matchingResources.typeMappings.cend(); - for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) { + auto fixedTypeMapping = matchingResources.getTypeMapping(); + const auto typesEnd = fixedTypeMapping.cend(); + for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) { *outSize += 4 * sizeof(uint16_t); // target type, overlay type, entry count, entry offset - *outSize += matchingResources.numberOfEntriesIncludingPadding[ti->first] * + *outSize += matchingResources.getNumberOfEntriesIncludingPadding(ti->first) * sizeof(uint32_t); // entries } if ((*outData = malloc(*outSize)) == NULL) { @@ -7190,11 +7222,11 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, uint16_t* typeData = reinterpret_cast<uint16_t*>(data); *typeData++ = htods(targetPackageStruct->id); // write: target package id *typeData++ = - htods(static_cast<uint16_t>(matchingResources.typeMappings.size())); // write: type count + htods(static_cast<uint16_t>(fixedTypeMapping.size())); // write: type count // write idmap data - for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) { - const size_t entryCount = matchingResources.numberOfEntriesIncludingPadding[ti->first]; + for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) { + const size_t entryCount = matchingResources.getNumberOfEntriesIncludingPadding(ti->first); auto ei = ti->second.cbegin(); *typeData++ = htods(Res_GETTYPE(ei->first) + 1); // write: target type id *typeData++ = htods(Res_GETTYPE(ei->second) + 1); // write: overlay type id @@ -7202,7 +7234,7 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, *typeData++ = htods(Res_GETENTRY(ei->first)); // write: (target) entry offset uint32_t *entryData = reinterpret_cast<uint32_t*>(typeData); for (; ei != ti->second.cend(); ++ei) { - const size_t padding = matchingResources.entryPadding[ei->first]; + const size_t padding = matchingResources.getPadding(ei->first); for (size_t i = 0; i < padding; ++i) { *entryData++ = htodl(0xffffffff); // write: padding } diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index b772e5b87f2a..3bee3018d36e 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -85,19 +85,18 @@ void DeferredLayerUpdater::apply() { mUpdateTexImage = false; sk_sp<SkImage> layerImage; SkMatrix textureTransform; - android_dataspace dataSpace; bool queueEmpty = true; // If the SurfaceTexture queue is in synchronous mode, need to discard all // but latest frame. Since we can't tell which mode it is in, // do this unconditionally. do { - layerImage = mSurfaceTexture->dequeueImage(textureTransform, dataSpace, &queueEmpty, + layerImage = mSurfaceTexture->dequeueImage(textureTransform, &queueEmpty, mRenderState); } while (layerImage.get() && (!queueEmpty)); if (layerImage.get()) { // force filtration if buffer size != layer size bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height(); - updateLayer(forceFilter, textureTransform, dataSpace, layerImage); + updateLayer(forceFilter, textureTransform, layerImage); } } @@ -109,12 +108,11 @@ void DeferredLayerUpdater::apply() { } void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform, - android_dataspace dataspace, const sk_sp<SkImage>& layerImage) { + const sk_sp<SkImage>& layerImage) { mLayer->setBlend(mBlend); mLayer->setForceFilter(forceFilter); mLayer->setSize(mWidth, mHeight); mLayer->getTexTransform() = textureTransform; - mLayer->setDataSpace(dataspace); mLayer->setImage(layerImage); } diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index b2c5131dd613..a91c111933c4 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -95,7 +95,7 @@ public: void detachSurfaceTexture(); void updateLayer(bool forceFilter, const SkMatrix& textureTransform, - android_dataspace dataspace, const sk_sp<SkImage>& layerImage); + const sk_sp<SkImage>& layerImage); void destroyLayer(); diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 32aaa54e696c..d0df200d2fa6 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -33,7 +33,6 @@ Layer::Layer(RenderState& renderState, sk_sp<SkColorFilter> colorFilter, int alp // TODO: This is a violation of Android's typical ref counting, but it // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); - buildColorSpaceWithFilter(); renderState.registerLayer(this); texTransform.setIdentity(); transform.setIdentity(); @@ -43,36 +42,6 @@ Layer::~Layer() { mRenderState.unregisterLayer(this); } -void Layer::setColorFilter(sk_sp<SkColorFilter> filter) { - if (filter != mColorFilter) { - mColorFilter = filter; - buildColorSpaceWithFilter(); - } -} - -void Layer::setDataSpace(android_dataspace dataspace) { - if (dataspace != mCurrentDataspace) { - mCurrentDataspace = dataspace; - buildColorSpaceWithFilter(); - } -} - -void Layer::buildColorSpaceWithFilter() { - sk_sp<SkColorFilter> colorSpaceFilter; - sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace); - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } - - if (mColorFilter && colorSpaceFilter) { - mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter); - } else if (colorSpaceFilter) { - mColorSpaceWithFilter = colorSpaceFilter; - } else { - mColorSpaceWithFilter = mColorFilter; - } -} - void Layer::postDecStrong() { mRenderState.postDecStrong(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index e4f96e914c36..98600dbf1eea 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -69,15 +69,9 @@ public: SkBlendMode getMode() const; - inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); } + inline sk_sp<SkColorFilter> getColorFilter() const { return mColorFilter; } - void setColorFilter(sk_sp<SkColorFilter> filter); - - void setDataSpace(android_dataspace dataspace); - - void setColorSpace(sk_sp<SkColorSpace> colorSpace); - - inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; } + void setColorFilter(sk_sp<SkColorFilter> filter) { mColorFilter = filter; }; inline SkMatrix& getTexTransform() { return texTransform; } @@ -98,24 +92,12 @@ protected: RenderState& mRenderState; private: - void buildColorSpaceWithFilter(); - /** * Color filter used to draw this layer. Optional. */ sk_sp<SkColorFilter> mColorFilter; /** - * Colorspace of the contents of the layer. Optional. - */ - android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN; - - /** - * A color filter that is the combination of the mColorFilter and mColorSpace. Optional. - */ - sk_sp<SkColorFilter> mColorSpaceWithFilter; - - /** * Indicates raster data backing the layer is scaled, requiring filtration. */ bool forceFilter = false; diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index f0a3a959617d..1b5cb60ca4bd 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -27,6 +27,7 @@ namespace android { namespace uirenderer { #define SK_MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]" +#define SK_MATRIX_STRING_V "[%.9f %.9f %.9f] [%.9f %.9f %.9f] [%.9f %.9f %.9f]" #define SK_MATRIX_ARGS(m) \ (m)->get(0), (m)->get(1), (m)->get(2), (m)->get(3), (m)->get(4), (m)->get(5), (m)->get(6), \ (m)->get(7), (m)->get(8) diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 80f2b5714659..2a488378e3a8 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -66,13 +66,10 @@ CopyResult Readback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBi sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(static_cast<android_dataspace>(surface.getBuffersDataSpace())); - sk_sp<SkColorFilter> colorSpaceFilter; - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), kPremul_SkAlphaType); - return copyImageInto(image, colorSpaceFilter, texTransform, srcRect, bitmap); + reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), + kPremul_SkAlphaType, colorSpace); + return copyImageInto(image, texTransform, srcRect, bitmap); } CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { @@ -83,20 +80,7 @@ CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { transform.loadScale(1, -1, 1); transform.translate(0, -1); - // TODO: Try to take and reuse the image inside HW bitmap with "hwBitmap->makeImage". - // TODO: When this was attempted, it resulted in instability. - sk_sp<SkColorFilter> colorSpaceFilter; - sk_sp<SkColorSpace> colorSpace = hwBitmap->info().refColorSpace(); - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } - sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(hwBitmap->graphicBuffer()), kPremul_SkAlphaType); - - // HW Bitmap currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 format - // and SRGB color space. ImageDecoder can create a new HW Bitmap with non-SRGB color space: for - // example see android.graphics.cts.BitmapColorSpaceTest#testEncodeP3hardware test. - return copyImageInto(image, colorSpaceFilter, transform, srcRect, bitmap); + return copyImageInto(hwBitmap->makeImage(), transform, srcRect, bitmap); } CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) { @@ -118,8 +102,7 @@ CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap return copyResult; } -CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, - sk_sp<SkColorFilter>& colorSpaceFilter, Matrix4& texTransform, +CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { mRenderThread.requireGlContext(); @@ -157,11 +140,7 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, return copyResult; } - // See Readback::copyLayerInto for an overview of color space conversion. - // HW Bitmap are allowed to be in a non-SRGB color space (for example coming from ImageDecoder). - // For Surface and HW Bitmap readback flows we pass colorSpaceFilter, which does the conversion. - // TextureView readback is using Layer::setDataSpace, which creates a SkColorFilter internally. - Layer layer(mRenderThread.renderState(), colorSpaceFilter, 255, SkBlendMode::kSrc); + Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc); bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height()); layer.setForceFilter(!disableFilter); @@ -177,38 +156,6 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, SkBitmap* bitmap) { - /* - * In the past only TextureView readback was setting the temporary surface color space to null. - * Now all 3 readback flows are drawing into a SkSurface with null color space. - * At readback there are 3 options to convert the source image color space to the destination - * color space requested in "bitmap->info().colorSpace()": - * 1. Set color space for temporary surface render target to null (disables color management), - * colorspace tag from source SkImage is ignored by Skia, - * convert SkImage to SRGB at draw time with SkColorFilter/SkToSRGBColorFilter, - * do a readback from temporary SkSurface to a temporary SRGB SkBitmap "bitmap2", - * read back from SRGB "bitmap2" into non-SRGB "bitmap" which will do a CPU color conversion. - * - * 2. Set color space for temporary surface render target to SRGB (not nullptr), - * colorspace tag on the source SkImage is used by Skia to enable conversion, - * convert SkImage to SRGB at draw time with drawImage (no filters), - * do a readback from temporary SkSurface, which will do a color conversion from SRGB to - * bitmap->info().colorSpace() on the CPU. - * - * 3. Set color space for temporary surface render target to bitmap->info().colorSpace(), - * colorspace tag on the source SkImage is used by Skia to enable conversion, - * convert SkImage to bitmap->info().colorSpace() at draw time with drawImage (no filters), - * do a readback from SkSurface, which will not do any color conversion, because - * surface was created with the same color space as the "bitmap". - * - * Option 1 is used for all readback flows. - * Options 2 and 3 are new, because skia added support for non-SRGB render targets without - * linear blending. - * TODO: evaluate if options 2 or 3 for color space conversion are better. - */ - - // drop the colorSpace from the temporary surface. - SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr); - /* This intermediate surface is present to work around a bug in SwiftShader that * prevents us from reading the contents of the layer's texture directly. The * workaround involves first rendering that texture into an intermediate buffer and @@ -217,70 +164,44 @@ bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* * with reading incorrect data from EGLImage backed SkImage (likely a driver bug). */ sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), - SkBudgeted::kYes, surfaceInfo); + SkBudgeted::kYes, bitmap->info()); + // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we + // attempt to do the intermediate rendering step in 8888 if (!tmpSurface.get()) { - surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType); + SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType); tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, - surfaceInfo); + tmpInfo); if (!tmpSurface.get()) { - ALOGW("Unable to readback GPU contents into the provided bitmap"); + ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap"); return false; } } - if (skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(), - tmpSurface->getCanvas(), layer, srcRect, dstRect, - false)) { - // If bitmap->info().colorSpace() is non-SRGB, convert the data from SRGB to non-SRGB on - // CPU. We can't just pass bitmap->info() to SkSurface::readPixels, because "tmpSurface" has - // disabled color conversion. - SkColorSpace* destColorSpace = bitmap->info().colorSpace(); - SkBitmap tempSRGBBitmap; - SkBitmap tmpN32Bitmap; - SkBitmap* bitmapInSRGB; - if (destColorSpace && !destColorSpace->isSRGB()) { - tempSRGBBitmap.allocPixels(bitmap->info().makeColorSpace(SkColorSpace::MakeSRGB())); - bitmapInSRGB = &tempSRGBBitmap; // Need to convert latter from SRGB to non-SRGB. - } else { - bitmapInSRGB = bitmap; // No need for color conversion - write directly into output. - } - bool success = false; - - // TODO: does any of the readbacks below clamp F16 exSRGB? - // Readback into a SRGB SkBitmap. - if (tmpSurface->readPixels(bitmapInSRGB->info(), bitmapInSRGB->getPixels(), - bitmapInSRGB->rowBytes(), 0, 0)) { - success = true; - } else { - // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into - // 8888 and then convert that into the destination format before giving up. - SkImageInfo bitmapInfo = - SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType(), - SkColorSpace::MakeSRGB()); - if (tmpN32Bitmap.tryAllocPixels(bitmapInfo) && - tmpSurface->readPixels(bitmapInfo, tmpN32Bitmap.getPixels(), - tmpN32Bitmap.rowBytes(), 0, 0)) { - success = true; - bitmapInSRGB = &tmpN32Bitmap; - } - } - - if (success) { - if (bitmapInSRGB != bitmap) { - // Convert from SRGB to non-SRGB color space if needed. Convert from N32 to - // destination bitmap color format if needed. - if (!bitmapInSRGB->readPixels(bitmap->info(), bitmap->getPixels(), - bitmap->rowBytes(), 0, 0)) { - return false; - } - } - bitmap->notifyPixelsChanged(); - return true; + if (!skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(), + tmpSurface->getCanvas(), layer, srcRect, dstRect, + false)) { + ALOGW("Unable to draw content from GPU into the provided bitmap"); + return false; + } + + if (!tmpSurface->readPixels(*bitmap, 0, 0)) { + // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into + // 8888 and then convert that into the destination format before giving up. + SkBitmap tmpBitmap; + SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType); + if (bitmap->info().colorType() == SkColorType::kN32_SkColorType || + !tmpBitmap.tryAllocPixels(tmpInfo) || + !tmpSurface->readPixels(tmpBitmap, 0, 0) || + !tmpBitmap.readPixels(bitmap->info(), bitmap->getPixels(), + bitmap->rowBytes(), 0, 0)) { + ALOGW("Unable to convert content into the provided bitmap"); + return false; } } - return false; + bitmap->notifyPixelsChanged(); + return true; } } /* namespace uirenderer */ diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index d9e10cedc0e8..e86a8136cfa3 100644 --- a/libs/hwui/Readback.h +++ b/libs/hwui/Readback.h @@ -54,8 +54,8 @@ public: CopyResult copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); private: - CopyResult copyImageInto(const sk_sp<SkImage>& image, sk_sp<SkColorFilter>& colorSpaceFilter, - Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap); + CopyResult copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform, + const Rect& srcRect, SkBitmap* bitmap); bool copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, SkBitmap* bitmap); diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 9a15ff2de463..ba343841d760 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -27,7 +27,6 @@ #include <SkAnimatedImage.h> #include <SkCanvasStateUtils.h> #include <SkColorFilter.h> -#include <SkColorSpaceXformCanvas.h> #include <SkDeque.h> #include <SkDrawable.h> #include <SkFont.h> @@ -61,19 +60,8 @@ SkiaCanvas::SkiaCanvas() {} SkiaCanvas::SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {} SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { - sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); - mCanvasOwned = - std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - if (cs.get() == nullptr || cs->isSRGB()) { - mCanvas = mCanvasOwned.get(); - } else { - /** The wrapper is needed if we are drawing into a non-sRGB destination, since - * we need to transform all colors (not just bitmaps via filters) into the - * destination's colorspace. - */ - mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), std::move(cs)); - mCanvas = mCanvasWrapper.get(); - } + mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap)); + mCanvas = mCanvasOwned.get(); } SkiaCanvas::~SkiaCanvas() {} @@ -82,7 +70,6 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { if (mCanvas != skiaCanvas) { mCanvas = skiaCanvas; mCanvasOwned.reset(); - mCanvasWrapper.reset(); } mSaveStack.reset(nullptr); } @@ -92,18 +79,9 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { // ---------------------------------------------------------------------------- void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { - sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); - std::unique_ptr<SkCanvas> newCanvas = - std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - std::unique_ptr<SkCanvas> newCanvasWrapper; - if (cs.get() != nullptr && !cs->isSRGB()) { - newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs)); - } - // deletes the previously owned canvas (if any) - mCanvasOwned = std::move(newCanvas); - mCanvasWrapper = std::move(newCanvasWrapper); - mCanvas = mCanvasWrapper ? mCanvasWrapper.get() : mCanvasOwned.get(); + mCanvasOwned.reset(new SkCanvas(bitmap)); + mCanvas = mCanvasOwned.get(); // clean up the old save stack mSaveStack.reset(nullptr); @@ -548,40 +526,14 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons // Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- -SkiaCanvas::PaintCoW&& SkiaCanvas::filterBitmap(PaintCoW&& paint, - sk_sp<SkColorFilter> colorSpaceFilter) const { - /* We don't apply the colorSpace filter if this canvas is already wrapped with - * a SkColorSpaceXformCanvas since it already takes care of converting the - * contents of the bitmap into the appropriate colorspace. The mCanvasWrapper - * should only be used if this canvas is backed by a surface/bitmap that is known - * to have a non-sRGB colorspace. - */ - if (!mCanvasWrapper && colorSpaceFilter) { - SkPaint& tmpPaint = paint.writeable(); - if (tmpPaint.getColorFilter()) { - tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter(tmpPaint.refColorFilter(), - std::move(colorSpaceFilter))); - LOG_ALWAYS_FATAL_IF(!tmpPaint.getColorFilter()); - } else { - tmpPaint.setColorFilter(std::move(colorSpaceFilter)); - } - } - return filterPaint(std::move(paint)); -} - void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImage(bitmap.makeImage(), left, top, filterPaint(paint)); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(mCanvas, true); mCanvas->concat(matrix); - - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImage(bitmap.makeImage(), 0, 0, filterPaint(paint)); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, @@ -590,9 +542,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), + mCanvas->drawImageRect(bitmap.makeImage(), srcRect, dstRect, filterPaint(paint), SkCanvas::kFast_SrcRectConstraint); } @@ -674,13 +624,9 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, PaintCoW paintCoW(paint); SkPaint& tmpPaint = paintCoW.writeable(); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - if (colorFilter) { - shader = shader->makeWithColorFilter(std::move(colorFilter)); - } tmpPaint.setShader(std::move(shader)); mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, @@ -711,10 +657,7 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageLattice(image.get(), lattice, dst, - filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImageLattice(bitmap.makeImage().get(), lattice, dst, filterPaint(paint)); } double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) { diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 3a877cf84010..24d9c08ec1c6 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -232,7 +232,6 @@ private: class Clip; - std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us // unless it is the same as mCanvasOwned.get() diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 75a6e722dd8a..6c77f9ee1845 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -32,7 +32,6 @@ #include <SkCanvas.h> #include <SkImagePriv.h> -#include <SkToSRGBColorFilter.h> #include <SkHighContrastFilter.h> #include <limits> @@ -287,14 +286,8 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) { void Bitmap::getSkBitmap(SkBitmap* outBitmap) { if (isHardware()) { - outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), - info().colorType(), info().alphaType(), nullptr)); + outBitmap->allocPixels(mInfo); uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap); - if (mInfo.colorSpace()) { - sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef()); - outBitmap->setInfo(mInfo); - outBitmap->setPixelRef(std::move(pixelRef), 0, 0); - } return; } outBitmap->setInfo(mInfo, rowBytes()); @@ -313,7 +306,7 @@ GraphicBuffer* Bitmap::graphicBuffer() { return nullptr; } -sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { +sk_sp<SkImage> Bitmap::makeImage() { sk_sp<SkImage> image = mImage; if (!image) { SkASSERT(!isHardware()); @@ -325,9 +318,6 @@ sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here. image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); } - if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) { - *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace()); - } return image; } diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index 238c764cdea6..d446377ec1d9 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -105,14 +105,8 @@ public: * Creates or returns a cached SkImage and is safe to be invoked from either * the UI or RenderThread. * - * @param outputColorFilter is a required param that will be populated by - * this function if the bitmap's colorspace is not sRGB. If populated the - * filter will convert colors from the bitmaps colorspace into sRGB. It - * is the callers responsibility to use this colorFilter when drawing - * this image into any destination that is presumed to be sRGB (i.e. a - * buffer that has no colorspace defined). */ - sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter); + sk_sp<SkImage> makeImage(); static BitmapPalette computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 13d2dae8e281..9b408fbc95ca 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <utils/MathUtils.h> #include "LayerDrawable.h" #include "GrBackendSurface.h" @@ -32,6 +33,24 @@ void LayerDrawable::onDraw(SkCanvas* canvas) { } } +// This is a less-strict matrix.isTranslate() that will still report being translate-only +// on imperceptibly small scaleX & scaleY values. +static bool isBasicallyTranslate(const SkMatrix& matrix) { + if (!matrix.isScaleTranslate()) return false; + return MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY()); +} + +static bool shouldFilter(const SkMatrix& matrix) { + if (!matrix.isScaleTranslate()) return true; + + // We only care about meaningful scale here + bool noScale = MathUtils::isOne(matrix.getScaleX()) + && MathUtils::isOne(matrix.getScaleY()); + bool pixelAligned = SkScalarIsInt(matrix.getTranslateX()) + && SkScalarIsInt(matrix.getTranslateY()); + return !(noScale && pixelAligned); +} + bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect, const SkRect* dstRect, bool useLayerTransform) { @@ -70,7 +89,7 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer SkPaint paint; paint.setAlpha(layer->getAlpha()); paint.setBlendMode(layer->getMode()); - paint.setColorFilter(layer->getColorSpaceWithFilter()); + paint.setColorFilter(layer->getColorFilter()); const bool nonIdentityMatrix = !matrix.isIdentity(); if (nonIdentityMatrix) { canvas->save(); @@ -101,7 +120,7 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer // Integer translation is defined as when src rect and dst rect align fractionally. // Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works // only for SrcOver blending and without color filter (readback uses Src blending). - bool isIntegerTranslate = totalMatrix.isTranslate() + bool isIntegerTranslate = isBasicallyTranslate(totalMatrix) && SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) == SkScalarFraction(skiaSrcRect.fLeft) && SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) @@ -112,10 +131,7 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint, SkCanvas::kFast_SrcRectConstraint); } else { - bool isIntegerTranslate = totalMatrix.isTranslate() - && SkScalarIsInt(totalMatrix[SkMatrix::kMTransX]) - && SkScalarIsInt(totalMatrix[SkMatrix::kMTransY]); - if (layer->getForceFilter() || !isIntegerTranslate) { + if (layer->getForceFilter() || shouldFilter(totalMatrix)) { paint.setFilterQuality(kLow_SkFilterQuality); } canvas->drawImage(layerImage.get(), 0, 0, &paint); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 6ae59990d0ab..142bca95e598 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -97,7 +97,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con SkASSERT(mRenderThread.getGrContext() != nullptr); sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget( mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType, - nullptr, &props)); + mSurfaceColorSpace, &props)); SkiaPipeline::updateLighting(lightGeometry, lightInfo); renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); @@ -176,6 +176,7 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, } else if (colorMode == ColorMode::WideColorGamut) { mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType; } + mSurfaceColorSpace = SkColorSpace::MakeSRGB(); if (mEglSurface != EGL_NO_SURFACE) { const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 2dfe7c71ca1b..7a255c15bf5f 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -169,7 +169,7 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) { SkImageInfo info; info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(), - kPremul_SkAlphaType); + kPremul_SkAlphaType, getSurfaceColorSpace()); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), @@ -204,8 +204,7 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { GrContext* context = thread.getGrContext(); if (context) { ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height()); - sk_sp<SkColorFilter> colorFilter; - auto image = bitmap->makeImage(&colorFilter); + auto image = bitmap->makeImage(); if (image.get() && !bitmap->isHardware()) { SkImage_pinAsTexture(image.get(), context); SkImage_unpinAsTexture(image.get(), context); diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 45022e733979..f5de1c8adfaf 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -179,9 +179,8 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint, } void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImage(image, left, top, filterPaint(paint), bitmap.palette()); // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means // it is not safe to store a raw SkImage pointer, because the image object will be destroyed // when this function ends. @@ -194,9 +193,8 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con SkAutoCanvasRestore acr(&mRecorder, true); concat(matrix); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImage(image, 0, 0, filterPaint(paint), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); } @@ -208,9 +206,8 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImageRect(image, srcRect, dstRect, filterPaint(paint), SkCanvas::kFast_SrcRectConstraint, bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { @@ -247,10 +244,9 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch if (!filteredPaint || filteredPaint->getFilterQuality() != kLow_SkFilterQuality) { filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality); } - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); mRecorder.drawImageLattice(image, lattice, dst, - filterBitmap(std::move(filteredPaint), std::move(colorFilter)), + filterPaint(std::move(filteredPaint)), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp index 9ffccfb4d340..15aec9f291a4 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.cpp +++ b/libs/hwui/surfacetexture/ImageConsumer.cpp @@ -22,6 +22,7 @@ #include "renderthread/EglManager.h" #include "renderthread/RenderThread.h" #include "renderthread/VulkanManager.h" +#include "utils/Color.h" // Macro for including the SurfaceTexture name in log messages #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) @@ -44,13 +45,16 @@ void ImageConsumer::onReleaseBufferLocked(int buf) { mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR; } -void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer) { - if (!mImage.get()) { +void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer, + android_dataspace dataspace) { + if (!mImage.get() || dataspace != mDataspace) { mImage = graphicBuffer.get() ? SkImage::MakeFromAHardwareBuffer( reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), - kPremul_SkAlphaType) + kPremul_SkAlphaType, + uirenderer::DataSpaceToColorSpace(dataspace)) : nullptr; + mDataspace = dataspace; } } @@ -66,7 +70,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, int slot = st.mCurrentTexture; if (slot != BufferItem::INVALID_BUFFER_SLOT) { *queueEmpty = true; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace); return mImageSlots[slot].mImage; } } @@ -145,7 +149,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, st.computeCurrentTransformMatrixLocked(); *queueEmpty = false; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace); return mImageSlots[slot].mImage; } diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h index 31ee8db52874..5bab0ef58a9a 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -68,18 +68,21 @@ private: * ImageConsumer maintains about a BufferQueue buffer slot. */ struct ImageSlot { - ImageSlot() : mEglFence(EGL_NO_SYNC_KHR) {} + ImageSlot() : mDataspace(HAL_DATASPACE_UNKNOWN), mEglFence(EGL_NO_SYNC_KHR) {} // mImage is the SkImage created from mGraphicBuffer. sk_sp<SkImage> mImage; + // the dataspace associated with the current image + android_dataspace mDataspace; + /** * mEglFence is the EGL sync object that must signal before the buffer * associated with this buffer slot may be dequeued. */ EGLSyncKHR mEglFence; - void createIfNeeded(sp<GraphicBuffer> graphicBuffer); + void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace); }; /** diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp index 4bff715822e8..90f891265572 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.cpp +++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp @@ -470,8 +470,7 @@ void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { ConsumerBase::dumpLocked(result, prefix); } -sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, - bool* queueEmpty, +sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, uirenderer::RenderState& renderState) { Mutex::Autolock _l(mMutex); @@ -488,7 +487,6 @@ sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_d auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState); if (image.get()) { uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix); - dataSpace = mCurrentDataSpace; } return image; } diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h index db392a9f8476..96afd82b0d40 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.h +++ b/libs/hwui/surfacetexture/SurfaceTexture.h @@ -258,8 +258,8 @@ public: */ status_t attachToContext(uint32_t tex); - sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, - bool* queueEmpty, uirenderer::RenderState& renderState); + sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, + uirenderer::RenderState& renderState); /** * attachToView attaches a SurfaceTexture that is currently in the diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 66b9b85bdbe7..8a1bc4d2f7f2 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -72,9 +72,7 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( layerUpdater->setTransform(&transform); // updateLayer so it's ready to draw - SkMatrix identity; - identity.setIdentity(); - layerUpdater->updateLayer(true, identity, HAL_DATASPACE_UNKNOWN, nullptr); + layerUpdater->updateLayer(true, SkMatrix::I(), nullptr); return layerUpdater; } diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp index 15039b5fa976..ad11a1d32310 100644 --- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp +++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp @@ -44,8 +44,7 @@ public: }); SkPaint paint; - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter); + sk_sp<SkImage> image = hwuiBitmap->makeImage(); sk_sp<SkShader> repeatShader = image->makeShader(SkShader::TileMode::kRepeat_TileMode, SkShader::TileMode::kRepeat_TileMode, nullptr); diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp index f137562e7c73..448408d19eb1 100644 --- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp +++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp @@ -72,8 +72,7 @@ public: void doFrame(int frameNr) override {} sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); return image->makeShader(SkShader::TileMode::kClamp_TileMode, SkShader::TileMode::kClamp_TileMode); } diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp index c235715073f5..210fced574e9 100644 --- a/libs/hwui/tests/unit/CacheManagerTests.cpp +++ b/libs/hwui/tests/unit/CacheManagerTests.cpp @@ -54,8 +54,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) { // create an image and pin it so that we have something with a unique key in the cache sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(displayInfo.w, displayInfo.h)); - sk_sp<SkColorFilter> filter; - sk_sp<SkImage> image = bitmap->makeImage(&filter); + sk_sp<SkImage> image = bitmap->makeImage(); ASSERT_TRUE(SkImage_pinAsTexture(image.get(), grContext)); // attempt to trim all memory while we still hold strong refs diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp index 6c8775b1bdbb..a6869791a915 100644 --- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp +++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp @@ -43,7 +43,7 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) { SkBitmap bitmap; bitmap.allocN32Pixels(16, 16); sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap); - layerUpdater->updateLayer(true, scaledMatrix, HAL_DATASPACE_UNKNOWN, layerImage); + layerUpdater->updateLayer(true, scaledMatrix, layerImage); // the backing layer should now have all the properties applied. EXPECT_EQ(100u, layerUpdater->backingLayer()->getWidth()); diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index 634ceffe0741..f3a764874e2b 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -53,12 +53,12 @@ TEST(SkiaCanvas, colorSpaceXform) { adobeBitmap->getSkBitmap(&adobeSkBitmap); *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red - SkImageInfo info = adobeInfo.makeColorSpace(nullptr); + SkImageInfo info = adobeInfo.makeColorSpace(SkColorSpace::MakeSRGB()); sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info); SkBitmap skBitmap; bitmap->getSkBitmap(&skBitmap); - // Create a software canvas. + // Create a software sRGB canvas. SkiaCanvas canvas(skBitmap); canvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); // The result should be fully red, since we convert to sRGB at draw time. @@ -77,7 +77,7 @@ TEST(SkiaCanvas, colorSpaceXform) { picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - // Playback to an software canvas. The result should be fully red. + // Playback to a software sRGB canvas. The result should be fully red. canvas.asSkCanvas()->drawPicture(picture); ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0)); } diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h index 5475898bff28..cc8d83f10d43 100644 --- a/libs/hwui/utils/MathUtils.h +++ b/libs/hwui/utils/MathUtils.h @@ -34,6 +34,10 @@ public: return (value >= -NON_ZERO_EPSILON) && (value <= NON_ZERO_EPSILON); } + inline static bool isOne(float value) { + return areEqual(value, 1.0f); + } + inline static bool isPositive(float value) { return value >= NON_ZERO_EPSILON; } /** diff --git a/location/java/android/location/ILocationListener.aidl b/location/java/android/location/ILocationListener.aidl index 7627cf6920c1..180183e77668 100644 --- a/location/java/android/location/ILocationListener.aidl +++ b/location/java/android/location/ILocationListener.aidl @@ -26,7 +26,9 @@ import android.os.Bundle; oneway interface ILocationListener { void onLocationChanged(in Location location); - void onStatusChanged(String provider, int status, in Bundle extras); void onProviderEnabled(String provider); void onProviderDisabled(String provider); + + // --- deprecated --- + void onStatusChanged(String provider, int status, in Bundle extras); } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index b5d835a90c7b..ff2fad443bcb 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -99,9 +99,10 @@ interface ILocationManager void clearTestProviderLocation(String provider, String opPackageName); void setTestProviderEnabled(String provider, boolean enabled, String opPackageName); void clearTestProviderEnabled(String provider, String opPackageName); + + // --- deprecated --- void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime, String opPackageName); - void clearTestProviderStatus(String provider, String opPackageName); boolean sendExtraCommand(String provider, String command, inout Bundle extras); diff --git a/location/java/android/location/LocationListener.java b/location/java/android/location/LocationListener.java index 88904c824912..aa9dddc03515 100644 --- a/location/java/android/location/LocationListener.java +++ b/location/java/android/location/LocationListener.java @@ -44,29 +44,12 @@ public interface LocationListener { void onLocationChanged(Location location); /** - * Called when the provider status changes. This method is called when - * a provider is unable to fetch a location or if the provider has recently - * become available after a period of unavailability. + * This callback will never be invoked and providers can be considers as always in the + * {@link LocationProvider#AVAILABLE} state. * - * @param provider the name of the location provider associated with this - * update. - * @param status {@link LocationProvider#OUT_OF_SERVICE} if the - * provider is out of service, and this is not expected to change in the - * near future; {@link LocationProvider#TEMPORARILY_UNAVAILABLE} if - * the provider is temporarily unavailable but is expected to be available - * shortly; and {@link LocationProvider#AVAILABLE} if the - * provider is currently available. - * @param extras an optional Bundle which will contain provider specific - * status variables. - * - * <p> A number of common key/value pairs for the extras Bundle are listed - * below. Providers that use any of the keys on this list must - * provide the corresponding value as described below. - * - * <ul> - * <li> satellites - the number of satellites used to derive the fix - * </ul> + * @deprecated This callback will never be invoked. */ + @Deprecated void onStatusChanged(String provider, int status, Bundle extras); /** diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 02680ab86062..b66ceef29ceb 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -146,9 +146,14 @@ public class LocationManager { public static final String KEY_PROXIMITY_ENTERING = "entering"; /** + * This key is no longer in use. + * * Key used for a Bundle extra holding an Integer status value * when a status change is broadcast using a PendingIntent. + * + * @deprecated Status changes are deprecated and no longer broadcast. */ + @Deprecated public static final String KEY_STATUS_CHANGED = "status"; /** @@ -1581,8 +1586,7 @@ public class LocationManager { } /** - * Sets mock status values for the given provider. These values will be used in place - * of any actual values from the provider. + * This method has no effect as provider status has been deprecated and is no longer supported. * * @param provider the provider name * @param status the mock status @@ -1593,7 +1597,10 @@ public class LocationManager { * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED * allowed} for your app. * @throws IllegalArgumentException if no provider with the given name exists + * + * @deprecated This method has no effect. */ + @Deprecated public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { try { mService.setTestProviderStatus(provider, status, extras, updateTime, @@ -1604,21 +1611,19 @@ public class LocationManager { } /** - * Removes any mock status values associated with the given provider. + * This method has no effect as provider status has been deprecated and is no longer supported. * * @param provider the provider name - * * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED * allowed} for your app. * @throws IllegalArgumentException if no provider with the given name exists + * + * @deprecated This method has no effect. */ + @Deprecated public void clearTestProviderStatus(String provider) { - try { - mService.clearTestProviderStatus(provider, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + setTestProviderStatus(provider, LocationProvider.AVAILABLE, null, 0L); } // --- GPS-specific support --- diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java index c4fd0975a3bc..b69a9d79e5b8 100644 --- a/location/java/android/location/LocationProvider.java +++ b/location/java/android/location/LocationProvider.java @@ -34,8 +34,23 @@ import com.android.internal.location.ProviderProperties; * user-specified criteria. */ public class LocationProvider { + + /** + * @deprecated Location provider statuses are no longer supported. + */ + @Deprecated public static final int OUT_OF_SERVICE = 0; + + /** + * @deprecated Location provider statuses are no longer supported. + */ + @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; + + /** + * @deprecated Location provider statuses are no longer supported. + */ + @Deprecated public static final int AVAILABLE = 2; /** diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt index 1e69f162fb07..d19559e8cccd 100644 --- a/location/lib/api/current.txt +++ b/location/lib/api/current.txt @@ -11,8 +11,8 @@ package com.android.location.provider { method public abstract void onDisable(); method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public abstract void onEnable(); - method public abstract int onGetStatus(android.os.Bundle); - method public abstract long onGetStatusUpdateTime(); + method public deprecated int onGetStatus(android.os.Bundle); + method public deprecated long onGetStatusUpdateTime(); method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle); method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); method public final void reportLocation(android.location.Location); diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java index 30655f5bbf10..d45a4bac8f96 100644 --- a/location/lib/java/com/android/location/provider/LocationProviderBase.java +++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java @@ -16,14 +16,11 @@ package com.android.location.provider; -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.PrintWriter; - import android.content.Context; import android.location.ILocationManager; import android.location.Location; import android.location.LocationManager; +import android.location.LocationProvider; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -36,6 +33,10 @@ import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.internal.util.FastPrintWriter; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.PrintWriter; + /** * Base class for location providers implemented as unbundled services. * @@ -173,6 +174,8 @@ public abstract class LocationProviderBase { } /** + * This method will no longer be invoked. + * * Returns a information on the status of this provider. * <p>{@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is * out of service, and this is not expected to change in the near @@ -183,10 +186,17 @@ public abstract class LocationProviderBase { * * <p>If extras is non-null, additional status information may be * added to it in the form of provider-specific key/value pairs. + * + * @deprecated This method will no longer be invoked. */ - public abstract int onGetStatus(Bundle extras); + @Deprecated + public int onGetStatus(Bundle extras) { + return LocationProvider.AVAILABLE; + } /** + * This method will no longer be invoked. + * * Returns the time at which the status was last updated. It is the * responsibility of the provider to appropriately set this value using * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}. @@ -195,8 +205,13 @@ public abstract class LocationProviderBase { * the same status again. * * @return time of last status update in millis since last reboot + * + * @deprecated This method will no longer be invoked. */ - public abstract long onGetStatusUpdateTime(); + @Deprecated + public long onGetStatusUpdateTime() { + return 0; + } /** * Implements addditional location provider specific additional commands. diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 976d3803096f..ff1bdd47f565 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1911,7 +1911,7 @@ public class AudioManager { * system failed to generate a new session, a condition in which audio playback or recording * will subsequently fail as well. */ - public static int generateAudioSessionId() { + public int generateAudioSessionId() { int session = AudioSystem.newAudioSessionId(); if (session > 0) { return session; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 67cc456a7c93..082a375470ee 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -75,6 +75,12 @@ public class AudioSystem */ public static final int NUM_STREAMS = 5; + /** Maximum value for AudioTrack channel count + * @hide public for MediaCode only, do not un-hide or change to a numeric literal + */ + public static final int OUT_CHANNEL_COUNT_MAX = native_get_FCC_8(); + private static native int native_get_FCC_8(); + // Expose only the getter method publicly so we can change it in the future private static final int NUM_STREAM_TYPES = 11; @UnsupportedAppUsage @@ -918,6 +924,15 @@ public class AudioSystem public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled); + /** + * Communicate UID of active assistant to audio policy service. + */ + public static native int setAssistantUid(int uid); + /** + * Communicate UIDs of active accessibility services to audio policy service. + */ + public static native int setA11yServicesUids(int[] uids); + // Items shared with audio service /** diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index d37f8ab529a1..c226d49c6af7 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -93,11 +93,6 @@ public class AudioTrack extends PlayerBase */ private static final float GAIN_MAX = 1.0f; - /** Maximum value for AudioTrack channel count - * @hide public for MediaCode only, do not un-hide or change to a numeric literal - */ - public static final int CHANNEL_COUNT_MAX = native_get_FCC_8(); - /** indicates AudioTrack state is stopped */ public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED /** indicates AudioTrack state is paused */ @@ -1001,7 +996,8 @@ public class AudioTrack extends PlayerBase } // mask of all the positional channels supported, however the allowed combinations - // are further restricted by the matching left/right rule and CHANNEL_COUNT_MAX + // are further restricted by the matching left/right rule and + // AudioSystem.OUT_CHANNEL_COUNT_MAX private static final int SUPPORTED_OUT_CHANNELS = AudioFormat.CHANNEL_OUT_FRONT_LEFT | AudioFormat.CHANNEL_OUT_FRONT_RIGHT | @@ -1124,7 +1120,7 @@ public class AudioTrack extends PlayerBase mChannelIndexMask = channelIndexMask; if (mChannelIndexMask != 0) { // restrictive: indexMask could allow up to AUDIO_CHANNEL_BITS_LOG2 - final int indexMask = (1 << CHANNEL_COUNT_MAX) - 1; + final int indexMask = (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1; if ((channelIndexMask & ~indexMask) != 0) { throw new IllegalArgumentException("Unsupported channel index configuration " + channelIndexMask); @@ -1169,9 +1165,9 @@ public class AudioTrack extends PlayerBase return false; } final int channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig); - if (channelCount > CHANNEL_COUNT_MAX) { + if (channelCount > AudioSystem.OUT_CHANNEL_COUNT_MAX) { loge("Channel configuration contains too many channels " + - channelCount + ">" + CHANNEL_COUNT_MAX); + channelCount + ">" + AudioSystem.OUT_CHANNEL_COUNT_MAX); return false; } // check for unsupported multichannel combinations: @@ -3418,7 +3414,6 @@ public class AudioTrack extends PlayerBase private native final int native_getRoutedDeviceId(); private native final void native_enableDeviceCallback(); private native final void native_disableDeviceCallback(); - static private native int native_get_FCC_8(); private native int native_applyVolumeShaper( @NonNull VolumeShaper.Configuration configuration, diff --git a/media/java/android/media/CallbackDataSourceDesc.java b/media/java/android/media/CallbackDataSourceDesc.java index a7e168f60ae8..e22203dab4bc 100644 --- a/media/java/android/media/CallbackDataSourceDesc.java +++ b/media/java/android/media/CallbackDataSourceDesc.java @@ -18,13 +18,13 @@ package android.media; import android.annotation.NonNull; -import com.android.internal.util.Preconditions; - /** * @hide - * Structure for file data source descriptor. + * Structure of data source descriptor for sources using callback. * - * Used by {@link MediaPlayer2#setDataSource(CallbackDataSourceDesc)} + * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, + * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and + * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}. @@ -105,7 +105,7 @@ public class CallbackDataSourceDesc extends DataSourceDesc { * @throws NullPointerException if m2ds is null. */ public @NonNull Builder setDataSource(@NonNull Media2DataSource m2ds) { - Preconditions.checkNotNull(m2ds); + Media2Utils.checkArgument(m2ds != null, "data source cannot be null."); mMedia2DataSource = m2ds; return this; } diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java index aed3f84a9eb2..702034e987ca 100644 --- a/media/java/android/media/DataSourceDesc.java +++ b/media/java/android/media/DataSourceDesc.java @@ -18,13 +18,13 @@ package android.media; import android.annotation.NonNull; -import com.android.internal.util.Preconditions; - /** * @hide * Base class of data source descriptor. * - * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)} + * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, + * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and + * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use subclasses' builder to change {@link DataSourceDesc}. @@ -32,7 +32,7 @@ import com.android.internal.util.Preconditions; */ public class DataSourceDesc { // intentionally less than long.MAX_VALUE - public static final long LONG_MAX = 0x7ffffffffffffffL; + static final long LONG_MAX = 0x7ffffffffffffffL; // keep consistent with native code public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000; @@ -48,6 +48,19 @@ public class DataSourceDesc { } /** + * Releases the resources held by this {@code DataSourceDesc} object. + */ + void close() { + } + + // Have to declare protected for finalize() since it is protected + // in the base class Object. + @Override + protected void finalize() throws Throwable { + close(); + } + + /** * Return the media Id of data source. * @return the media Id of data source */ @@ -118,7 +131,7 @@ public class DataSourceDesc { * @return the same instance of subclass of {@link DataSourceDesc} */ void build(@NonNull DataSourceDesc dsd) { - Preconditions.checkNotNull(dsd); + Media2Utils.checkArgument(dsd != null, "dsd cannot be null."); if (mStartPositionMs > mEndPositionMs) { throw new IllegalStateException("Illegal start/end position: " diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index b96a5853b9dc..01a0cb619bf0 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -16,7 +16,10 @@ package android.media; +import android.annotation.CurrentTimeMillisLong; +import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.Bitmap; @@ -26,12 +29,14 @@ import android.system.Os; import android.system.OsConstants; import android.util.Log; import android.util.Pair; -import android.annotation.IntDef; + +import libcore.io.IoUtils; +import libcore.io.Streams; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; -import java.io.DataInputStream; import java.io.DataInput; +import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileDescriptor; @@ -42,14 +47,14 @@ import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Arrays; -import java.util.LinkedList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -58,11 +63,6 @@ import java.util.Set; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import libcore.io.IoUtils; -import libcore.io.Streams; /** * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file. @@ -583,11 +583,19 @@ public class ExifInterface { private static class ExifAttribute { public final int format; public final int numberOfComponents; + public final long bytesOffset; public final byte[] bytes; + public static final long BYTES_OFFSET_UNKNOWN = -1; + private ExifAttribute(int format, int numberOfComponents, byte[] bytes) { + this(format, numberOfComponents, BYTES_OFFSET_UNKNOWN, bytes); + } + + private ExifAttribute(int format, int numberOfComponents, long bytesOffset, byte[] bytes) { this.format = format; this.numberOfComponents = numberOfComponents; + this.bytesOffset = bytesOffset; this.bytes = bytes; } @@ -1318,6 +1326,7 @@ public class ExifInterface { private int mOrfThumbnailLength; private int mRw2JpgFromRawOffset; private boolean mIsSupportedFile; + private boolean mModified; // Pattern to check non zero timestamp private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*"); @@ -1328,7 +1337,14 @@ public class ExifInterface { /** * Reads Exif tags from the specified image file. */ - public ExifInterface(String filename) throws IOException { + public ExifInterface(@NonNull File file) throws IOException { + this(file.getAbsolutePath()); + } + + /** + * Reads Exif tags from the specified image file. + */ + public ExifInterface(@NonNull String filename) throws IOException { if (filename == null) { throw new IllegalArgumentException("filename cannot be null"); } @@ -1354,7 +1370,7 @@ public class ExifInterface { * for writable and seekable file descriptors only. This constructor will not rewind the offset * of the given file descriptor. Developers should close the file descriptor after use. */ - public ExifInterface(FileDescriptor fileDescriptor) throws IOException { + public ExifInterface(@NonNull FileDescriptor fileDescriptor) throws IOException { if (fileDescriptor == null) { throw new IllegalArgumentException("fileDescriptor cannot be null"); } @@ -1388,7 +1404,7 @@ public class ExifInterface { * for input streams. The given input stream will proceed its current position. Developers * should close the input stream after use. */ - public ExifInterface(InputStream inputStream) throws IOException { + public ExifInterface(@NonNull InputStream inputStream) throws IOException { if (inputStream == null) { throw new IllegalArgumentException("inputStream cannot be null"); } @@ -1414,7 +1430,7 @@ public class ExifInterface { * * @param tag the name of the tag. */ - private ExifAttribute getExifAttribute(String tag) { + private @Nullable ExifAttribute getExifAttribute(@NonNull String tag) { // Retrieves all tag groups. The value from primary image tag group has a higher priority // than the value from the thumbnail tag group if there are more than one candidates. for (int i = 0; i < EXIF_TAGS.length; ++i) { @@ -1432,7 +1448,7 @@ public class ExifInterface { * * @param tag the name of the tag. */ - public String getAttribute(String tag) { + public @Nullable String getAttribute(@NonNull String tag) { ExifAttribute attribute = getExifAttribute(tag); if (attribute != null) { if (!sTagSetForCompatibility.contains(tag)) { @@ -1470,7 +1486,7 @@ public class ExifInterface { * @param tag the name of the tag. * @param defaultValue the value to return if the tag is not available. */ - public int getAttributeInt(String tag, int defaultValue) { + public int getAttributeInt(@NonNull String tag, int defaultValue) { ExifAttribute exifAttribute = getExifAttribute(tag); if (exifAttribute == null) { return defaultValue; @@ -1491,7 +1507,7 @@ public class ExifInterface { * @param tag the name of the tag. * @param defaultValue the value to return if the tag is not available. */ - public double getAttributeDouble(String tag, double defaultValue) { + public double getAttributeDouble(@NonNull String tag, double defaultValue) { ExifAttribute exifAttribute = getExifAttribute(tag); if (exifAttribute == null) { return defaultValue; @@ -1510,7 +1526,7 @@ public class ExifInterface { * @param tag the name of the tag. * @param value the value of the tag. */ - public void setAttribute(String tag, String value) { + public void setAttribute(@NonNull String tag, @Nullable String value) { // Convert the given value to rational values for backwards compatibility. if (value != null && sTagSetForCompatibility.contains(tag)) { if (tag.equals(TAG_GPS_TIMESTAMP)) { @@ -1772,12 +1788,18 @@ public class ExifInterface { } /** - * Save the tag data into the original image file. This is expensive because it involves - * copying all the data from one file to another and deleting the old file and renaming the - * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write - * and make a single call rather than multiple calls for each attribute. + * Save the tag data into the original image file. This is expensive because + * it involves copying all the data from one file to another and deleting + * the old file and renaming the other. It's best to use + * {@link #setAttribute(String,String)} to set all attributes to write and + * make a single call rather than multiple calls for each attribute. * <p> * This method is only supported for JPEG files. + * <p class="note"> + * Note: after calling this method, any attempts to obtain range information + * from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()} + * will throw {@link IllegalStateException}, since the offsets may have + * changed in the newly written file. * </p> */ public void saveAttributes() throws IOException { @@ -1789,6 +1811,10 @@ public class ExifInterface { "ExifInterface does not support saving attributes for the current input."); } + // Remember the fact that we've changed the file on disk from what was + // originally parsed, meaning we can't answer range questions + mModified = true; + // Keep the thumbnail in memory mThumbnailBytes = getThumbnail(); @@ -1849,6 +1875,15 @@ public class ExifInterface { } /** + * Returns true if the image file has the given attribute defined. + * + * @param tag the name of the tag. + */ + public boolean hasAttribute(String tag) { + return (getExifAttribute(tag) != null); + } + + /** * Returns the JPEG compressed thumbnail inside the image file, or {@code null} if there is no * JPEG compressed thumbnail. * The returned data can be decoded using @@ -1968,17 +2003,45 @@ public class ExifInterface { * * @return two-element array, the offset in the first value, and length in * the second, or {@code null} if no thumbnail was found. + * @throws IllegalStateException if {@link #saveAttributes()} has been + * called since the underlying file was initially parsed, since + * that means offsets may have changed. */ - public long[] getThumbnailRange() { - if (!mHasThumbnail) { + public @Nullable long[] getThumbnailRange() { + if (mModified) { + throw new IllegalStateException( + "The underlying file has been modified since being parsed"); + } + + if (mHasThumbnail) { + return new long[] { mThumbnailOffset, mThumbnailLength }; + } else { return null; } + } - long[] range = new long[2]; - range[0] = mThumbnailOffset; - range[1] = mThumbnailLength; + /** + * Returns the offset and length of the requested tag inside the image file, + * or {@code null} if the tag is not contained. + * + * @return two-element array, the offset in the first value, and length in + * the second, or {@code null} if no tag was found. + * @throws IllegalStateException if {@link #saveAttributes()} has been + * called since the underlying file was initially parsed, since + * that means offsets may have changed. + */ + public @Nullable long[] getAttributeRange(@NonNull String tag) { + if (mModified) { + throw new IllegalStateException( + "The underlying file has been modified since being parsed"); + } - return range; + final ExifAttribute attribute = getExifAttribute(tag); + if (attribute != null) { + return new long[] { attribute.bytesOffset, attribute.bytes.length }; + } else { + return null; + } } /** @@ -2023,13 +2086,41 @@ public class ExifInterface { } /** - * Returns number of milliseconds since Jan. 1, 1970, midnight local time. - * Returns -1 if the date time information if not available. + * Returns parsed {@code DateTime} value, or -1 if unavailable or invalid. + * * @hide */ @UnsupportedAppUsage - public long getDateTime() { - String dateTimeString = getAttribute(TAG_DATETIME); + public @CurrentTimeMillisLong long getDateTime() { + return parseDateTime(getAttribute(TAG_DATETIME), + getAttribute(TAG_SUBSEC_TIME)); + } + + /** + * Returns parsed {@code DateTimeDigitized} value, or -1 if unavailable or + * invalid. + * + * @hide + */ + public @CurrentTimeMillisLong long getDateTimeDigitized() { + return parseDateTime(getAttribute(TAG_DATETIME_DIGITIZED), + getAttribute(TAG_SUBSEC_TIME_DIGITIZED)); + } + + /** + * Returns parsed {@code DateTimeOriginal} value, or -1 if unavailable or + * invalid. + * + * @hide + */ + @UnsupportedAppUsage + public @CurrentTimeMillisLong long getDateTimeOriginal() { + return parseDateTime(getAttribute(TAG_DATETIME_ORIGINAL), + getAttribute(TAG_SUBSEC_TIME_ORIGINAL)); + } + + private static @CurrentTimeMillisLong long parseDateTime(@Nullable String dateTimeString, + @Nullable String subSecs) { if (dateTimeString == null || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1; @@ -2041,7 +2132,6 @@ public class ExifInterface { if (datetime == null) return -1; long msecs = datetime.getTime(); - String subSecs = getAttribute(TAG_SUBSEC_TIME); if (subSecs != null) { try { long sub = Long.parseLong(subSecs); @@ -3125,9 +3215,11 @@ public class ExifInterface { continue; } - byte[] bytes = new byte[(int) byteCount]; + final int bytesOffset = dataInputStream.peek(); + final byte[] bytes = new byte[(int) byteCount]; dataInputStream.readFully(bytes); - ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents, bytes); + ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents, + bytesOffset, bytes); mAttributes[ifdType].put(tag.name, attribute); // DNG files have a DNG Version tag specifying the version of specifications that the diff --git a/media/java/android/media/FileDataSourceDesc.java b/media/java/android/media/FileDataSourceDesc.java index 5d8ff4913fb5..763a81f53765 100644 --- a/media/java/android/media/FileDataSourceDesc.java +++ b/media/java/android/media/FileDataSourceDesc.java @@ -17,22 +17,26 @@ package android.media; import android.annotation.NonNull; +import android.os.ParcelFileDescriptor; +import android.util.Log; -import com.android.internal.util.Preconditions; - -import java.io.FileDescriptor; +import java.io.IOException; /** * @hide - * Structure for data source descriptor. + * Structure of data source descriptor for sources using file descriptor. * - * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)} + * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, + * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and + * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}. * */ public class FileDataSourceDesc extends DataSourceDesc { + private static final String TAG = "FileDataSourceDesc"; + /** * Used when the length of file descriptor is unknown. * @@ -40,34 +44,61 @@ public class FileDataSourceDesc extends DataSourceDesc { */ public static final long FD_LENGTH_UNKNOWN = LONG_MAX; - private FileDescriptor mFD; + private ParcelFileDescriptor mPFD; private long mOffset = 0; private long mLength = FD_LENGTH_UNKNOWN; private FileDataSourceDesc() { + super(); + } + + /** + * Releases the resources held by this {@code FileDataSourceDesc} object. + */ + @Override + void close() { + super.close(); + closeFD(); + } + + /** + * Releases the file descriptor held by this {@code FileDataSourceDesc} object. + */ + void closeFD() { + synchronized (this) { + if (mPFD != null) { + try { + mPFD.close(); + } catch (IOException e) { + Log.e(TAG, "failed to close pfd: " + e); + } + + mPFD = null; + } + } } /** - * Return the FileDescriptor of this data source. - * @return the FileDescriptor of this data source + * Return the ParcelFileDescriptor of this data source. + * @return the ParcelFileDescriptor of this data source */ - public FileDescriptor getFileDescriptor() { - return mFD; + public ParcelFileDescriptor getParcelFileDescriptor() { + return mPFD; } /** - * Return the offset associated with the FileDescriptor of this data source. + * Return the offset associated with the ParcelFileDescriptor of this data source. * It's meaningful only when it has been set by the {@link Builder}. - * @return the offset associated with the FileDescriptor of this data source + * @return the offset associated with the ParcelFileDescriptor of this data source */ public long getOffset() { return mOffset; } /** - * Return the content length associated with the FileDescriptor of this data source. + * Return the content length associated with the ParcelFileDescriptor of this data source. * {@link #FD_LENGTH_UNKNOWN} means same as the length of source content. - * @return the content length associated with the FileDescriptor of this data source + * @return the content length associated with the ParcelFileDescriptor of this data source */ public long getLength() { return mLength; @@ -80,7 +111,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * * <pre class="prettyprint"> * FileDataSourceDesc newDSD = new FileDataSourceDesc.Builder() - * .setDataSource(fd, 0, srcLength) + * .setDataSource(pfd, 0, srcLength) * .setStartPosition(1000) * .setEndPosition(15000) * .build(); @@ -88,7 +119,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * </pre> */ public static class Builder extends BuilderBase<Builder> { - private FileDescriptor mFD; + private ParcelFileDescriptor mPFD; private long mOffset = 0; private long mLength = FD_LENGTH_UNKNOWN; @@ -109,7 +140,7 @@ public class FileDataSourceDesc extends DataSourceDesc { if (dsd == null) { return; // use default } - mFD = dsd.mFD; + mPFD = dsd.mPFD; mOffset = dsd.mOffset; mLength = dsd.mLength; } @@ -124,7 +155,7 @@ public class FileDataSourceDesc extends DataSourceDesc { public @NonNull FileDataSourceDesc build() { FileDataSourceDesc dsd = new FileDataSourceDesc(); super.build(dsd); - dsd.mFD = mFD; + dsd.mPFD = mPFD; dsd.mOffset = mOffset; dsd.mLength = mLength; @@ -132,38 +163,46 @@ public class FileDataSourceDesc extends DataSourceDesc { } /** - * Sets the data source (FileDescriptor) to use. The FileDescriptor must be - * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility - * to close the file descriptor after the source has been used. + * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be + * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc} + * created by this builder is passed to {@link MediaPlayer2} via + * {@link MediaPlayer2#setDataSource(DataSourceDesc)}, + * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} or + * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)}, MediaPlayer2 will + * close the ParcelFileDescriptor. * - * @param fd the FileDescriptor for the file to play + * @param pfd the ParcelFileDescriptor for the file to play * @return the same Builder instance. - * @throws NullPointerException if fd is null. + * @throws NullPointerException if pfd is null. */ - public @NonNull Builder setDataSource(@NonNull FileDescriptor fd) { - Preconditions.checkNotNull(fd); + public @NonNull Builder setDataSource(@NonNull ParcelFileDescriptor pfd) { + Media2Utils.checkArgument(pfd != null, "pfd cannot be null."); resetDataSource(); - mFD = fd; + mPFD = pfd; return this; } /** - * Sets the data source (FileDescriptor) to use. The FileDescriptor must be - * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility - * to close the file descriptor after the source has been used. + * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be + * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc} + * created by this builder is passed to {@link MediaPlayer2} via + * {@link MediaPlayer2#setDataSource(DataSourceDesc)}, + * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} or + * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)}, MediaPlayer2 will + * close the ParcelFileDescriptor. * * Any negative number for offset is treated as 0. * Any negative number for length is treated as maximum length of the data source. * - * @param fd the FileDescriptor for the file to play + * @param pfd the ParcelFileDescriptor for the file to play * @param offset the offset into the file where the data to be played starts, in bytes * @param length the length in bytes of the data to be played * @return the same Builder instance. - * @throws NullPointerException if fd is null. + * @throws NullPointerException if pfd is null. */ public @NonNull Builder setDataSource( - @NonNull FileDescriptor fd, long offset, long length) { - Preconditions.checkNotNull(fd); + @NonNull ParcelFileDescriptor pfd, long offset, long length) { + Media2Utils.checkArgument(pfd != null, "pfd cannot be null."); if (offset < 0) { offset = 0; } @@ -171,14 +210,14 @@ public class FileDataSourceDesc extends DataSourceDesc { length = FD_LENGTH_UNKNOWN; } resetDataSource(); - mFD = fd; + mPFD = pfd; mOffset = offset; mLength = length; return this; } private void resetDataSource() { - mFD = null; + mPFD = null; mOffset = 0; mLength = FD_LENGTH_UNKNOWN; } diff --git a/media/java/android/media/Media2HTTPConnection.java b/media/java/android/media/Media2HTTPConnection.java index 0d7825a0853f..a369a62b39db 100644 --- a/media/java/android/media/Media2HTTPConnection.java +++ b/media/java/android/media/Media2HTTPConnection.java @@ -16,27 +16,27 @@ package android.media; -import android.net.NetworkUtils; +import static android.media.MediaPlayer2.MEDIA_ERROR_UNSUPPORTED; + import android.os.StrictMode; import android.util.Log; import java.io.BufferedInputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.net.CookieHandler; -import java.net.CookieManager; -import java.net.Proxy; -import java.net.URL; import java.net.HttpURLConnection; +import java.net.InetAddress; import java.net.MalformedURLException; import java.net.NoRouteToHostException; import java.net.ProtocolException; +import java.net.Proxy; +import java.net.URL; +import java.net.UnknownHostException; import java.net.UnknownServiceException; import java.util.HashMap; import java.util.Map; -import static android.media.MediaPlayer2.MEDIA_ERROR_UNSUPPORTED; - /** @hide */ public class Media2HTTPConnection { private static final String TAG = "Media2HTTPConnection"; @@ -161,10 +161,10 @@ public class Media2HTTPConnection { if (host.equalsIgnoreCase("localhost")) { return true; } - if (NetworkUtils.numericToInetAddress(host).isLoopbackAddress()) { + if (InetAddress.getByName(host).isLoopbackAddress()) { return true; } - } catch (IllegalArgumentException iex) { + } catch (IllegalArgumentException | UnknownHostException e) { } return false; } diff --git a/media/java/android/media/Media2Utils.java b/media/java/android/media/Media2Utils.java index 066233d95f55..5fd61915b4aa 100644 --- a/media/java/android/media/Media2Utils.java +++ b/media/java/android/media/Media2Utils.java @@ -31,6 +31,20 @@ public class Media2Utils { private Media2Utils() { } + /** + * Ensures that an expression checking an argument is true. + * + * @param expression the expression to check + * @param errorMessage the exception message to use if the check fails; will + * be converted to a string using {@link String#valueOf(Object)} + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument(boolean expression, String errorMessage) { + if (!expression) { + throw new IllegalArgumentException(errorMessage); + } + } + public static synchronized void storeCookies(List<HttpCookie> cookies) { CookieHandler cookieHandler = CookieHandler.getDefault(); if (cookieHandler == null) { diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index dfe29e953a56..6301993a74be 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -16,6 +16,9 @@ package android.media; +import static android.media.Utils.intersectSortedDistinctRanges; +import static android.media.Utils.sortDistinctRanges; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; @@ -32,9 +35,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import static android.media.Utils.intersectSortedDistinctRanges; -import static android.media.Utils.sortDistinctRanges; - /** * Provides information about a given media codec available on the device. You can * iterate through all codecs available by querying {@link MediaCodecList}. For example, @@ -1117,7 +1117,7 @@ public final class MediaCodecInfo { } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { sampleRateRange = Range.create(1, 96000); bitRates = Range.create(1, 10000000); - maxChannels = AudioTrack.CHANNEL_COUNT_MAX; + maxChannels = AudioSystem.OUT_CHANNEL_COUNT_MAX; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { sampleRateRange = Range.create(1, 655350); // lossless codec, so bitrate is ignored diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java index c203fa9ca71b..7785900a7c6e 100644 --- a/media/java/android/media/MediaExtractor.java +++ b/media/java/android/media/MediaExtractor.java @@ -434,9 +434,12 @@ final public class MediaExtractor { */ @NonNull public List<AudioPresentation> getAudioPresentations(int trackIndex) { - return new ArrayList<AudioPresentation>(); + return native_getAudioPresentations(trackIndex); } + @NonNull + private native List<AudioPresentation> native_getAudioPresentations(int trackIndex); + /** * Get the PSSH info if present. * @return a map of uuid-to-bytes, with the uuid specifying diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index 82889761b592..0f2604e3f2ce 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -20,6 +20,7 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringDef; import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; @@ -35,6 +36,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.PowerManager; import android.util.Log; @@ -411,6 +413,9 @@ public class MediaPlayer2 implements AutoCloseable mHandlerThread = null; } + setCurrentSourceInfo(null); + clearNextSourceInfos(); + // Modular DRM clean up mOnDrmConfigHelper = null; synchronized (mDrmEventCbLock) { @@ -456,10 +461,8 @@ public class MediaPlayer2 implements AutoCloseable synchronized (mDrmEventCbLock) { mDrmEventCallbackRecords.clear(); } - synchronized (mSrcLock) { - mCurrentSourceInfo = null; - mNextSourceInfos.clear(); - } + setCurrentSourceInfo(null); + clearNextSourceInfos(); synchronized (mTaskLock) { mPendingTasks.clear(); @@ -684,6 +687,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets the data source as described by a DataSourceDesc. + * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} + * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsd the descriptor of data source you want to play * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. @@ -693,15 +698,19 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) { @Override void process() throws IOException { - checkArgument(dsd != null, "the DataSourceDesc cannot be null"); + Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null"); int state = getState(); - if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) { - throw new IllegalStateException("called in wrong state " + state); - } + try { + if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) { + throw new IllegalStateException("called in wrong state " + state); + } - synchronized (mSrcLock) { - mCurrentSourceInfo = new SourceInfo(dsd); - handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId); + synchronized (mSrcLock) { + setCurrentSourceInfo(new SourceInfo(dsd)); + handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId); + } + } finally { + dsd.close(); } } }); @@ -710,6 +719,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets a single data source as described by a DataSourceDesc which will be played * after current data source is finished. + * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} + * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsd the descriptor of data source you want to play after current one * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. @@ -719,9 +730,9 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) { @Override void process() { - checkArgument(dsd != null, "the DataSourceDesc cannot be null"); + Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null"); synchronized (mSrcLock) { - mNextSourceInfos.clear(); + clearNextSourceInfos(); mNextSourceInfos.add(new SourceInfo(dsd)); } prepareNextDataSource(); @@ -731,6 +742,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets a list of data sources to be played sequentially after current data source is done. + * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} + * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsds the list of data sources you want to play after current one * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. @@ -743,17 +756,15 @@ public class MediaPlayer2 implements AutoCloseable if (dsds == null || dsds.size() == 0) { throw new IllegalArgumentException("data source list cannot be null or empty."); } - for (DataSourceDesc dsd : dsds) { - if (dsd == null) { - throw new IllegalArgumentException( - "DataSourceDesc in the source list cannot be null."); - } - } synchronized (mSrcLock) { - mNextSourceInfos.clear(); + clearNextSourceInfos(); for (DataSourceDesc dsd : dsds) { - mNextSourceInfos.add(new SourceInfo(dsd)); + if (dsd != null) { + mNextSourceInfos.add(new SourceInfo(dsd)); + } else { + Log.w(TAG, "DataSourceDesc in the source list shall not be null."); + } } } prepareNextDataSource(); @@ -770,7 +781,7 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) { @Override void process() { - mNextSourceInfos.clear(); + clearNextSourceInfos(); } }); } @@ -788,7 +799,7 @@ public class MediaPlayer2 implements AutoCloseable private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId) throws IOException { - checkArgument(dsd != null, "the DataSourceDesc cannot be null"); + Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null"); if (dsd instanceof CallbackDataSourceDesc) { CallbackDataSourceDesc cbDSD = (CallbackDataSourceDesc) dsd; @@ -801,7 +812,7 @@ public class MediaPlayer2 implements AutoCloseable FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd; handleDataSource(isCurrent, srcId, - fileDSD.getFileDescriptor(), + fileDSD.getParcelFileDescriptor(), fileDSD.getOffset(), fileDSD.getLength(), fileDSD.getStartPosition(), @@ -885,7 +896,7 @@ public class MediaPlayer2 implements AutoCloseable if (afd.getDeclaredLength() < 0) { handleDataSource(isCurrent, srcId, - afd.getFileDescriptor(), + ParcelFileDescriptor.dup(afd.getFileDescriptor()), 0, DataSourceDesc.LONG_MAX, startPos, @@ -893,7 +904,7 @@ public class MediaPlayer2 implements AutoCloseable } else { handleDataSource(isCurrent, srcId, - afd.getFileDescriptor(), + ParcelFileDescriptor.dup(afd.getFileDescriptor()), afd.getStartOffset(), afd.getDeclaredLength(), startPos, @@ -959,7 +970,8 @@ public class MediaPlayer2 implements AutoCloseable if (file.exists()) { FileInputStream is = new FileInputStream(file); FileDescriptor fd = is.getFD(); - handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX, startPos, endPos); + handleDataSource(isCurrent, srcId, ParcelFileDescriptor.dup(fd), + 0, DataSourceDesc.LONG_MAX, startPos, endPos); is.close(); } else { throw new IOException("handleDataSource failed."); @@ -983,9 +995,10 @@ public class MediaPlayer2 implements AutoCloseable */ private void handleDataSource( boolean isCurrent, long srcId, - FileDescriptor fd, long offset, long length, + ParcelFileDescriptor pfd, long offset, long length, long startPos, long endPos) throws IOException { - nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length, startPos, endPos); + nativeHandleDataSourceFD(isCurrent, srcId, pfd.getFileDescriptor(), offset, length, + startPos, endPos); } private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId, @@ -1036,7 +1049,10 @@ public class MediaPlayer2 implements AutoCloseable MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null); mTaskHandler.handleMessage(msg, nextSource.mId); - mNextSourceInfos.poll(); + SourceInfo nextSourceInfo = mNextSourceInfos.poll(); + if (nextSource != null) { + nextSourceInfo.close(); + } return prepareNextDataSource(); } } @@ -1057,7 +1073,7 @@ public class MediaPlayer2 implements AutoCloseable SourceInfo nextSourceInfo = mNextSourceInfos.peek(); if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) { // Switch to next source only when it has been prepared. - mCurrentSourceInfo = mNextSourceInfos.poll(); + setCurrentSourceInfo(mNextSourceInfos.poll()); long srcId = mCurrentSourceInfo.mId; try { @@ -1513,7 +1529,7 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_SET_BUFFERING_PARAMS, false) { @Override void process() { - checkArgument(params != null, "the BufferingParams cannot be null"); + Media2Utils.checkArgument(params != null, "the BufferingParams cannot be null"); native_setBufferingParams(params); } }); @@ -1536,7 +1552,7 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) { @Override void process() { - checkArgument(params != null, "the PlaybackParams cannot be null"); + Media2Utils.checkArgument(params != null, "the PlaybackParams cannot be null"); native_setPlaybackParams(params); } }); @@ -1564,7 +1580,7 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_SET_SYNC_PARAMS, false) { @Override void process() { - checkArgument(params != null, "the SyncParams cannot be null"); + Media2Utils.checkArgument(params != null, "the SyncParams cannot be null"); native_setSyncParams(params); } }); @@ -2690,12 +2706,6 @@ public class MediaPlayer2 implements AutoCloseable } } - private static void checkArgument(boolean expression, String errorMessage) { - if (!expression) { - throw new IllegalArgumentException(errorMessage); - } - } - private void sendEvent(final EventNotifier notifier) { synchronized (mEventCbLock) { try { @@ -3321,6 +3331,25 @@ public class MediaPlayer2 implements AutoCloseable @Retention(RetentionPolicy.SOURCE) public @interface PrepareDrmStatusCode {} + /** @hide */ + @IntDef({ + MediaDrm.KEY_TYPE_STREAMING, + MediaDrm.KEY_TYPE_OFFLINE, + MediaDrm.KEY_TYPE_RELEASE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MediaDrmKeyType {} + + /** @hide */ + @StringDef({ + MediaDrm.PROPERTY_VENDOR, + MediaDrm.PROPERTY_VERSION, + MediaDrm.PROPERTY_DESCRIPTION, + MediaDrm.PROPERTY_ALGORITHMS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MediaDrmStringProperty {} + /** * Retrieves the DRM Info associated with the given source * @@ -3628,7 +3657,7 @@ public class MediaPlayer2 implements AutoCloseable public MediaDrm.KeyRequest getDrmKeyRequest( @NonNull DataSourceDesc dsd, @Nullable byte[] keySetId, @Nullable byte[] initData, - @Nullable String mimeType, @MediaDrm.KeyType int keyType, + @Nullable String mimeType, @MediaDrmKeyType int keyType, @Nullable Map<String, String> optionalParameters) throws NoDrmSchemeException { // TODO: this implementation only works when dsd is the only data source @@ -3786,7 +3815,7 @@ public class MediaPlayer2 implements AutoCloseable @NonNull public String getDrmPropertyString( @NonNull DataSourceDesc dsd, - @NonNull @MediaDrm.StringProperty String propertyName) + @NonNull @MediaDrmStringProperty String propertyName) throws NoDrmSchemeException { // TODO: this implementation only works when dsd is the only data source Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName); @@ -3829,7 +3858,7 @@ public class MediaPlayer2 implements AutoCloseable // This is a synchronous call. public void setDrmPropertyString( @NonNull DataSourceDesc dsd, - @NonNull @MediaDrm.StringProperty String propertyName, @NonNull String value) + @NonNull @MediaDrmStringProperty String propertyName, @NonNull String value) throws NoDrmSchemeException { // TODO: this implementation only works when dsd is the only data source Log.v(TAG, "setDrmPropertyString: propertyName: " + propertyName + " value: " + value); @@ -4476,6 +4505,7 @@ public class MediaPlayer2 implements AutoCloseable final DataSourceDesc mDSD; final long mId = mSrcIdGenerator.getAndIncrement(); AtomicInteger mBufferedPercentage = new AtomicInteger(0); + boolean mClosed = false; // m*AsNextSource (below) only applies to pending data sources in the playlist; // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource} @@ -4487,6 +4517,17 @@ public class MediaPlayer2 implements AutoCloseable this.mDSD = dsd; } + void close() { + synchronized (this) { + if (!mClosed) { + if (mDSD != null) { + mDSD.close(); + } + mClosed = true; + } + } + } + @Override public String toString() { return String.format("%s(%d)", SourceInfo.class.getName(), mId); @@ -4517,6 +4558,26 @@ public class MediaPlayer2 implements AutoCloseable return nextSourceInfo != null && nextSourceInfo.mId == srcId; } + private void setCurrentSourceInfo(SourceInfo newSourceInfo) { + synchronized (mSrcLock) { + if (mCurrentSourceInfo != null) { + mCurrentSourceInfo.close(); + } + mCurrentSourceInfo = newSourceInfo; + } + } + + private void clearNextSourceInfos() { + synchronized (mSrcLock) { + for (SourceInfo sourceInfo : mNextSourceInfos) { + if (sourceInfo != null) { + sourceInfo.close(); + } + } + mNextSourceInfos.clear(); + } + } + public static final class MetricsConstants { private MetricsConstants() {} diff --git a/media/java/android/media/UriDataSourceDesc.java b/media/java/android/media/UriDataSourceDesc.java index e6f39e0bc8fb..6a83dab14aa4 100644 --- a/media/java/android/media/UriDataSourceDesc.java +++ b/media/java/android/media/UriDataSourceDesc.java @@ -21,8 +21,6 @@ import android.annotation.Nullable; import android.content.Context; import android.net.Uri; -import com.android.internal.util.Preconditions; - import java.net.CookieHandler; import java.net.CookieManager; import java.net.HttpCookie; @@ -33,9 +31,11 @@ import java.util.Map; /** * @hide - * Structure for data source descriptor. + * Structure of data source descriptor for sources using URI. * - * Used by {@link MediaPlayer2#setDataSource(UriDataSourceDesc)} + * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, + * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and + * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}. @@ -158,8 +158,8 @@ public class UriDataSourceDesc extends DataSourceDesc { * @throws NullPointerException if context or uri is null. */ public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri) { - Preconditions.checkNotNull(context, "context cannot be null"); - Preconditions.checkNotNull(uri, "uri cannot be null"); + Media2Utils.checkArgument(context != null, "context cannot be null"); + Media2Utils.checkArgument(uri != null, "uri cannot be null"); resetDataSource(); mUri = uri; mContext = context; @@ -195,8 +195,8 @@ public class UriDataSourceDesc extends DataSourceDesc { */ public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri, @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) { - Preconditions.checkNotNull(context, "context cannot be null"); - Preconditions.checkNotNull(uri); + Media2Utils.checkArgument(context != null, "context cannot be null"); + Media2Utils.checkArgument(uri != null, "uri cannot be null"); if (cookies != null) { CookieHandler cookieHandler = CookieHandler.getDefault(); if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) { diff --git a/media/jni/android_media_AudioPresentation.h b/media/jni/android_media_AudioPresentation.h index 5306de6f8580..a3adddd21fd6 100644 --- a/media/jni/android_media_AudioPresentation.h +++ b/media/jni/android_media_AudioPresentation.h @@ -14,173 +14,135 @@ * limitations under the License. */ -#ifndef _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ -#define _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ +#ifndef _ANDROID_MEDIA_AUDIOPRESENTATION_H_ +#define _ANDROID_MEDIA_AUDIOPRESENTATION_H_ #include "jni.h" -#include <media/AudioPresentationInfo.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/AMessage.h> - +#include <media/stagefright/foundation/ADebug.h> // CHECK +#include <media/stagefright/foundation/AudioPresentationInfo.h> #include <nativehelper/ScopedLocalRef.h> namespace android { struct JAudioPresentationInfo { struct fields_t { - jclass clazz; + jclass clazz = NULL; jmethodID constructID; // list parameters - jclass listclazz; + jclass listClazz = NULL; jmethodID listConstructId; jmethodID listAddId; + // hashmap parameters + jclass hashMapClazz = NULL; + jmethodID hashMapConstructID; + jmethodID hashMapPutID; + + // ulocale parameters + jclass ulocaleClazz = NULL; + jmethodID ulocaleConstructID; + void init(JNIEnv *env) { jclass lclazz = env->FindClass("android/media/AudioPresentation"); - if (lclazz == NULL) { - return; - } - + CHECK(lclazz != NULL); clazz = (jclass)env->NewGlobalRef(lclazz); - if (clazz == NULL) { - return; - } - + CHECK(clazz != NULL); constructID = env->GetMethodID(clazz, "<init>", - "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V"); - env->DeleteLocalRef(lclazz); + "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V"); + CHECK(constructID != NULL); // list objects - jclass llistclazz = env->FindClass("java/util/ArrayList"); - CHECK(llistclazz != NULL); - listclazz = static_cast<jclass>(env->NewGlobalRef(llistclazz)); - CHECK(listclazz != NULL); - listConstructId = env->GetMethodID(listclazz, "<init>", "()V"); + jclass llistClazz = env->FindClass("java/util/ArrayList"); + CHECK(llistClazz != NULL); + listClazz = static_cast<jclass>(env->NewGlobalRef(llistClazz)); + CHECK(listClazz != NULL); + listConstructId = env->GetMethodID(listClazz, "<init>", "()V"); CHECK(listConstructId != NULL); - listAddId = env->GetMethodID(listclazz, "add", "(Ljava/lang/Object;)Z"); + listAddId = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z"); CHECK(listAddId != NULL); - env->DeleteLocalRef(llistclazz); - } - void exit(JNIEnv *env) { - env->DeleteGlobalRef(clazz); - clazz = NULL; - env->DeleteGlobalRef(listclazz); - listclazz = NULL; - } - }; - - static status_t ConvertMessageToMap(JNIEnv *env, const sp<AMessage> &msg, jobject *map) { - ScopedLocalRef<jclass> hashMapClazz(env, env->FindClass("java/util/HashMap")); - - if (hashMapClazz.get() == NULL) { - return -EINVAL; - } - jmethodID hashMapConstructID = - env->GetMethodID(hashMapClazz.get(), "<init>", "()V"); - - if (hashMapConstructID == NULL) { - return -EINVAL; - } - jmethodID hashMapPutID = - env->GetMethodID( - hashMapClazz.get(), + // hashmap objects + jclass lhashMapClazz = env->FindClass("java/util/HashMap"); + CHECK(lhashMapClazz != NULL); + hashMapClazz = (jclass)env->NewGlobalRef(lhashMapClazz); + CHECK(hashMapClazz != NULL); + hashMapConstructID = env->GetMethodID(hashMapClazz, "<init>", "()V"); + CHECK(hashMapConstructID != NULL); + hashMapPutID = env->GetMethodID( + hashMapClazz, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - - if (hashMapPutID == NULL) { - return -EINVAL; + CHECK(hashMapPutID != NULL); + + jclass lulocaleClazz = env->FindClass("android/icu/util/ULocale"); + CHECK(lulocaleClazz != NULL); + ulocaleClazz = (jclass)env->NewGlobalRef(lulocaleClazz); + CHECK(ulocaleClazz != NULL); + ulocaleConstructID = env->GetMethodID(ulocaleClazz, "<init>", "(Ljava/lang/String;)V"); + CHECK(ulocaleConstructID != NULL); } - jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); + void exit(JNIEnv *env) { + env->DeleteGlobalRef(clazz); clazz = NULL; + env->DeleteGlobalRef(listClazz); listClazz = NULL; + env->DeleteGlobalRef(hashMapClazz); hashMapClazz = NULL; + env->DeleteGlobalRef(ulocaleClazz); ulocaleClazz = NULL; + } + }; - for (size_t i = 0; i < msg->countEntries(); ++i) { - AMessage::Type valueType; - const char *key = msg->getEntryNameAt(i, &valueType); + static jobject asJobject(JNIEnv *env, const fields_t& fields) { + return env->NewObject(fields.listClazz, fields.listConstructId); + } - if (!strncmp(key, "android._", 9)) { - // don't expose private keys (starting with android._) - continue; - } - jobject valueObj = NULL; - AString val; - CHECK(msg->findString(key, &val)); - valueObj = env->NewStringUTF(val.c_str()); - if (valueObj != NULL) { - ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale")); - if (localeClazz.get() == NULL) { - return -EINVAL; - } - jmethodID localeConstructID = - env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V"); - if (localeConstructID == NULL) { - return -EINVAL; - } - jstring jLanguage = env->NewStringUTF(key); - jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage); - env->CallObjectMethod(hashMap, hashMapPutID, jLocale, valueObj); - env->DeleteLocalRef(jLocale); jLocale = NULL; - env->DeleteLocalRef(valueObj); valueObj = NULL; - env->DeleteLocalRef(jLanguage); jLanguage = NULL; + static void addPresentations(JNIEnv *env, const fields_t& fields, + const AudioPresentationCollection& presentations, jobject presentationsJObj) { + for (const auto& ap : presentations) { + ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels); + if (jLabelObject == nullptr) return; + ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(ap.mLanguage.c_str())); + if (jLanguage == nullptr) return; + ScopedLocalRef<jobject> jLocale(env, env->NewObject( + fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get())); + ScopedLocalRef<jobject> jValueObj(env, env->NewObject(fields.clazz, fields.constructID, + static_cast<jint>(ap.mPresentationId), + static_cast<jint>(ap.mProgramId), + jLocale.get(), + static_cast<jint>(ap.mMasteringIndication), + static_cast<jboolean>((ap.mAudioDescriptionAvailable == 1) ? 1 : 0), + static_cast<jboolean>((ap.mSpokenSubtitlesAvailable == 1) ? 1 : 0), + static_cast<jboolean>((ap.mDialogueEnhancementAvailable == 1) ? 1 : 0), + jLabelObject.get())); + if (jValueObj != nullptr) { + env->CallBooleanMethod(presentationsJObj, fields.listAddId, jValueObj.get()); } } - - *map = hashMap; - - return OK; } - jobject asJobject(JNIEnv *env, const fields_t& fields, const AudioPresentationInfo &info) { - jobject list = env->NewObject(fields.listclazz, fields.listConstructId); - - for (size_t i = 0; i < info.countPresentations(); ++i) { - const sp<AudioPresentation> &ap = info.getPresentation(i); - jobject jLabelObject; - - sp<AMessage> labelMessage = new AMessage(); - for (size_t i = 0; i < ap->mLabels.size(); ++i) { - labelMessage->setString(ap->mLabels.keyAt(i).string(), - ap->mLabels.valueAt(i).string()); - } - if (ConvertMessageToMap(env, labelMessage, &jLabelObject) != OK) { - return NULL; - } - ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale")); - if (localeClazz.get() == NULL) { - return NULL; - } - jmethodID localeConstructID = - env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V"); - if (localeConstructID == NULL) { - return NULL; - } - jstring jLanguage = env->NewStringUTF(ap->mLanguage.c_str()); - jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage); - jobject jValueObj = env->NewObject(fields.clazz, fields.constructID, - static_cast<jint>(ap->mPresentationId), - static_cast<jint>(ap->mProgramId), - jLocale, - static_cast<jint>(ap->mMasteringIndication), - static_cast<jboolean>((ap->mAudioDescriptionAvailable == 1) ? - 1 : 0), - static_cast<jboolean>((ap->mSpokenSubtitlesAvailable == 1) ? - 1 : 0), - static_cast<jboolean>((ap->mDialogueEnhancementAvailable == 1) ? - 1 : 0), - jLabelObject); - if (jValueObj == NULL) { - env->DeleteLocalRef(jLanguage); jLanguage = NULL; - return NULL; - } + private: + static ScopedLocalRef<jobject> convertLabelsToMap( + JNIEnv *env, const fields_t& fields, const std::map<std::string, std::string> &labels) { + ScopedLocalRef<jobject> nullMap(env, nullptr); + ScopedLocalRef<jobject> hashMap(env, env->NewObject( + fields.hashMapClazz, fields.hashMapConstructID)); + if (hashMap == nullptr) { + return nullMap; + } - env->CallBooleanMethod(list, fields.listAddId, jValueObj); - env->DeleteLocalRef(jLocale); jLocale = NULL; - env->DeleteLocalRef(jValueObj); jValueObj = NULL; - env->DeleteLocalRef(jLanguage); jLanguage = NULL; + for (const auto& label : labels) { + ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(label.first.c_str())); + if (jLanguage == nullptr) return nullMap; + ScopedLocalRef<jobject> jLocale(env, env->NewObject( + fields.ulocaleClazz, + fields.ulocaleConstructID, + jLanguage.get())); + if (jLocale == nullptr) return nullMap; + ScopedLocalRef<jobject> jValue(env, env->NewStringUTF(label.second.c_str())); + if (jValue == nullptr) return nullMap; + env->CallObjectMethod(hashMap.get(), fields.hashMapPutID, jLocale.get(), jValue.get()); } - return list; + return hashMap; } }; } // namespace android diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 15957c6a9c5e..29238d3b8ea4 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "MediaExtractor-JNI" #include <utils/Log.h> +#include "android_media_AudioPresentation.h" #include "android_media_MediaDataSource.h" #include "android_media_MediaExtractor.h" #include "android_media_MediaMetricsJNI.h" @@ -56,6 +57,7 @@ struct fields_t { }; static fields_t gFields; +static JAudioPresentationInfo::fields_t gAudioPresentationFields; JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz) : mClass(NULL), @@ -289,6 +291,10 @@ bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const { return mImpl->getCachedDuration(durationUs, eos); } +status_t JMediaExtractor::getAudioPresentations(size_t trackIdx, + AudioPresentationCollection *presentations) const { + return mImpl->getAudioPresentations(trackIdx, presentations); +} } // namespace android //////////////////////////////////////////////////////////////////////////////// @@ -668,6 +674,28 @@ static jboolean android_media_MediaExtractor_getSampleCryptoInfo( return JNI_TRUE; } +static jobject android_media_MediaExtractor_getAudioPresentations( + JNIEnv *env, jobject thiz, jint trackIdx) { + sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); + jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields); + if (extractor == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return presentationsJObj; + } + AudioPresentationCollection presentations; + status_t err = extractor->getAudioPresentations(trackIdx, &presentations); + if (err == ERROR_END_OF_STREAM || err == ERROR_UNSUPPORTED) { + return presentationsJObj; + } else if (err != OK) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return presentationsJObj; + } + + JAudioPresentationInfo::addPresentations( + env, gAudioPresentationFields, presentations, presentationsJObj); + return presentationsJObj; +} + static void android_media_MediaExtractor_native_init(JNIEnv *env) { jclass clazz = env->FindClass("android/media/MediaExtractor"); CHECK(clazz != NULL); @@ -683,6 +711,8 @@ static void android_media_MediaExtractor_native_init(JNIEnv *env) { gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz, "setPattern", "(II)V"); + + gAudioPresentationFields.init(env); } static void android_media_MediaExtractor_native_setup( @@ -963,6 +993,9 @@ static const JNINativeMethod gMethods[] = { {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaExtractor_native_getMetrics}, + + { "native_getAudioPresentations", "(I)Ljava/util/List;", + (void *)android_media_MediaExtractor_getAudioPresentations }, }; int register_android_media_MediaExtractor(JNIEnv *env) { diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h index aaa8421df48e..baa779c24b09 100644 --- a/media/jni/android_media_MediaExtractor.h +++ b/media/jni/android_media_MediaExtractor.h @@ -18,6 +18,7 @@ #define _ANDROID_MEDIA_MEDIAEXTRACTOR_H_ #include <media/stagefright/foundation/ABase.h> +#include <media/stagefright/foundation/AudioPresentationInfo.h> #include <media/MediaSource.h> #include <media/DataSource.h> #include <utils/Errors.h> @@ -66,6 +67,8 @@ struct JMediaExtractor : public RefBase { status_t getMetrics(Parcel *reply) const; bool getCachedDuration(int64_t *durationUs, bool *eos) const; + status_t getAudioPresentations(size_t trackIdx, + AudioPresentationCollection *presentations) const; protected: virtual ~JMediaExtractor(); diff --git a/media/proto/Android.bp b/media/proto/Android.bp index 50d44c3e6145..74fd5255ecd5 100644 --- a/media/proto/Android.bp +++ b/media/proto/Android.bp @@ -7,6 +7,7 @@ java_library_static { srcs: ["mediaplayer2.proto"], no_framework_libs: true, jarjar_rules: "jarjar-rules.txt", + sdk_version: "28", } cc_library_static { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/SurfaceUtilsTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/SurfaceUtilsTest.java new file mode 100644 index 000000000000..f578e46ea4f1 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/SurfaceUtilsTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mediaframeworktest.unit; + +import android.graphics.ImageFormat; +import android.hardware.camera2.utils.SurfaceUtils; +import android.media.ImageReader; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.Surface; + +import junit.framework.Assert; + +public class SurfaceUtilsTest extends junit.framework.TestCase { + + @SmallTest + public void testInvalidSurfaceException() { + ImageReader reader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 1); + Surface surface = reader.getSurface(); + surface.release(); + + try { + SurfaceUtils.isFlexibleConsumer(surface); + Assert.fail("unreachable"); + } catch (UnsupportedOperationException e) { + // expected + } + + reader.close(); + } +} diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index e7e8384c5567..207508e18a8b 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -144,6 +144,7 @@ LIBANDROID { AHardwareBuffer_describe; # introduced=26 AHardwareBuffer_fromHardwareBuffer; # introduced=26 AHardwareBuffer_getNativeHandle; # introduced=26 + AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; # introduced=26 AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26 AHardwareBuffer_release; # introduced=26 diff --git a/native/webview/plat_support/draw_gl_functor.cpp b/native/webview/plat_support/draw_gl_functor.cpp index 7cb49da483de..e3e52b1ea1f1 100644 --- a/native/webview/plat_support/draw_gl_functor.cpp +++ b/native/webview/plat_support/draw_gl_functor.cpp @@ -42,10 +42,10 @@ AwDrawGLFunction* g_aw_drawgl_function = NULL; class DrawGLFunctor : public Functor { public: explicit DrawGLFunctor(jlong view_context) : view_context_(view_context) {} - virtual ~DrawGLFunctor() {} + ~DrawGLFunctor() override {} // Functor - virtual status_t operator ()(int what, void* data) { + status_t operator ()(int what, void* data) override { using uirenderer::DrawGlInfo; if (!g_aw_drawgl_function) { ALOGE("Cannot draw: no DrawGL Function installed"); diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index 8f13497b2673..f244f9f88684 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -45,6 +45,7 @@ android_app { "androidx.slice_slice-builders", "androidx.arch.core_core-runtime", "androidx.lifecycle_lifecycle-extensions", + "car-theme-lib-bp", "SystemUI-tags", "SystemUI-proto", ], diff --git a/packages/CarSystemUI/res/layout/car_volume_dialog.xml b/packages/CarSystemUI/res/layout/car_volume_dialog.xml index c98740e42701..709797d41060 100644 --- a/packages/CarSystemUI/res/layout/car_volume_dialog.xml +++ b/packages/CarSystemUI/res/layout/car_volume_dialog.xml @@ -20,11 +20,9 @@ android:id="@+id/volume_list" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@android:color/black" android:minWidth="@dimen/volume_dialog_panel_width" - android:theme="@style/Theme.Car.DialogListView" - app:dividerEndMargin="@dimen/car_keyline_1" - app:dividerStartMargin="@dimen/car_keyline_1" + android:theme="@style/PagedListViewTheme" app:gutter="none" app:scrollBarEnabled="false" + app:listDividerColor="@color/list_divider_color" app:showPagedListViewDivider="true"/> diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml index df8f8dba06b9..c510ab6d1046 100644 --- a/packages/CarSystemUI/res/values/colors.xml +++ b/packages/CarSystemUI/res/values/colors.xml @@ -51,4 +51,6 @@ <color name="car_grey_900">#ff212121</color> <color name="keyguard_button_text_color">@android:color/black</color> + + <color name="list_divider_color">@*android:color/car_list_divider_light</color> </resources> diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml index 7f4544a38479..0d95d308f48b 100644 --- a/packages/CarSystemUI/res/values/styles.xml +++ b/packages/CarSystemUI/res/values/styles.xml @@ -41,15 +41,16 @@ <item name="android:colorControlHighlight">@color/nav_bar_ripple_background_color</item> </style> - <style name="Theme.Car.DialogListView" parent="@style/Theme.Car.NoActionBar"> - <item name="android:colorControlActivated">@color/car_accent</item> - <item name="listItemBackgroundColor">@android:color/black</item> - </style> - <style name="NavigationBarButton"> <item name="android:layout_height">96dp</item> <item name="android:layout_width">96dp</item> <item name="android:background">@drawable/nav_button_background</item> </style> -</resources> + <style name="PagedListViewTheme" parent="@style/Theme.CarSupportWrapper.NoActionBar"> + <item name="android:background">@*android:color/car_background</item> + <item name="listItemBackgroundColor">@*android:color/car_background</item> + <item name="dividerEndMargin">@dimen/car_keyline_1</item> + <item name="dividerStartMargin">@dimen/car_keyline_1</item> + </style> +</resources>
\ No newline at end of file diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index 60153fcbc26b..22d0e3b7bdc9 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -355,6 +355,29 @@ public class Assistant extends NotificationAssistantService { } @Override + public void onNotificationExpansionChanged(String key, boolean isUserAction, + boolean isExpanded) { + if (DEBUG) { + Log.i(TAG, + "onNotificationExpansionChanged " + key + ", isUserAction =" + isUserAction + + ", isExpanded = isExpanded"); + } + } + + @Override + public void onNotificationDirectReply(String key) { + if (DEBUG) Log.i(TAG, "onNotificationDirectReply " + key); + } + + @Override + public void onSuggestedReplySent(String key, CharSequence reply, int source) { + if (DEBUG) { + Log.d(TAG, "onSuggestedReplySent() called with: key = [" + key + "], reply = [" + reply + + "], source = [" + source + "]"); + } + } + + @Override public void onListenerConnected() { if (DEBUG) Log.i(TAG, "CONNECTED"); try { diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java index 56feb4726dd6..87d6e4a137ac 100644 --- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java +++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java @@ -16,27 +16,24 @@ package com.android.location.fused; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -import com.android.location.provider.LocationProviderBase; -import com.android.location.provider.ProviderPropertiesUnbundled; -import com.android.location.provider.ProviderRequestUnbundled; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.location.Criteria; -import android.location.LocationProvider; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.UserHandle; import android.os.WorkSource; +import com.android.location.provider.LocationProviderBase; +import com.android.location.provider.ProviderPropertiesUnbundled; +import com.android.location.provider.ProviderRequestUnbundled; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + public class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback { private static final String TAG = "FusedLocationProvider"; @@ -48,7 +45,6 @@ public class FusedLocationProvider extends LocationProviderBase implements Fusio private static final int MSG_DISABLE = 2; private static final int MSG_SET_REQUEST = 3; - private final Context mContext; private final FusionEngine mEngine; private static class RequestWrapper { @@ -62,13 +58,12 @@ public class FusedLocationProvider extends LocationProviderBase implements Fusio public FusedLocationProvider(Context context) { super(TAG, PROPERTIES); - mContext = context; mEngine = new FusionEngine(context, Looper.myLooper()); // listen for user change IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_SWITCHED); - mContext.registerReceiverAsUser(new BroadcastReceiver() { + context.registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -122,14 +117,4 @@ public class FusedLocationProvider extends LocationProviderBase implements Fusio // perform synchronously mEngine.dump(fd, pw, args); } - - @Override - public int onGetStatus(Bundle extras) { - return LocationProvider.AVAILABLE; - } - - @Override - public long onGetStatusUpdateTime() { - return 0; - } } diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index d1f140f4deec..444e72459510 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -16,6 +16,7 @@ android_library { "SettingsLibAppPreference", "SettingsLibSearchWidget", "SettingsLibSettingsSpinner", + "SettingsLayoutPreference", ], // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES diff --git a/packages/SettingsLib/SearchWidget/res/values-as/strings.xml b/packages/SettingsLib/SearchWidget/res/values-as/strings.xml new file mode 100644 index 000000000000..813e7647632a --- /dev/null +++ b/packages/SettingsLib/SearchWidget/res/values-as/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="search_menu" msgid="1604061903696928905">"সন্ধান সম্পৰ্কীয় ছেটিংসমূহ"</string> +</resources> diff --git a/packages/SettingsLib/SettingsLayoutPreference/Android.bp b/packages/SettingsLib/SettingsLayoutPreference/Android.bp new file mode 100644 index 000000000000..489d3606ae15 --- /dev/null +++ b/packages/SettingsLib/SettingsLayoutPreference/Android.bp @@ -0,0 +1,13 @@ +android_library { + name: "SettingsLayoutPreference", + + srcs: ["src/**/*.java"], + resource_dirs: ["res"], + + static_libs: [ + "androidx.preference_preference", + ], + + sdk_version: "system_current", + min_sdk_version: "21", +} diff --git a/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml b/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml new file mode 100644 index 000000000000..4b9f1ab8d6cc --- /dev/null +++ b/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.settingslib.widget"> + + <uses-sdk android:minSdkVersion="21" /> + +</manifest> diff --git a/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml b/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml new file mode 100644 index 000000000000..ee4ce499396f --- /dev/null +++ b/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> diff --git a/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml new file mode 100644 index 000000000000..06782633a4de --- /dev/null +++ b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/entity_header" + style="@style/EntityHeader" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <LinearLayout + android:id="@+id/entity_header_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:gravity="center_horizontal" + android:orientation="vertical"> + + <ImageView + android:id="@+id/entity_header_icon" + android:layout_width="48dp" + android:layout_height="48dp" + android:scaleType="fitXY" + android:antialias="true"/> + + <TextView + android:id="@+id/entity_header_title" + style="@style/TextAppearance.EntityHeaderTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="false" + android:ellipsize="marquee" + android:textDirection="locale" + android:layout_marginTop="8dp"/> + + <TextView + android:id="@+id/install_type" + style="@style/TextAppearance.EntityHeaderSummary" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="2dp"/> + + <TextView + android:id="@+id/entity_header_summary" + style="@style/TextAppearance.EntityHeaderSummary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="2dp"/> + + <TextView + android:id="@+id/entity_header_second_summary" + style="@style/TextAppearance.EntityHeaderSummary" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + </LinearLayout> + + <LinearLayout + android:id="@+id/entity_header_links" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_centerVertical="true" + android:layout_alignParentEnd="true" + android:orientation="vertical"> + + <ImageButton + android:id="@android:id/button1" + style="?android:attr/actionOverflowButtonStyle" + android:layout_width="wrap_content" + android:layout_weight="1" + android:layout_height="0dp" + android:minWidth="24dp" + android:src="@null" + android:tint="?android:attr/colorAccent"/> + + <ImageButton + android:id="@android:id/button2" + style="?android:attr/actionOverflowButtonStyle" + android:layout_width="wrap_content" + android:layout_weight="1" + android:layout_height="0dp" + android:minWidth="24dp" + android:src="@null" + android:tint="?android:attr/colorAccent"/> + + </LinearLayout> + +</RelativeLayout> diff --git a/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml b/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml new file mode 100644 index 000000000000..805744baef10 --- /dev/null +++ b/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + <style name="EntityHeader"> + <item name="android:background">?android:attr/colorPrimaryDark</item> + <item name="android:paddingTop">24dp</item> + <item name="android:paddingBottom">16dp</item> + <item name="android:paddingEnd">16dp</item> + </style> + + <style name="TextAppearance.EntityHeaderTitle" + parent="@android:style/TextAppearance.Material.Subhead"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:textSize">20sp</item> + </style> + + <style name="TextAppearance.EntityHeaderSummary" + parent="@android:style/TextAppearance.Material.Body1"> + <item name="android:textAlignment">viewStart</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:gravity">start</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">marquee</item> + <item name="android:textSize">14sp</item> + </style> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java b/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java new file mode 100644 index 000000000000..2a635b0996e6 --- /dev/null +++ b/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.res.TypedArrayUtils; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + +/** + * A preference can be simply customized a view by adding layout attribute in xml. + * User also can decide whether or not LayoutPreference allows above divider or below divider. + * + * For instances, + * + * <com.android.settingslib.widget.LayoutPreference + * ... + * android:layout="@layout/settings_entity_header" + * xxxxxxx:allowDividerAbove="true" + * xxxxxxx:allowDividerBelow="true" + * + */ +public class LayoutPreference extends Preference { + + private final View.OnClickListener mClickListener = v -> performClick(v); + private boolean mAllowDividerAbove; + private boolean mAllowDividerBelow; + private View mRootView; + + /** + * Constructs a new LayoutPreference with the given context's theme and the supplied + * attribute set. + * + * @param context The Context the view is running in, through which it can + * access the current theme, resources, etc. + * @param attrs The attributes of the XML tag that is inflating the view. + */ + public LayoutPreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0 /* defStyleAttr */); + } + + /** + * Constructs a new LayoutPreference with the given context's theme, the supplied + * attribute set, and default style attribute. + * + * @param context The Context the view is running in, through which it can + * access the current theme, resources, etc. + * @param attrs The attributes of the XML tag that is inflating the view. + * @param defStyleAttr An attribute in the current theme that contains a + * reference to a style resource that supplies default + * values for the view. Can be 0 to not look for + * defaults. + */ + public LayoutPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + + /** + * Constructs a new LayoutPreference with the given context's theme and a customized view id. + * + * @param context The Context the view is running in, through which it can + * access the current theme, resources, etc. + * @param resource The view id which you expected to be inflated and show in preference. + */ + public LayoutPreference(Context context, int resource) { + this(context, LayoutInflater.from(context).inflate(resource, null, false)); + } + + /** + * Constructs a new LayoutPreference with the given context's theme and a customized view. + * + * @param context The Context the view is running in, through which it can + * access the current theme, resources, etc. + * @param view The view which you expected show in preference. + */ + public LayoutPreference(Context context, View view) { + super(context); + setView(view); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Preference); + mAllowDividerAbove = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerAbove, + R.styleable.Preference_allowDividerAbove, false); + mAllowDividerBelow = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerBelow, + R.styleable.Preference_allowDividerBelow, false); + a.recycle(); + + a = context.obtainStyledAttributes( + attrs, R.styleable.Preference, defStyleAttr, 0); + int layoutResource = a.getResourceId(R.styleable.Preference_android_layout, 0); + if (layoutResource == 0) { + throw new IllegalArgumentException("LayoutPreference requires a layout to be defined"); + } + a.recycle(); + + // Need to create view now so that findViewById can be called immediately. + final View view = LayoutInflater.from(getContext()) + .inflate(layoutResource, null, false); + setView(view); + } + + private void setView(View view) { + setLayoutResource(R.layout.layout_preference_frame); + mRootView = view; + setShouldDisableView(false); + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + holder.itemView.setOnClickListener(mClickListener); + + final boolean selectable = isSelectable(); + holder.itemView.setFocusable(selectable); + holder.itemView.setClickable(selectable); + holder.setDividerAllowedAbove(mAllowDividerAbove); + holder.setDividerAllowedBelow(mAllowDividerBelow); + + FrameLayout layout = (FrameLayout) holder.itemView; + layout.removeAllViews(); + ViewGroup parent = (ViewGroup) mRootView.getParent(); + if (parent != null) { + parent.removeView(mRootView); + } + layout.addView(mRootView); + } + + /** + * Finds the view with the given ID. + * + * @param id the ID to search for + * @return a view with given ID if found, or {@code null} otherwise + */ + public <T extends View> T findViewById(int id) { + return mRootView.findViewById(id); + } + + /** + * LayoutPreference whether or not allows to set a below divider. + */ + public void setAllowDividerBelow(boolean allowed) { + mAllowDividerBelow = allowed; + } + + /** + * Return a value whether or not LayoutPreference allows to set a below divider. + */ + public boolean isAllowDividerBelow() { + return mAllowDividerBelow; + } +} diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index d34820cd3a11..1dd783835265 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Kan nie skandeer vir netwerke nie"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Geen"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Gestoor"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Gedeaktiveer"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-opstelling het misluk"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Sal op grond van jou gebruik waarskynlik hou tot omtrent <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Sal waarskynlik hou tot omtrent <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Sal waarskynlik hou tot omtrent <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Tot <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Minder as <xliff:g id="THRESHOLD">%1$s</xliff:g> oor"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Minder as <xliff:g id="THRESHOLD">%1$s</xliff:g> oor (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Meer as <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vra elke keer"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat jy dit afskakel"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Sopas"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aansluitingprogram om opgedateerde grafikadrywer in ontwikkeling te gebruik"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Foonluidspreker"</string> </resources> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index b595e2b05154..2ce5f444834e 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ለአውታረመረቦች መቃኘት አይቻልም"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"የለም"</string> <string name="wifi_remembered" msgid="4955746899347821096">"ተቀምጧል"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"ተሰናክሏል"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"የአይ.ፒ. ውቅረት መሰናከል"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"በአጠቃቀምዎ መሠረት እስከ <xliff:g id="TIME">%1$s</xliff:g> ገደማ መቆየት አለበት"</string> <string name="power_discharge_by" msgid="6453537733650125582">"እስከ <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) ገደማ ድረስ መቆየት አለበት"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"እስከ <xliff:g id="TIME">%1$s</xliff:g> ገደማ መቆየት አለበት"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"እስከ <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"ከ<xliff:g id="THRESHOLD">%1$s</xliff:g> ያነሰ ይቀራል"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"ከ<xliff:g id="THRESHOLD">%1$s</xliff:g> ያነሰ ይቀራል (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"ከ<xliff:g id="TIME_REMAINING">%1$s</xliff:g> በላይ ይቀራል (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ሁልጊዜ ጠይቅ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"እስኪያጠፉት ድረስ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ልክ አሁን"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"በግንባታ ላይ የተዘመነ የግራፊክስ ነጂን ለመጠቀም መተግበሪያን መርጠው ያስገቡ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"የስልክ ድምጽ ማጉያ"</string> </resources> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index f8c2ba2bd20d..23f3a12db8de 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"لا يمكن فحص الشبكات"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"بدون"</string> <string name="wifi_remembered" msgid="4955746899347821096">"تم الحفظ"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"غير مفعّلة"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"تعذّرت تهيئة عنوان IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> حسب استخدامك."</string> <string name="power_discharge_by" msgid="6453537733650125582">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> <string name="power_discharge_by_only" msgid="107616694963545745">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g>."</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"حتى <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"يتبقى أقل من <xliff:g id="THRESHOLD">%1$s</xliff:g>."</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"يتبقى أقل من <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"يتبقى أكثر من <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> @@ -451,4 +453,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"الطلب في كل مرة"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"إلى أن توقف الوضع يدويًا"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"للتو"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"فعِّل التطبيق لاستخدام برنامج تشغيل الرسومات المُحدَّث في تطوير البرامج."</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"مكبر صوت الهاتف"</string> </resources> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index 72122c2648ae..86d145916510 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"নেটৱৰ্ক বিচাৰি স্কেন কৰিব পৰা নাই"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"নাই"</string> <string name="wifi_remembered" msgid="4955746899347821096">"ছেভ কৰি থোৱা নেটৱৰ্কসমূহ"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"নিষ্ক্ৰিয় হৈ আছে"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP কনফিগাৰেশ্বন বিফল হৈছে"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি বেটাৰি আনুমানিকভাৱে <xliff:g id="TIME">%1$s</xliff:g> লৈকে চলিব"</string> <string name="power_discharge_by" msgid="6453537733650125582">"বেটাৰি আনুমানিকভাৱে <xliff:g id="TIME">%1$s</xliff:g> লৈকে চলিব (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"বেটাৰি আনুমানিকভাৱে <xliff:g id="TIME">%1$s</xliff:g> লৈকে চলিব"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> পৰ্যন্ত"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>তকৈও কম সময় বাকী আছে"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g>তকৈও কম সময় বাকী আছে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>তকৈও বেছি সময় বাকী আছে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্ৰতিবাৰতে সোধক"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"আপুনি অফ নকৰা পর্যন্ত"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"এই মাত্ৰ"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"বিকাশকাৰ্য চলি থকা আপডে\'টেড গ্ৰাফিক ড্ৰাইভাৰ ব্যৱহাৰ কৰিবলৈ এপ্ অপ্ট ইন কৰক"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফ’নৰ স্পীকাৰ"</string> </resources> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 23008e2f3a35..17d0ca622a61 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Şəbəkə axtarmaq olmur"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Heç biri"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Yadda saxlanılan"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Deaktiv"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Konfiqurasiya Uğursuzluğu"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"İstifadəyə əsasən təxminən <xliff:g id="TIME">%1$s</xliff:g> olana qədər davam edəcək"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Təxminən <xliff:g id="TIME">%1$s</xliff:g> olana qədər davam edəcək (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Təxminən <xliff:g id="TIME">%1$s</xliff:g> olana qədər davam edəcək"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> olana qədər"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Qalan vaxt <xliff:g id="THRESHOLD">%1$s</xliff:g> və daha azdır"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Qalan vaxt <xliff:g id="THRESHOLD">%1$s</xliff:g> və daha azdır (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Qalan vaxt <xliff:g id="TIME_REMAINING">%1$s</xliff:g> və daha çoxdur (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Hər dəfə soruşun"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Deaktiv edənə qədər"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"İndicə"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Qrafik drayverdən istifadə etmək üçün tətbiq seçin"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon spikeri"</string> </resources> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 3ee8589268cd..56052d214464 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nije moguće skenirati mreže"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nema"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Sačuvano"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogućeno"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP konfiguracija je otkazala"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Trajaće približno do <xliff:g id="TIME">%1$s</xliff:g> na osnovu korišćenja"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Trajaće približno do <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Trajaće približno do <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Preostalo je više od <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -448,4 +450,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uvek pitaj"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogući aplikaciju za korišćenje upravljačkog programa grafičke katice u razvoju"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string> </resources> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index 64253bff6a25..f2c204617b82 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не атрымлiваецца выканаць сканаванне для сетак"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Няма"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Захавана"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Адключана"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Збой канфігурацыі IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Зараду хопіць прыблізна да <xliff:g id="TIME">%1$s</xliff:g> пры цяперашнім узроўні выкарыстання"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Зараду (<xliff:g id="LEVEL">%2$s</xliff:g>) хопіць прыблізна да <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Зараду хопіць прыблізна да <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Да <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Засталося менш за <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Узровень зараду батарэі: <xliff:g id="LEVEL">%2$s</xliff:g> (хопіць менш чым на <xliff:g id="THRESHOLD">%1$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Узровень зараду батарэі: <xliff:g id="LEVEL">%2$s</xliff:g> (хопіць больш чым на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Заўсёды пытацца"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Пакуль не выключыце"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Зараз"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Выбраная праграма, якая выкарыстоўвае абноўлены драйвер графічнай сістэмы (падчас распрацоўкі)"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Дынамік тэлефона"</string> </resources> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 668aa2d82d07..5b8d6b877b2a 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не може да се сканира за мрежи"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Няма"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Запазено"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Деактивирани"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Неуспешно конфигуриране на IP адреса"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Следва да издържи приблизително до <xliff:g id="TIME">%1$s</xliff:g> въз основа на използването"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Следва да издържи приблизително до <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Следва да издържи до около <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"До <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Остава/т по-малко от <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Остава/т по-малко от <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Остава/т повече от <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Да се пита винаги"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"До изключване"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Току-що"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Включване на приложението за използване на актуализирания графичен драйвер в разработка"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Високоговорител на телефона"</string> </resources> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index c6eed2cbf7dc..7efad9998ae1 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"নেটওয়ার্কগুলির জন্য স্ক্যান করা যাবে না"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"কোনো কিছুই নয়"</string> <string name="wifi_remembered" msgid="4955746899347821096">"সংরক্ষিত"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"অক্ষম হয়েছে"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP কনফিগারেশনের ব্যর্থতা"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"বর্তমান ব্যবহার অনুযায়ী আনুমানিক <xliff:g id="TIME">%1$s</xliff:g> পর্যন্ত চলবে"</string> <string name="power_discharge_by" msgid="6453537733650125582">"আনুমানিক <xliff:g id="TIME">%1$s</xliff:g> পর্যন্ত চলবে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"আনুমানিক <xliff:g id="TIME">%1$s</xliff:g> পর্যন্ত চলবে"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> পর্যন্ত"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> এর থেকেও কম বাকি আছে"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"আর <xliff:g id="THRESHOLD">%1$s</xliff:g>-এর কম চার্জ বাকি আছে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"আরও <xliff:g id="TIME_REMAINING">%1$s</xliff:g>-এর বেশি চলবে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্রতিবার জিজ্ঞেস করা হবে"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"যতক্ষণ না আপনি বন্ধ করছেন"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"এখনই"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ডেভলপমেন্টে আপডেট হওয়া গ্রাফিক্স ড্রাইভার ব্যবহার করতে অ্যাপ বেছে নিন"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফেনের স্পিকার"</string> </resources> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 16179fb7157c..92435f7ef1b8 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ne može skenirati mreže"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nema"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Sačuvano"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogućeno"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Greška u konfiguraciji IP-a"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Trebala bi trajati otprilike do <xliff:g id="TIME">%1$s</xliff:g> na osnovu vaše upotrebe"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Trebala bi trajati do otprilike <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Trebala bi trajati otprilike do <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Preostalo je više od <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -448,4 +450,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prijavi aplikaciju za korištenje ažuriranog grafičkog drajvera u razvoju"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string> </resources> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index f906ea4eeef1..3182f16fee44 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"No es poden cercar xarxes"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Cap"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Desat"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desactivat"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Error de configuració d\'IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"La bateria hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g> segons l\'ús que en fas"</string> <string name="power_discharge_by" msgid="6453537733650125582">"La bateria hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"La bateria hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Temps restant inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Temps restant inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Temps restant superior a <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pregunta sempre"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Fins que no ho desactivis"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Ara mateix"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicació activada per utilitzar el controlador de gràfics actualitzat en desenvolupament"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altaveu del telèfon"</string> </resources> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index f9c866992628..37854334c273 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nelze hledat sítě"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Žádné"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Uloženo"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Vypnuto"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Selhání konfigurace protokolu IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Při vašem obvyklém využití vydrží asi do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Vydrží asi do <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Vydrží asi do <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Zbývá méně než <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Zbývá méně než <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Zbývá více než <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pokaždé se zeptat"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Dokud tuto funkci nevypnete"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Právě teď"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Přihlaste aplikaci k použití vyvíjeného aktualizovaného grafického ovladače"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefonu"</string> </resources> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 6b2bd98e4f09..eeeccee81948 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Der kan ikke søges efter netværk"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ingen"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Gemt"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Deaktiveret"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurationsfejl"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Bør holde indtil ca. <xliff:g id="TIME">%1$s</xliff:g> baseret på dit forbrug"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Bør holde indtil ca. <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Bør holde indtil ca. <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Indtil <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Der er mindre end <xliff:g id="THRESHOLD">%1$s</xliff:g> tilbage"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Der er mindre end <xliff:g id="THRESHOLD">%1$s</xliff:g> tilbage (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Der er mere end <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spørg hver gang"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Indtil du deaktiverer"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Lige nu"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Tilvælg en app, der skal bruge den opdaterede grafikdriver under udvikling"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonens højttaler"</string> </resources> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index ad6f5f2112cc..95f7416b1ae3 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Netzwerkscan nicht möglich"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Keine"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Gespeichert"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Deaktiviert"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-Konfigurationsfehler"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Sollte basierend auf deiner Nutzung etwa bis <xliff:g id="TIME">%1$s</xliff:g> reichen"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Sollte etwa bis <xliff:g id="TIME">%1$s</xliff:g> reichen (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Sollte etwa bis <xliff:g id="TIME">%1$s</xliff:g> reichen"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Bis <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Weniger als <xliff:g id="THRESHOLD">%1$s</xliff:g> verbleibend"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Weniger als <xliff:g id="THRESHOLD">%1$s</xliff:g> verbleibend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mehr als <xliff:g id="TIME_REMAINING">%1$s</xliff:g> verbleibend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Jedes Mal fragen"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Bis zur Deaktivierung"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Gerade eben"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App aktivieren, um den aktualisierten Grafiktreiber in der Entwicklung zu verwenden"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon-Lautsprecher"</string> </resources> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 5bfbf2c0c1cb..310b6cf04db7 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Δεν είναι δυνατή η σάρωση για δίκτυα"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Καμία"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Αποθηκευμένο"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Απενεργοποιημένο"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Αποτυχία διαμόρφωσης διεύθυνσης IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Θα διαρκέσει μέχρι τις <xliff:g id="TIME">%1$s</xliff:g> περίπου, ανάλογα με τη χρήση σας"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Θα διαρκέσει μέχρι τις <xliff:g id="TIME">%1$s</xliff:g> περίπου (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Θα διαρκέσει μέχρι τις <xliff:g id="TIME">%1$s</xliff:g> περίπου"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Έως τις <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Απομένει/ουν λιγότερo/α από <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Απομένει/ουν λιγότερo/α από <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Απομένουν περισσότερα/ες από <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Να ερωτώμαι κάθε φορά"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Μέχρι την απενεργοποίηση"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Μόλις τώρα"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Επιλέξτε μια εφαρμογή για τη χρήση του ενημερωμένου προγράμματος οδήγησης γραφικών σε ανάπτυξη"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Ηχείο τηλεφώνου"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index f0eaeed5f885..5b11d63d4ac5 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"None"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> based on your usage"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Should last until about <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Until <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"More than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index f0eaeed5f885..5b11d63d4ac5 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"None"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> based on your usage"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Should last until about <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Until <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"More than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index f0eaeed5f885..5b11d63d4ac5 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"None"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> based on your usage"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Should last until about <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Until <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"More than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index f0eaeed5f885..5b11d63d4ac5 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"None"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> based on your usage"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Should last until about <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Until <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"More than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index 6927fda440e7..d7ed49a067e4 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"None"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> based on your usage"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Should last until about <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Until <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"More than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphcis driver in developement"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string> </resources> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 675084fbed8d..ecec63cd22cf 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"No se pueden buscar las redes."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ninguna"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Guardada"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Inhabilitada"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Error de configuración IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> según el uso"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Hasta <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Tiempo restante: más de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que lo desactives"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Recién"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar app para que use el controlador de gráficos actualizado en el desarrollo"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string> </resources> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index b51b84751def..b8fdf30e673f 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"No se puede buscar redes."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ninguna"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Guardado"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Inhabilitado"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Error de configuración de IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> según el uso"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Hasta: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Queda menos del <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Queda más del <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que se desactive"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Justo ahora"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar aplicación para usar controlador de gráficos actualizado en desarrollo"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string> </resources> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index fb077be51f4f..1246626ce6b1 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Võrke ei saa kontrollida"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Puudub"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Salvestatud"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Keelatud"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP seadistamise ebaõnnestumine"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Peaks teie kasutuse põhjal kestma kuni <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Peaks kestma kuni <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Peaks kestma kuni <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Kuni <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Jäänud on alla <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Jäänud on alla <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Jäänud on üle <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Küsi iga kord"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Kuni välja lülitate"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Äsja"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lubage rakendus, et kasutada arenduses olevat värskendatud graafikadraiverit"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoni kõlar"</string> </resources> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 3d3b8c324f77..68b48408638a 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ezin dira sareak bilatu"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Bat ere ez"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Gordeta"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desgaituta"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Ezin izan da konfiguratu IP helbidea"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Erabileraren arabera, ordu honetara arte iraungo du, gutxi gorabehera: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Ordu honetara arte iraungo du, gutxi gorabehera: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Ordu honetara arte iraungo du, gutxi gorabehera: <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> arte"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> baino gutxiago gelditzen dira"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> baino gutxiago gelditzen da (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> baino gehiago gelditzen da (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Galdetu beti"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Desaktibatu arte"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Oraintxe"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Hautatu zein aplikaziorekin erabili nahi duzun garatze-prozesuan dagoen grafikoen kontrolatzaile eguneratua"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonoaren bozgorailua"</string> </resources> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 0af118ec0ad8..7882b0563a6b 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"اسکن شبکهها امکانپذیر نیست"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"هیچکدام"</string> <string name="wifi_remembered" msgid="4955746899347821096">"ذخیرهشده"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"غیرفعال شد"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"پیکربندی IP انجام نشد"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"باتوجه به میزان مصرفتان، باید حدوداً تا <xliff:g id="TIME">%1$s</xliff:g> شارژ داشته باشید"</string> <string name="power_discharge_by" msgid="6453537733650125582">"باید حدوداً تا <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) شارژ داشته باشید"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"باید حدوداً تا <xliff:g id="TIME">%1$s</xliff:g> شارژ داشته باشید"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"تا <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"کمتر از <xliff:g id="THRESHOLD">%1$s</xliff:g> باقی مانده"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"کمتر از <xliff:g id="THRESHOLD">%1$s</xliff:g> شارژ باقی مانده است (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"بیش از <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"هربار پرسیده شود"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"تا زمانیکه آن را خاموش کنید"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"هماکنون"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"برنامه انتخابشده برای استفاده از درایور گرافیک بهروزرسانیشده در برنامهنویس"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"بلندگوی تلفن"</string> </resources> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index dde10d0d7fcb..1904c4d460e4 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Verkkoja ei voi etsiä."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ei mitään"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Tallennettu"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Pois käytöstä"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-kokoonpanovirhe"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Varaus loppuu käyttösi perusteella noin <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Varaus loppuu noin <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Varaus loppuu noin <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> saakka"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Alle <xliff:g id="THRESHOLD">%1$s</xliff:g> jäljellä"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Alle <xliff:g id="THRESHOLD">%1$s</xliff:g> jäljellä (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Yli <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Kysy aina"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Kunnes poistat sen käytöstä"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Äsken"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lisää sovellus käyttämään päivitettyä grafiikkaohjainta kehitysvaiheessa"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Puhelimen kaiutin"</string> </resources> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 1257ea53c0c0..45b2872820c8 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Impossible de rechercher des réseaux."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Aucune"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Enregistré"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Désactivés"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Échec de configuration de l\'adresse IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g>, en fonction de votre usage"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Jusqu\'à <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Il reste plus de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionnez l\'application pour utiliser le pilote graphique mis à jour en mode de conception"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 444a52ea94b2..13361d74ede1 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Impossible de rechercher des réseaux."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Aucune"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Enregistré"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Désactivé"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Échec de configuration de l\'adresse IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Temps restant estimé en fonction de votre utilisation : <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Temps restant estimé : <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Temps restant estimé : <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Jusqu\'à <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Il reste plus de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionner une application pour le développement de laquelle utiliser le pilote graphique mis à jour"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 8df269719ef6..e8cf009c07a3 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Non se poden explorar redes"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ningunha"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Gardada"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desactivadas"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Erro na configuración de IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"En función do uso, debería durar aproximadamente ata a seguinte hora: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Debería durar aproximadamente ata a seguinte hora: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Debería durar aproximadamente ata a seguinte hora: <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Ata: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tempo restante inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Tempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Tempo restante: máis de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar sempre"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Ata a desactivación"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Subscribirse á aplicación para utilizar o controlador de gráficos actualizado en desenvolvemento"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altofalante do teléfono"</string> </resources> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 4a92f2a4a8e8..918920dbb8bf 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"નેટવર્ક્સ માટે સ્કૅન કરી શકતા નથી"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"કોઈ નહીં"</string> <string name="wifi_remembered" msgid="4955746899347821096">"સાચવેલા"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"અક્ષમ કર્યો"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP કન્ફિગરેશન નિષ્ફળ"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"તમારા વપરાશના આધારે લગભગ <xliff:g id="TIME">%1$s</xliff:g> સુધી ચાલવી જોઈએ"</string> <string name="power_discharge_by" msgid="6453537733650125582">"લગભગ <xliff:g id="TIME">%1$s</xliff:g> સુધી ચાલવી જોઈએ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"લગભગ <xliff:g id="TIME">%1$s</xliff:g> સુધી ચાલવી જોઈએ"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> સુધી"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> કરતાં ઓછો સમય બાકી છે"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> કરતાં ઓછો સમય બાકી છે (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> કરતાં વધુ સમય બાકી છે (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"દર વખતે પૂછો"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"તમે બંધ ન કરો ત્યાં સુધી"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"હમણાં જ"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"અપડેટ કરેલ ગ્રાફિક્સ ડ્રાઇવરનો ઉપયોગ કરવા માટે અૅપ પસંદ કરો"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ફોન સ્પીકર"</string> </resources> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 6d88c3587597..890d0362bfc2 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"नेटवर्क के लिए स्कैन नहीं कर सकता"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"कोई नहीं"</string> <string name="wifi_remembered" msgid="4955746899347821096">"सेव किया गया"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"अक्षम"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP कॉन्फ़िगरेशन की विफलता"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"आपके इस्तेमाल के हिसाब से बैटरी लगभग <xliff:g id="TIME">%1$s</xliff:g> चलेगी"</string> <string name="power_discharge_by" msgid="6453537733650125582">"बैटरी लगभग <xliff:g id="TIME">%1$s</xliff:g> चलेगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"बैटरी लगभग <xliff:g id="TIME">%1$s</xliff:g> चलेगी"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> तक"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> से कम समय बचा है"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> से कम बैटरी बची है (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> से ज़्यादा चलने लायक बैटरी बची है (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"डेवलपमेंट में अपडेट किए गए ग्राफ़िक्स ड्राइवर का इस्तेमाल करने के लिए ऐप्लिकेशन में ऑप्ट इन करें"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फ़ोन स्पीकर"</string> </resources> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 32c9a620b3fb..1464b918ce60 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Skeniranje mreža nije moguće"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nema"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Spremljeno"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogućeno"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Konfiguracija IP-a nije uspjela"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Otprilike bi trebalo trajati do <xliff:g id="TIME">%1$s</xliff:g> na temelju vaše upotrebe"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Otprilike bi trebalo trajati do <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Otprilike bi trebalo trajati do <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Preostalo je više od <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -448,4 +450,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo sad"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uključi aplikaciju za upotrebu ažuriranog upravljačkog programa u razvoju"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string> </resources> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index ed19267f342b..c9fdd4526d0b 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nem lehet beolvasni a hálózatokat"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nincs"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Mentve"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Letiltva"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurációs hiba"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"A használat alapján nagyjából még ennyit bír: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Nagyjából még ennyit bír: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Nagyjából még ennyit bír: <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Eddig: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Kevesebb mint <xliff:g id="THRESHOLD">%1$s</xliff:g> van hátra"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Kevesebb mint <xliff:g id="THRESHOLD">%1$s</xliff:g> van hátra (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Kevesebb mint <xliff:g id="TIME_REMAINING">%1$s</xliff:g> van hátra (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Mindig kérdezzen rá"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Kikapcsolásig"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Az imént"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"A frissített, fejlesztés alatt álló grafikus drivert használja a választott alkalmazás"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hangszórója"</string> </resources> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 6d516ea3d760..3b13ed1dca1c 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Հնարավոր չէ սկանավորել ցանցերը"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ոչ մեկը"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Պահված է"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Անջատված"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP կարգավորման ձախողում"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Լիցքը պետք է, որ բավականացնի մոտ <xliff:g id="TIME">%1$s</xliff:g>՝ կախված օգտագործման եղանակից"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Լիցքը (<xliff:g id="LEVEL">%2$s</xliff:g>) պետք է, որ բավականացնի մոտ <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Լիցքը պետք է, որ բավականացնի մոտ <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Մինչև <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Մնացել է <xliff:g id="THRESHOLD">%1$s</xliff:g>-ից պակաս"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Մնացել է <xliff:g id="THRESHOLD">%1$s</xliff:g>-ից պակաս (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Մնացել է ավելի քան <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Հարցնել ամեն անգամ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Մինչև չանջատեք"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Հենց նոր"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ընտրված հավելվածը, որը պետք է օգտագործի թարմացված գրաֆիկական սարքավարը մշակման ժամանակ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Հեռախոսի բարձրախոս"</string> </resources> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index a5f2317bba7c..4d1b2dfc8971 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tidak dapat memindai jaringan"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Tidak ada"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Disimpan"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Nonaktif"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Kegagalan Konfigurasi IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Akan bertahan kira-kira sampai <xliff:g id="TIME">%1$s</xliff:g> berdasarkan penggunaan Anda"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Akan bertahan kira-kira sampai <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Akan bertahan kira-kira sampai <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Hingga <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tersisa kurang dari <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Tersisa kurang dari <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Tersisa lebih dari <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Selalu tanya"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Sampai Anda menonaktifkannya"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Baru saja"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ikut sertakan aplikasi untuk menggunakan driver grafis yang diupdate dalam pengembangan"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ponsel"</string> </resources> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 6cf09a615eb7..600ffa4d2268 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ekki er hægt að leita að netum"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ekkert"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Vistað"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Óvirkt"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-stillingarvilla"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Ætti að endast til u.þ.b. <xliff:g id="TIME">%1$s</xliff:g> miðað við notkun þína"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Ætti að endast til u.þ.b. <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Ætti að endast til u.þ.b. <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Til klukkan <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Minna en <xliff:g id="THRESHOLD">%1$s</xliff:g> eftir"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Minna en <xliff:g id="THRESHOLD">%1$s</xliff:g> eftir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Meira en <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spyrja í hvert skipti"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Þar til þú slekkur"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Rétt í þessu"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velja að nota uppfærðan myndefnisrekil í þróun í forriti"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Símahátalari"</string> </resources> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index a1b9b82eddf4..068aa91537bc 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Impossibile cercare reti"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nessuna"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Salvata"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disattivata"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Errore configurazione IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Tempo stimato rimanente in base al tuo utilizzo: <xliff:g id="TIME">%1$s</xliff:g> circa"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Tempo stimato rimanente: <xliff:g id="TIME">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Tempo stimato rimanente: <xliff:g id="TIME">%1$s</xliff:g> circa"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Fino alle ore <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tempo rimanente: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Tempo rimanente: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Tempo rimanente: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Chiedi ogni volta"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Fino alla disattivazione"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Adesso"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Attiva l\'app per utilizzare il driver grafico aggiornato nella versione di sviluppo"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlante telefono"</string> </resources> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 1a5062200d77..fa38f774856d 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"לא ניתן לסרוק לאיתור רשתות"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ללא"</string> <string name="wifi_remembered" msgid="4955746899347821096">"נשמר"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"מושבת"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"כשל בתצורת IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"אמורה להחזיק מעמד בערך עד <xliff:g id="TIME">%1$s</xliff:g> על סמך השימוש במכשיר"</string> <string name="power_discharge_by" msgid="6453537733650125582">"אמורה להחזיק מעמד בערך עד <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"אמורה להחזיק מעמד בערך עד <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"עד <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"נותרו פחות מ-<xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"נותרו פחות מ-<xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"נותרו יותר מ-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"שאל בכל פעם"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"עד הכיבוי"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"הרגע"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"האפליקציה שנבחרה לשימוש במנהל ההתקן המעודכן לגרפיקה שבפיתוח"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"רמקול של טלפון"</string> </resources> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 4c544af39fd0..992765499f3f 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ネットワークをスキャンできません"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"なし"</string> <string name="wifi_remembered" msgid="4955746899347821096">"保存済み"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"無効"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP設定エラー"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"電池切れの推定時間: <xliff:g id="TIME">%1$s</xliff:g>(使用状況に基づく)"</string> <string name="power_discharge_by" msgid="6453537733650125582">"電池切れの推定時間: <xliff:g id="TIME">%1$s</xliff:g>(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"電池切れの推定時間: <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> まで"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"残り時間: <xliff:g id="THRESHOLD">%1$s</xliff:g>未満"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"残り時間: <xliff:g id="THRESHOLD">%1$s</xliff:g>未満(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"残り時間: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>以上(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"毎回確認"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"OFF にするまで"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"たった今"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"更新したグラフィックス ドライバを開発に使用するオプトイン アプリ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"スマートフォンのスピーカー"</string> </resources> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 92f304960f59..7ba015337b3b 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ქსელების სკანირება არა არის შესაძლებელი"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"არცერთი"</string> <string name="wifi_remembered" msgid="4955746899347821096">"დამახსოვრებულია"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"გამორთულია"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP კონფიგურაციის შეფერხება"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"უნდა იმუშაოს დაახლოებით <xliff:g id="TIME">%1$s</xliff:g>, მოხმარების გათვალისწინებით"</string> <string name="power_discharge_by" msgid="6453537733650125582">"უნდა იმუშაოს დაახლოებით <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"უნდა იმუშაოს დაახლოებით <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g>-მდე"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"დარჩენილია <xliff:g id="THRESHOLD">%1$s</xliff:g>-ზე ნაკლები"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"დარჩენილია <xliff:g id="THRESHOLD">%1$s</xliff:g>-ზე ნაკლები დრო (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"დარჩენილია <xliff:g id="TIME_REMAINING">%1$s</xliff:g>-ზე მეტი დრო (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ყოველთვის მკითხეთ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"გამორთვამდე"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ახლახან"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"გააქტიურების აპი, რომელიც გამოიყენებს შემუშავების პროცესში მყოფ, განახლებულ გრაფიკულ დრაივერს"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ტელეფონის დინამიკი"</string> </resources> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index b56c6fd1c39d..d5b4441ea07a 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Желілерді шолу мүмкін емес"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ешқандай"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Сақталды"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Өшірілген"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP конфигурациясының қатесі"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Пайдалануға байланысты шамамен <xliff:g id="TIME">%1$s</xliff:g> уақытқа жетеді"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) уақытқа жетеді"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> уақытқа жетеді"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> дейін"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> шамасынан аз қалды"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> шамасынан аз қалды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> шамасынан көп уақыт қалды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Әрдайым сұрау"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Өшірілгенге дейін"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Дәл қазір"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Әзірлеу барысында қолданба жаңартылған графика драйверін пайдаланады"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефон динамигі"</string> </resources> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 58604731a258..d1d1c7681c92 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"មិនអាចវិភាគរកបណ្ដាញ"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"គ្មាន"</string> <string name="wifi_remembered" msgid="4955746899347821096">"បានរក្សាទុក"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"បានបិទ"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"ការកំណត់រចនាសម្ព័ន្ធ IP បរាជ័យ"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"គួរតែអាចប្រើបានរហូតដល់ម៉ោងប្រហែល <xliff:g id="TIME">%1$s</xliff:g> ដោយផ្អែកលើការប្រើប្រាស់របស់អ្នក"</string> <string name="power_discharge_by" msgid="6453537733650125582">"គួរតែអាចប្រើបានរហូតដល់ម៉ោងប្រហែល <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"គួរតែអាចប្រើបានរហូតដល់ម៉ោងប្រហែល <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"រហូតដល់ម៉ោង <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"នៅសល់តិចជាង <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"នៅសល់តិចជាង <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"នៅសល់ច្រើនជាង <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"សួរគ្រប់ពេល"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"រហូតទាល់តែអ្នកបិទ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"អម្បាញ់មិញ"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ភ្ជាប់កម្មវិធី ដើម្បីប្រើដ្រាយវើក្រាហ្វិកដែលបានដំឡើងជំនាន់សម្រាប់ការអភិវឌ្ឍ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ឧបករណ៍បំពងសំឡេងទូរសព្ទ"</string> </resources> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 87e18e68750c..46759f5b79e4 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ನೆಟ್ವರ್ಕ್ಗಳಿಗಾಗಿ ಸ್ಕ್ಯಾನ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ಯಾವುದೂ ಇಲ್ಲ"</string> <string name="wifi_remembered" msgid="4955746899347821096">"ಉಳಿಸಲಾಗಿದೆ"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP ಕಾನ್ಫಿಗರೇಶನ್ ವಿಫಲತೆ"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"ನಿಮ್ಮ ಬಳಕೆ ಆಧರಿಸಿ <xliff:g id="TIME">%1$s</xliff:g> ಸಮಯದವರೆಗೆ ಫೋನ್ ರನ್ ಆಗಬೇಕು"</string> <string name="power_discharge_by" msgid="6453537733650125582">"<xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) ಸಮಯದವರೆಗೆ ಫೋನ್ ರನ್ ಆಗಬೇಕು"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"<xliff:g id="TIME">%1$s</xliff:g> ಸಮಯದವರೆಗೆ ಫೋನ್ ರನ್ ಆಗಬೇಕು"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> ರವರೆಗೆ"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ನಿಮಿಷಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯ ಉಳಿದಿದೆ"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ಕ್ಕಿಂತ ಕಡಿಮೆ (<xliff:g id="LEVEL">%2$s</xliff:g>) ಬಾಕಿ"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಕ್ಕಿಂತ ಹೆಚ್ಚು (<xliff:g id="LEVEL">%2$s</xliff:g>) ಬಾಕಿ"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ಪ್ರತಿ ಬಾರಿ ಕೇಳಿ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ಇದೀಗ"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ಅಭಿವೃದ್ಧಿಯಲ್ಲಿ ಅಪ್ಡೇಟ್ ಮಾಡಲಾದ ಗ್ರಾಫಿಕ್ಗಳ ಡ್ರೈವರ್ ಬಳಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ಫೋನ್ ಸ್ಪೀಕರ್"</string> </resources> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 3333c0dd05d2..067175b75095 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"네트워크를 검색할 수 없습니다."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"없음"</string> <string name="wifi_remembered" msgid="4955746899347821096">"저장됨"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"사용 중지됨"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP 설정 실패"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"사용량을 기준으로 약 <xliff:g id="TIME">%1$s</xliff:g>까지 사용 가능"</string> <string name="power_discharge_by" msgid="6453537733650125582">"약 <xliff:g id="TIME">%1$s</xliff:g>까지 사용 가능(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"약 <xliff:g id="TIME">%1$s</xliff:g>까지 사용 가능"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g>까지"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> 미만 남음"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> 미만 남음(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> 이상 남음(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -435,7 +437,7 @@ <string name="cancel" msgid="6859253417269739139">"취소"</string> <string name="okay" msgid="1997666393121016642">"확인"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="8287824809739581837">"켜기"</string> - <string name="zen_mode_settings_turn_on_dialog_title" msgid="2297134204747331078">"알림 일시중지 사용 설정"</string> + <string name="zen_mode_settings_turn_on_dialog_title" msgid="2297134204747331078">"방해 금지 모드 사용 설정"</string> <string name="zen_mode_settings_summary_off" msgid="6119891445378113334">"사용 안함"</string> <string name="zen_interruption_level_priority" msgid="2078370238113347720">"중요 알림만"</string> <string name="zen_mode_and_condition" msgid="4927230238450354412">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"항상 확인"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"사용 중지할 때까지"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"조금 전"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"개발 중인 업데이트된 그래픽 드라이버를 사용할 앱을 선택하세요."</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"휴대전화 스피커"</string> </resources> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index cbbc47c1b3cf..8e994da2d35f 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Түйүндөрдү издөө мүмкүн эмес"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Жок"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Сакталды"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Өчүрүлгөн"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP конфигурациясы бузулду"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Колдонгонуңузга караганда болжол менен <xliff:g id="TIME">%1$s</xliff:g> кийин өчөт"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Болжол менен <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) кийин өчөт"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Болжол менен <xliff:g id="TIME">%1$s</xliff:g> кийин өчөт"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> чейин"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> жетпеген убакыт калды"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> жетпеген убакыт калды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ашыгыраак убакыт калды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ар дайым суралсын"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Бул функция өчүрүлгөнгө чейин"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Азыр эле"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Иштеп чыгууда жаңыртылган графикалык драйверлерди пайдалануу үчүн колдонмону кошуңуз"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефондун динамиги"</string> </resources> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 21e4679b9019..7bf46c014871 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ບໍ່ສາມາດກວດຫາເຄືອຂ່າຍໄດ້"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ບໍ່ໃຊ້"</string> <string name="wifi_remembered" msgid="4955746899347821096">"ບັນທຶກແລ້ວ"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"ປິດການນຳໃຊ້"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"ການຕັ້ງຄ່າ IP ລົ້ມເຫຼວ"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> based on your usage"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Should last until about <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Should last until about <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"ຈົນກວ່າຈະຮອດ <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"ຍັງເຫຼືອໜ້ອຍກວ່າ <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"ຍັງເຫຼືອໜ້ອຍກວ່າ <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"ຍັງເຫຼືອຫຼາຍກວ່າ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ຖາມທຸກເທື່ອ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"ຈົນກວ່າທ່ານຈະປິດ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ຕອນນີ້"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ເຂົ້າຮ່ວມແອັບເພື່ອໃຊ້ໄດຣເວີກຣາຟິກທີ່ອັບເດດແລ້ວໃນການພັດທະນາ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ລຳໂພງໂທລະສັບ"</string> </resources> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index cbff9e745965..9da3d523c1bd 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nepavyksta nuskaityti tinklų"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nėra"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Išsaugotas"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Neleidžiama"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP konfigūracijos triktis"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Pagal tai, kaip naudojama, turėtų išsikrauti maždaug po <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Turėtų išsikrauti maždaug po <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Turėtų išsikrauti maždaug po <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Iki <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Liko mažiau nei <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Liko mažiau nei <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Liko daugiau nei <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Klausti kaskart"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Kol išjungsite"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Ką tik"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Pasirinkti programą, kuri bus naudojama su atnaujinta kuriama grafikos tvarkykle"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefono garsiakalbis"</string> </resources> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index d200828f6933..2233468642d1 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nevar skenēt tīklus"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nav"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saglabāts"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Atspējots"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP konfigurācijas kļūme"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Ņemot vērā lietojumu, darbosies aptuveni līdz <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Darbosies aptuveni līdz <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Darbosies aptuveni līdz <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Līdz <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Atlikušais laiks — mazāk nekā <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Atlicis mazāk nekā <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Atlicis vairāk nekā <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -448,4 +450,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vaicāt katru reizi"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Līdz brīdim, kad izslēgsiet"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Tikko"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Izvēlēties izmantot atjaunināto grafikas dzini šīs lietotnes izstrādē"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Tālruņa skaļrunis"</string> </resources> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index db16847bd07c..534d154b5fe2 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не може да скенира за мрежи"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ниедна"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Зачувано"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Оневозможено"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Конфигурирањето ИП не успеа"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Треба да трае до околу <xliff:g id="TIME">%1$s</xliff:g> според вашето користење"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Треба да трае до околу <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Треба да трае до околу <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"До <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Уште помалку од <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Уште помалку од <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Уште повеќе од <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Секогаш прашувај"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Додека не го исклучите"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Неодамнешни"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Прифатете ја апликацијата за да се користи ажурираниот драјвер за графика во програмирање"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефонски звучник"</string> </resources> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index c3af9684db4c..7a335cd3920f 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"നെറ്റ്വർക്കുകൾക്കായി സ്കാൻ ചെയ്യാനായില്ല"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ഒന്നുമില്ല"</string> <string name="wifi_remembered" msgid="4955746899347821096">"സംരക്ഷിച്ചു"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"പ്രവർത്തനരഹിതമാക്കി"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP കോൺഫിഗറേഷൻ പരാജയം"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"നിങ്ങളുടെ ഉപയോഗത്തെ അടിസ്ഥാനമാക്കി ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> വരെ നീണ്ടുനിൽക്കേണ്ടതാണ്"</string> <string name="power_discharge_by" msgid="6453537733650125582">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> വരെ നീണ്ടുനിൽക്കേണ്ടതാണ് (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> വരെ നീണ്ടുനിൽക്കേണ്ടതാണ്"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> വരെ"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-ൽ കുറവ് സമയം ശേഷിക്കുന്നു"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-ൽ കുറവ് സമയം ശേഷിക്കുന്നു (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>-ൽ കൂടുതൽ സമയം ശേഷിക്കുന്നു (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"എപ്പോഴും ചോദിക്കുക"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ഇപ്പോൾ"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"വികസനത്തിൽ, അപ്ഡേറ്റ് ചെയ്ത ഗ്രാഫിക്സ് ഡ്രൈവർ ഉപയോഗിക്കാൻ ഓപ്റ്റ് ഇൻ ചെയ്യുക"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ഫോൺ സ്പീക്കർ"</string> </resources> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 8627e1b3b2b5..4816643f6424 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Сүлжээнүүдийг скан хийх боломжгүй"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Байхгүй"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Хадгалагдсан"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Идэвхгүйжүүлсэн"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP тохируулга амжилтгүй"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Таны хэрэглээнд тулгуурлан ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> хүртэл барих ёстой"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> хүртэл барих ёстой (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> хүртэл барих ёстой"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> хүртэл"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-с бага хугацаа үлдсэн"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-с бага хугацаа үлдсэн (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>-с их хугацаа үлдсэн (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Тухай бүрт асуух"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Таныг унтраах хүртэл"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Дөнгөж сая"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Хөгжүүлэлтэд буй шинэчилсэн график драйверийг ашиглахын тулд аппад нэгдэх"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Утасны чанга яригч"</string> </resources> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index cd7f175eabc0..8ebb182ac51c 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"नेटवर्कसाठी स्कॅन करू शकत नाही"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"काहीही नाही"</string> <string name="wifi_remembered" msgid="4955746899347821096">"सेव्ह केले"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"अक्षम"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP कॉन्फिगरेशन अयशस्वी"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"तुमच्या वापरावर अवलंबून सुमारे <xliff:g id="TIME">%1$s</xliff:g> पर्यंत टिकावी"</string> <string name="power_discharge_by" msgid="6453537733650125582">"सुमारे <xliff:g id="TIME">%1$s</xliff:g> पर्यंत टिकेल (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"सुमारे <xliff:g id="TIME">%1$s</xliff:g> पर्यंत टिकावी"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> पर्यंत"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> पेक्षा कमी शिल्लक आहे"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> पेक्षा कमी वेळ शिल्लक आहे (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> पेक्षा जास्त वेळ शिल्लक आहे (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक वेळी विचारा"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"तुम्ही बंद करेपर्यंत"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"आत्ताच"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"अपडेट केलेले ग्राफिक ड्राइव्हर डेव्हलमेंटमध्ये वापरण्यासाठी अॅप निवडा"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनचा स्पीकर"</string> </resources> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index d0b2e12b16b1..359388259048 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tidak boleh mengimbas untuk rangkaian"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Tiada"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Disimpan"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Dinyahdayakan"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Kegagalan Konfigurasi IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Seharusnya boleh digunakan hingga kira-kira <xliff:g id="TIME">%1$s</xliff:g> berdasarkan penggunaan anda"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Seharusnya boleh digunakan hingga kira-kira <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Seharusnya boleh digunakan hingga kira-kira <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Hingga <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tinggal kurang daripada <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Kurang daripada <xliff:g id="THRESHOLD">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Lebih daripada <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Tanya setiap kali"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Sehingga anda matikan"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Sebentar tadi"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sertakan apl untuk menggunakan pemacu grafik yang dikemas kini dalam pembangunan"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Pembesar suara telefon"</string> </resources> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 5f5957c46471..7ac3742cf7a5 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ကွန်ယက်များကို စကင်မလုပ်နိုင်ပါ"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"တစ်ခုမျှ မဟုတ်ပါ"</string> <string name="wifi_remembered" msgid="4955746899347821096">"သိမ်းဆည်းပြီး"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"ပိတ်ထားသည်"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP ပြုပြင်ခြင်း မအောင်မြင်ပါ"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"သင်၏ အသုံးပြုမှုအပေါ် အခြေခံ၍ <xliff:g id="TIME">%1$s</xliff:g> ခန့်အထိ သုံးနိုင်သည်"</string> <string name="power_discharge_by" msgid="6453537733650125582">"<xliff:g id="TIME">%1$s</xliff:g> ခန့်အထိ သုံးနိုင်သည် (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"<xliff:g id="TIME">%1$s</xliff:g> ခန့်အထိ သုံးနိုင်သည်"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> အထိ"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ခန့်သာ ကျန်တော့သည်"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> အောက်သာ ကျန်သည် (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ကျော် ကျန်သည် (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"အမြဲမေးပါ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"သင်ပိတ်လိုက်သည် အထိ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ယခုလေးတင်"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ဆော့ဖ်ဝဲရေးဆွဲမှုအတွင်း အပ်ဒိတ်လုပ်ထားသော ဂရပ်ဖစ်ဒရိုင်ဗာကို အသုံးပြုရန် အက်ပ်ကို ရွေးချယ်ပါ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ဖုန်းစပီကာ"</string> </resources> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 3c240f8ecd6e..ae9c5f2e21a4 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Kan ikke søke etter nettverk"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ingen"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Lagret"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Slått av"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurasjonsfeil"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Skal vare til omtrent <xliff:g id="TIME">%1$s</xliff:g>, basert på bruken din"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Skal vare til omtrent <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Skal vare til omtrent <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Til <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Mindre enn <xliff:g id="THRESHOLD">%1$s</xliff:g> gjenstår"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Mindre enn <xliff:g id="THRESHOLD">%1$s</xliff:g> gjenstår (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mer enn <xliff:g id="TIME_REMAINING">%1$s</xliff:g> gjenstår (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spør hver gang"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Til du slår av"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Nå nettopp"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velg app for å bruke en oppdatert grafikkdriver som er under utvikling"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonhøyttaler"</string> </resources> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 1699870e1ecf..0b4510fda69d 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"सञ्जालका लागि स्क्यान गर्न सक्दैन"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"कुनै पनि होइन"</string> <string name="wifi_remembered" msgid="4955746899347821096">"सुरक्षित गरियो"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"असक्षम पारियो"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP विन्यास असफल"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"तपाईंको प्रयोगका आधारमा लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ"</string> <string name="power_discharge_by" msgid="6453537733650125582">"ब्याट्री लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> सम्म"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी छ"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> भन्दा बढी समय बाँकी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक पटक सोध्नुहोस्"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"तपाईंले निष्क्रिय नपार्दासम्म"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"अहिले भर्खरै"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"विकासको क्रममा अद्यावधिक गरिएको ग्राफिक ड्राइभर प्रयोग गर्न अप्ट इन गर्नुहोस्"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनको स्पिकर"</string> </resources> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 738df94f47fd..f227e1c50505 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Kan niet zoeken naar netwerken"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Geen"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Opgeslagen"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Uitgeschakeld"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-configuratie mislukt"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Is nog genoeg tot ongeveer <xliff:g id="TIME">%1$s</xliff:g> op basis van je gebruik"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Is nog genoeg tot ongeveer <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Is nog genoeg tot ongeveer <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Tot <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Minder dan <xliff:g id="THRESHOLD">%1$s</xliff:g> resterend"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Minder dan <xliff:g id="THRESHOLD">%1$s</xliff:g> resterend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Meer dan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Altijd vragen"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat je uitschakelt"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Zojuist"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Meld een app aan om het geüpdatete grafische stuurprogramma in ontwikkeling te gebruiken"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoonluidspreker"</string> </resources> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 2d39cc6df105..bf8493a40648 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ନେଟ୍ୱର୍କଗୁଡ଼ିକୁ ଖୋଜିପାରୁନାହିଁ"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"କିଛି ନାହିଁ"</string> <string name="wifi_remembered" msgid="4955746899347821096">"ସେଭ୍ ହୋଇଗଲା"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"ଅକ୍ଷମ ହୋଇଛି"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP କନଫିଗରେଶନ ବିଫଳ ହୋଇଛି"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"ଆପଣଙ୍କର ବ୍ୟବହାରକୁ ଆଧାର କରି ବ୍ୟାଟେରୀ <xliff:g id="TIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ ଚାଲିବ"</string> <string name="power_discharge_by" msgid="6453537733650125582">"ବ୍ୟାଟେରୀ ପାଖାପାଖି <xliff:g id="TIME">%1$s</xliff:g> ଚାଲିବ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"ବ୍ୟାଟେରୀ <xliff:g id="TIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ ଚାଲିବ"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>ରୁ କମ୍ ସମୟ ବଳକା ଅଛି"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ରୁ କମ୍ ସମୟ ବଳକା ଅଛି (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>ରୁ ଅଧିକ ସମୟ ବଳକା ଅଛି(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ DND ଅନ୍ ରହିବ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ଏହିକ୍ଷଣି"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ଡେଭଲପ୍ମେଣ୍ଟରେ ଅପ୍ଡେଟ୍ ଗ୍ରାଫିକ୍ସ ଡ୍ରାଇଭର୍ ବ୍ୟବହାର କରିବାକୁ ଆପ୍ଟ ଇନ୍ ଅପ୍ଲିକେସନ୍"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ଫୋନ୍ ସ୍ପିକର୍"</string> </resources> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 61f04470a03e..f948a7e39aa2 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ਨੈਟਵਰਕਾਂ ਲਈ ਸਕੈਨ ਨਹੀਂ ਕਰ ਸਕਦਾ"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ਕੋਈ ਨਹੀਂ"</string> <string name="wifi_remembered" msgid="4955746899347821096">"ਰੱਖਿਅਤ ਕੀਤਾ"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"ਅਯੋਗ ਬਣਾਇਆ"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP ਕੌਂਫਿਗਰੇਸ਼ਨ ਅਸਫਲਤਾ"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"ਤੁਹਾਡੀ ਵਰਤੋਂ ਦੇ ਆਧਾਰ \'ਤੇ ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਚੱਲੇਗਾ"</string> <string name="power_discharge_by" msgid="6453537733650125582">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਚੱਲੇਗਾ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਚੱਲੇਗਾ"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> ਤੱਕ"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ਤੋਂ ਘੱਟ ਸਮਾਂ ਬਾਕੀ"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ਤੋਂ ਘੱਟ ਸਮਾਂ ਬਾਕੀ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਤੋਂ ਵੱਧ ਸਮਾਂ ਬਾਕੀ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ਹੁਣੇ ਹੀ"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ਅੱਪਡੇਟ ਕੀਤੇ ਵਿਕਾਸ-ਅਧੀਨ ਗ੍ਰਾਫਿਕਸ ਡਰਾਈਵਰ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਐਪ ਦੀ ਚੋਣ ਕਰੋ"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string> </resources> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 519f82cf5275..c75a8944c230 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nie można wyszukać sieci."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Brak"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Zapisana"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Wyłączona"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Błąd konfiguracji IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Na podstawie Twojego sposobu korzystania jeszcze około <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Powinno wystarczyć do <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Powinno wystarczyć do <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Pozostało ponad: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Zawsze pytaj"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Dopóki nie wyłączysz"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Przed chwilą"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Wybierz aplikację, która ma używać opracowywanego sterownika grafiki"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Głośnik telefonu"</string> </resources> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 16844a2ec063..c273f59cb754 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Não é possível verificar a existência de redes"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nenhuma"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Salva"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desativado"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Falha de configuração de IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Até <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s)"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s) (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mais de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> restante(s) (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index f01ddfa54d80..26e47293bd8f 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Não é possível verificar redes"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nenhuma"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Guardada"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desativado"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Falha de configuração de IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Deve durar até cerca da(s) <xliff:g id="TIME">%1$s</xliff:g> com base na sua utilização."</string> <string name="power_discharge_by" msgid="6453537733650125582">"Deve durar até cerca da(s) <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Deve durar até cerca da(s) <xliff:g id="TIME">%1$s</xliff:g>."</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Até à(s) <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Resta(m) menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>."</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Resta(m) menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Resta(m) mais de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Até ser desativado"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Optar pela aplicação para utilizar a placa gráfica atualizada em desenvolvimento"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altifalante do telemóvel"</string> </resources> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 16844a2ec063..c273f59cb754 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Não é possível verificar a existência de redes"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Nenhuma"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Salva"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desativado"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Falha de configuração de IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Até <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s)"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s) (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mais de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> restante(s) (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 8a7b4401217c..94f4842644bc 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nu se poate scana pentru rețele"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Niciuna"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Salvată"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Dezactivată"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Eroare de configurație IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"În baza utilizării, ar trebui să reziste până la aproximativ <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Ar trebui să reziste până la <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Ar trebui să reziste până la <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Până la <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"a mai rămas mai puțin de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"A mai rămas mai puțin de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"A mai rămas mai mult de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -448,4 +450,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Întreabă de fiecare dată"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Până când dezactivați"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Chiar acum"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicația pentru înscriere pentru a folosi driverul actualizat al plăcii grafice este în dezvoltare"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Difuzorul telefonului"</string> </resources> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 31274d1c378a..1c331d82164a 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не удалось начать поиск сетей."</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Нет"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Сохранено"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Отключено"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Ошибка IP-конфигурации"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"При текущем уровне использования заряда хватит примерно до <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Заряда (<xliff:g id="LEVEL">%2$s</xliff:g>) хватит примерно до <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Заряда хватит примерно до <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"До <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Осталось менее <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Уровень заряда батареи: <xliff:g id="LEVEL">%2$s</xliff:g> (хватит менее чем на <xliff:g id="THRESHOLD">%1$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Уровень заряда батареи: <xliff:g id="LEVEL">%2$s</xliff:g> (хватит более чем на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Всегда спрашивать"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Пока вы не отключите"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Только что"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Приложение будет использовать обновленный драйвер графической системы (на стадии разработки)"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Встроенный динамик"</string> </resources> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index b22e0689ef3a..608ff7f67542 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ජාල සඳහා පරිලෝකනය කළ නොහැක"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"කිසිවක් නැත"</string> <string name="wifi_remembered" msgid="4955746899347821096">"සුරකින ලදි"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"අබලයි"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP වින්යාස කිරීම අසාර්ථකයි"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"ඔබේ භාවිතය මත පදනම්ව <xliff:g id="TIME">%1$s</xliff:g> පමන වන තෙක් තිබිය යුතුය"</string> <string name="power_discharge_by" msgid="6453537733650125582">"<xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) පමණ වන තෙක් තිබිය යුතුය"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"<xliff:g id="TIME">%1$s</xliff:g> පමණ වන තෙක් තිබිය යුතුය"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> දක්වා"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>ට වඩා අඩුවෙන් ඉතිරිව ඇත"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g>ට වඩා අඩුවෙන් ඉතිරිය (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>ට වඩා වැඩියෙන් ඉතිරිය (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"සෑම විටම ඉල්ලන්න"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"ඔබ ක්රියාවිරහිත කරන තුරු"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"මේ දැන්"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"වැඩිදියුණු වෙමින් ඇති යාවත්කාලීන කළ චිත්රක ධාවකය භාවිත කිරීමට යෙදුමට ඇතුළු වන්න"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"දුරකථන ස්පීකරය"</string> </resources> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 43923b87d6a7..2f76ef97903a 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Siete sa nedajú vyhľadávať"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Žiadne"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Uložené"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Vypnuté"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Zlyhanie konfigurácie adresy IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Mal by vydržať približne do <xliff:g id="TIME">%1$s</xliff:g> v závislosti od využitia"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Mal by vydržať približne <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Mal by vydržať približne do <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Zostáva menej ako <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Zostáva menej ako <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Zostáva viac ako <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vždy sa opýtať"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Dokiaľ túto funkciu nevypnete"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Teraz"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prihlásiť aplikáciu, ktorá má používať aktualizovaný ovládač grafickej karty vo vývoji"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefónu"</string> </resources> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 6d392fe2e57e..64124cb87876 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ni mogoče iskati omrežij"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Brez"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Shranjeno"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogočeno"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Konfiguracija IP-ja ni uspela"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Naprava bi morala glede na način uporabe delovati do približno <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Naprava bi morala delovati do približno <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Naprava bi morala delovati do približno <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo manj kot <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Preostanek: manj kot <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Preostali čas delovanja: manj kot <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vedno vprašaj"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Dokler ne izklopite"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Pravkar"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogočena aplikacija za uporabo posodobljenega grafičnega gonilnika pri razvoju"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvočnik telefona"</string> </resources> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index e05a01953904..25d575efedb5 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nuk mund të skanojë për rrjete"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Asnjë"</string> <string name="wifi_remembered" msgid="4955746899347821096">"U ruajt"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Të çaktivizuara"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Dështim në konfigurimin e IP-së"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Duhet të zgjasë deri në rreth <xliff:g id="TIME">%1$s</xliff:g> bazuar në përdorimin tënd"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Duhet të zgjasë deri në rreth <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Duhet të zgjasë deri në rreth <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Deri në <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Më pak se <xliff:g id="THRESHOLD">%1$s</xliff:g> të mbetura"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Mbeten më pak se <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mbeten më shumë se <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pyet çdo herë"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Deri sa ta çaktivizosh"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Pikërisht tani"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prano aplikacionin për të përdorur drejtuesin e përditësuar të grafikës që është në zhvillim"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlanti i telefonit"</string> </resources> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 371b909d987b..b58b47caa8ae 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Није могуће скенирати мреже"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Нема"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Сачувано"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Онемогућено"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP конфигурација је отказала"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Трајаће приближно до <xliff:g id="TIME">%1$s</xliff:g> на основу коришћења"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Трајаће приближно до <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Трајаће приближно до <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"До <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Преостало је мање од <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Преостало је мање од <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Преостало је више од <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -448,4 +450,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Увек питај"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Док не искључите"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Управо"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Омогући апликацију за коришћење управљачког програма графичке катице у развоју"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Звучник телефона"</string> </resources> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index e6872bb35d8a..7198b84ed035 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Det går inte att söka efter nätverk"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Ingen"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Sparat"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Inaktiverad"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurationsfel"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Bör räcka ungefär till klockan <xliff:g id="TIME">%1$s</xliff:g> utifrån din användning"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Bör räcka ungefär till klockan <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Bör räcka ungefär till klockan <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Till kl. <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Mindre än <xliff:g id="THRESHOLD">%1$s</xliff:g> återstår"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Mindre än <xliff:g id="THRESHOLD">%1$s</xliff:g> återstår (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mer än <xliff:g id="TIME_REMAINING">%1$s</xliff:g> återstår (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Fråga varje gång"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Tills du inaktiverar funktionen"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Nyss"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Välj om appen ska använda den uppdaterade grafikdrivrutinen under utveckling"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Mobilens högtalare"</string> </resources> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 23efb916c4ca..657b54f02066 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Haiwezi kutambaza mitandao"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Hamna"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Imehifadhiwa"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Imezimwa"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Haikuweza Kusanidi IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Inapaswa kudumu hadi <xliff:g id="TIME">%1$s</xliff:g> kulingana na jinsi unavyoitumia"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Inapaswa kudumu kwa takribani <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Inapaswa kudumu hadi <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Hadi <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Zimesalia chini ya <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Zimesalia chini ya <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Zimesalia zaidi ya <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uliza kila wakati"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Hadi utakapoizima"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Sasa hivi"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chagua programu itakayotumia kiendeshaji cha michoro kilichosasishwa katika hatua ya kusanidi"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Spika ya simu"</string> </resources> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 53ba7386c9ae..59b42d834c34 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"நெட்வொர்க்குகளுக்கு ஸ்கேன் செய்யப்படவில்லை"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ஏதுமில்லை"</string> <string name="wifi_remembered" msgid="4955746899347821096">"சேமிக்கப்பட்டது"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"முடக்கப்பட்டது"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP உள்ளமைவில் தோல்வி"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"நீங்கள் பயன்படுத்துவதன் அடிப்படையில் <xliff:g id="TIME">%1$s</xliff:g> வரை உபயோகிக்க முடியும்"</string> <string name="power_discharge_by" msgid="6453537733650125582">"<xliff:g id="TIME">%1$s</xliff:g> வரை பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"<xliff:g id="TIME">%1$s</xliff:g> வரை பயன்படுத்த முடியும்"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> வரை"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்த முடியும்"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>க்கும் மேல் பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ஒவ்வொரு முறையும் கேள்"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"ஆஃப் செய்யும் வரை"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"சற்றுமுன்"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"உருவாக்கத்திலுள்ள புதுப்பிக்கப்பட்ட கிராஃபிக்ஸ் டிரைவரைப் பயன்படுத்த ஆப்ஸைத் தேர்ந்தெடுக்கவும்"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"மொபைல் ஸ்பீக்கர்"</string> </resources> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index c8c6b4ce69f6..af233dae55a3 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"నెట్వర్క్ల కోసం స్కాన్ చేయడం సాధ్యపడదు"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ఏదీ లేదు"</string> <string name="wifi_remembered" msgid="4955746899347821096">"సేవ్ చేయబడింది"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"నిలిపివేయబడింది"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP కాన్ఫిగరేషన్ వైఫల్యం"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"మీ వినియోగం ఆధారంగా దాదాపు <xliff:g id="TIME">%1$s</xliff:g> వరకు ఉండాలి"</string> <string name="power_discharge_by" msgid="6453537733650125582">"దాదాపు <xliff:g id="TIME">%1$s</xliff:g> వరకు ఉండాలి (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"దాదాపు <xliff:g id="TIME">%1$s</xliff:g> వరకు ఉండాలి"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> వరకు"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> కంటే తక్కువ సమయం మిగిలి ఉంది"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> కంటే తక్కువ సమయం మిగిలి ఉంది (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> కంటే ఎక్కువ సమయం మిగిలి ఉంది (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ప్రతిసారి అడుగు"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"మీరు ఆఫ్ చేసే వరకు"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ఇప్పుడే"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"అభివృద్దిలో అప్డేట్ చేసిన గ్రాఫిక్ డ్రైవర్ను ఉపయోగించడానికి యాప్ని ప్రారంభించండి"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ఫోన్ స్పీకర్"</string> </resources> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index d293d590f1a2..636c3f2f19c0 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ไม่สามารถสแกนหาเครือข่าย"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"ไม่มี"</string> <string name="wifi_remembered" msgid="4955746899347821096">"บันทึกแล้ว"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"ปิดอยู่"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"การกำหนดค่า IP ล้มเหลว"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"น่าจะใช้งานได้ถึงเวลาประมาณ <xliff:g id="TIME">%1$s</xliff:g> เมื่อดูจากการใช้งานของคุณ"</string> <string name="power_discharge_by" msgid="6453537733650125582">"น่าจะใช้งานได้ถึงเวลาประมาณ <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"น่าจะใช้งานได้ถึงเวลาประมาณ <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"จนถึง <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"เหลืออีกไม่ถึง <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"เหลือเวลาอีกไม่ถึง <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"เหลือเวลามากกว่า <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ถามทุกครั้ง"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"จนกว่าคุณจะปิด"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"เมื่อสักครู่"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"เลือกใช้แอปเพื่อใช้ไดรเวอร์กราฟิกที่อัปเดตในการพัฒนา"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ลำโพงโทรศัพท์"</string> </resources> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 9da4561c65b6..1bcc36a62618 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Hindi makapag-scan ng mga network"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Wala"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Na-save"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Naka-disable"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Pagkabigo ng Configuration ng IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Tatagal dapat nang hanggang humigit-kumulang <xliff:g id="TIME">%1$s</xliff:g> batay sa iyong paggamit"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Tatagal dapat nang hanggang humigit-kumulang <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Tatagal hanggang mga <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Hanggang <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Wala nang <xliff:g id="THRESHOLD">%1$s</xliff:g> ang natitira"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Wala nang <xliff:g id="THRESHOLD">%1$s</xliff:g> ang natitira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mahigit <xliff:g id="TIME_REMAINING">%1$s</xliff:g> pa ang natitira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Magtanong palagi"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Hanggang sa i-off mo"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Ngayon lang"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App sa pag-opt in para magamit ang na-update na graphics driver na ginagawa"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ng telepono"</string> </resources> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 2d5cd7f36f55..ff669f6a5f72 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ağlar taranamıyor"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Yok"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Kaydedildi"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Devre dışı"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Yapılandırması Hatası"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Kullanımınıza göre saat yaklaşık <xliff:g id="TIME">%1$s</xliff:g> olana kadar kullanılabilmelidir"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Saat yaklaşık <xliff:g id="TIME">%1$s</xliff:g> olana kadar kullanılabilmelidir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Saat yaklaşık <xliff:g id="TIME">%1$s</xliff:g> olana kadar kullanılabilmelidir"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Şu saate kadar: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"En fazla <xliff:g id="THRESHOLD">%1$s</xliff:g> kaldı"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"En çok <xliff:g id="THRESHOLD">%1$s</xliff:g> kaldı (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"En az <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Her zaman sor"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Siz kapatana kadar"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Az önce"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Güncellenmiş grafik sürücüsünü geliştirme ortamında kullanmak için uygulamayı kaydedin"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hoparlörü"</string> </resources> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 512ea86da467..2ded8c187936 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Неможливо здійснити сканування мереж"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Немає"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Збережено"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Вимкнено"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Помилка конфігурації IP-адреси"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"На основі даних про використання, вистачить приблизно до <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Вистачить приблизно до <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Вистачить приблизно до <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"До <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Залишилося менше ніж <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Залишилося менше ніж <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Залишилося понад <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -449,4 +451,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Запитувати щоразу"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Доки ви не вимкнете"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Щойно"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Вибраний додаток, який використовуватиме оновлений графічний драйвер під час розробки"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Динамік телефона"</string> </resources> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index 84ad3ed16410..7dc46906327c 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"نیٹ ورکس کیلئے اسکین نہيں کر سکتے ہیں"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"کوئی نہیں"</string> <string name="wifi_remembered" msgid="4955746899347821096">"محفوظ کردیا گیا"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"غیر فعال"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP کنفیگریشن کی ناکامی"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"آپ کے استعمال کی بنیاد پر تقریباً <xliff:g id="TIME">%1$s</xliff:g> تک بیٹری چلے گی"</string> <string name="power_discharge_by" msgid="6453537733650125582">"تقریباً <xliff:g id="TIME">%1$s</xliff:g> تک بیٹری چلے گی (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"تقریباً <xliff:g id="TIME">%1$s</xliff:g> تک بیٹری چلے گی"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> تک"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> سے کم باقی ہے"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> سے کم باقی ہے (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> سے زیادہ باقی ہے (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ہر بار پوچھیں"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"یہاں تک کہ آپ آف کر دیں"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ابھی ابھی"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ڈیولپمنٹ میں اپ ڈیٹ کردہ گرافکس ڈرائیور کو استعمال کرنے کے لیے ایپ آپٹ ان کریں"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"فون اسپیکر"</string> </resources> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index af2ada59c770..5f92c9ad52ce 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tarmoqlarni tekshirib chiqishni iloji bo‘lmadi"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Hech qanday"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saqlandi"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"O‘chiq"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP manzilini sozlab bo‘lmadi"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Joriy holatda taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha davom etadi"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha davom etadi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha davom etadi"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> gacha"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>dan kamroq vaqt qoldi"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g>dan kamroq vaqt qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>dan ko‘proq vaqt qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Har safar so‘ralsin"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Bekor qilinmaguncha"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Hozir"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ilova yangilangan grafik drayverdan (hali ishlov jarayonida) foydalanadi"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon karnayi"</string> </resources> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index f454127547ea..eb10fb1abb2e 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Không thể dò tìm mạng"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Không"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Đã lưu"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Đã tắt"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Lỗi cấu hình IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Sẽ hết pin cho tới khoảng <xliff:g id="TIME">%1$s</xliff:g> dựa trên mức sử dụng của bạn"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Sẽ hết pin cho tới khoảng <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Sẽ hết pin cho tới khoảng <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Cho đến <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Còn lại không đến <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Còn lại không đến <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Còn lại hơn <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Luôn hỏi"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Cho đến khi bạn tắt"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Vừa xong"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chọn ứng dụng để sử dụng trình điều khiển đồ họa được cập nhật trong giai đoạn phát triển"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Loa điện thoại"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 10a20bef083f..7b14138287a3 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"无法扫描网络"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"无"</string> <string name="wifi_remembered" msgid="4955746899347821096">"已保存"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"已停用"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP 配置失败"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"根据您的使用情况,估计大约还能用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"目前电量为 <xliff:g id="LEVEL">%2$s</xliff:g>,估计大约还能用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"估计大约还能用到<xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"直到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"剩余电池续航时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"电量剩余使用时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"电量剩余使用时间超过 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都询问"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"直到您将其关闭"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"刚刚"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"为应用启用更新后的显卡驱动,以在开发过程中使用"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手机扬声器"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index 15105453c5b6..48b6959129ad 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"無法掃瞄網絡"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"無"</string> <string name="wifi_remembered" msgid="4955746899347821096">"已儲存"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"已停用"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP 設定失敗"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"根據您的使用情況,電量剩餘約 <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"電量剩餘約 <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"電量剩餘約 <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"還可用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"剩餘電量時間少於 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"還有少於 <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"還有超過 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"直至您關閉為止"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"請選取應用程式,以在開發階段使用更新的顯示卡驅動程式"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 90c0d808cd08..684569b819e2 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"無法掃描網路"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"無"</string> <string name="wifi_remembered" msgid="4955746899347821096">"已儲存"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"已停用"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP 設定失敗"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"根據你的使用情形,預估可持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="6453537733650125582">"目前電量 <xliff:g id="LEVEL">%2$s</xliff:g>,預估還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"預估還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"電池可用時間超過 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"直到你關閉為止"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"選取要在開發階段使用最新版繪圖驅動程式的應用程式"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string> </resources> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index e4f9f4d77733..d107a5a80f1b 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -21,6 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ayikwazi ukuhlola amanethiwekhi"</string> + <string name="wifi_security_none" msgid="7985461072596594400">"Lutho"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Kulondoloziwe"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"Akusebenzi"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Ukwehluleka kokulungiswa kwe-IP"</string> @@ -374,6 +375,7 @@ <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Kumele ihlale cishe kube ngu-<xliff:g id="TIME">%1$s</xliff:g> kusukela ekusetshenzisweni kwakho"</string> <string name="power_discharge_by" msgid="6453537733650125582">"Kumele ihlale cishe kube ngu-<xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"Kumele ihlale cishe kube ngu-<xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Kuze kube ngu-<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Kusele okungaphansi kunokungu-<xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Ngaphansi kuka-<xliff:g id="THRESHOLD">%1$s</xliff:g> osele (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Ngaphezu kuka-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -447,4 +449,6 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Buza njalo"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"Uze uvale isikrini"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Khona manje"</string> + <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uhlelo lokusebenza lokukhetha ukungena olungasebenzisa idrayivu yamagrafikhi ekuthuthukiseni"</string> + <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Isipikha sefoni"</string> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 45a3bb07a952..a97e05442b6d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -54,18 +54,17 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private final Context mContext; private final BluetoothAdapter mLocalAdapter; private final LocalBluetoothProfileManager mProfileManager; + private final Object mProfileLock = new Object(); BluetoothDevice mDevice; private long mHiSyncId; // Need this since there is no method for getting RSSI short mRssi; // mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is // because current sub device is only for HearingAid and its profile is the same. - private final List<LocalBluetoothProfile> mProfiles = - Collections.synchronizedList(new ArrayList<>()); + private final List<LocalBluetoothProfile> mProfiles = new ArrayList<>(); // List of profiles that were previously in mProfiles, but have been removed - private final List<LocalBluetoothProfile> mRemovedProfiles = - Collections.synchronizedList(new ArrayList<>()); + private final List<LocalBluetoothProfile> mRemovedProfiles = new ArrayList<>(); // Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP private boolean mLocalNapRoleConnected; @@ -74,7 +73,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private int mMessageRejectionCount; - private final Collection<Callback> mCallbacks = new ArrayList<Callback>(); + private final Collection<Callback> mCallbacks = new ArrayList<>(); // How many times user should reject the connection to make the choice persist. private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2; @@ -134,36 +133,42 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } return; } - if (newProfileState == BluetoothProfile.STATE_CONNECTED) { - if (profile instanceof MapProfile) { - profile.setPreferred(mDevice, true); - } - if (!mProfiles.contains(profile)) { - mRemovedProfiles.remove(profile); - mProfiles.add(profile); - if (profile instanceof PanProfile && - ((PanProfile) profile).isLocalRoleNap(mDevice)) { - // Device doesn't support NAP, so remove PanProfile on disconnect - mLocalNapRoleConnected = true; + + synchronized (mProfileLock) { + if (newProfileState == BluetoothProfile.STATE_CONNECTED) { + if (profile instanceof MapProfile) { + profile.setPreferred(mDevice, true); } + if (!mProfiles.contains(profile)) { + mRemovedProfiles.remove(profile); + mProfiles.add(profile); + if (profile instanceof PanProfile + && ((PanProfile) profile).isLocalRoleNap(mDevice)) { + // Device doesn't support NAP, so remove PanProfile on disconnect + mLocalNapRoleConnected = true; + } + } + } else if (profile instanceof MapProfile + && newProfileState == BluetoothProfile.STATE_DISCONNECTED) { + profile.setPreferred(mDevice, false); + } else if (mLocalNapRoleConnected && profile instanceof PanProfile + && ((PanProfile) profile).isLocalRoleNap(mDevice) + && newProfileState == BluetoothProfile.STATE_DISCONNECTED) { + Log.d(TAG, "Removing PanProfile from device after NAP disconnect"); + mProfiles.remove(profile); + mRemovedProfiles.add(profile); + mLocalNapRoleConnected = false; } - } else if (profile instanceof MapProfile && - newProfileState == BluetoothProfile.STATE_DISCONNECTED) { - profile.setPreferred(mDevice, false); - } else if (mLocalNapRoleConnected && profile instanceof PanProfile && - ((PanProfile) profile).isLocalRoleNap(mDevice) && - newProfileState == BluetoothProfile.STATE_DISCONNECTED) { - Log.d(TAG, "Removing PanProfile from device after NAP disconnect"); - mProfiles.remove(profile); - mRemovedProfiles.add(profile); - mLocalNapRoleConnected = false; } + fetchActiveDevices(); } public void disconnect() { - for (LocalBluetoothProfile profile : mProfiles) { - disconnect(profile); + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : mProfiles) { + disconnect(profile); + } } // Disconnect PBAP server in case its connected // This is to ensure all the profiles are disconnected as some CK/Hs do not @@ -210,32 +215,35 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } private void connectWithoutResettingTimer(boolean connectAllProfiles) { - // Try to initialize the profiles if they were not. - if (mProfiles.isEmpty()) { - // if mProfiles is empty, then do not invoke updateProfiles. This causes a race - // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated - // from bluetooth stack but ACTION.uuid is not sent yet. - // Eventually ACTION.uuid will be received which shall trigger the connection of the - // various profiles - // If UUIDs are not available yet, connect will be happen - // upon arrival of the ACTION_UUID intent. - Log.d(TAG, "No profiles. Maybe we will connect later"); - return; - } + synchronized (mProfileLock) { + // Try to initialize the profiles if they were not. + if (mProfiles.isEmpty()) { + // if mProfiles is empty, then do not invoke updateProfiles. This causes a race + // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been + // updated from bluetooth stack but ACTION.uuid is not sent yet. + // Eventually ACTION.uuid will be received which shall trigger the connection of the + // various profiles + // If UUIDs are not available yet, connect will be happen + // upon arrival of the ACTION_UUID intent. + Log.d(TAG, "No profiles. Maybe we will connect later"); + return; + } - int preferredProfiles = 0; - for (LocalBluetoothProfile profile : mProfiles) { - if (connectAllProfiles ? profile.accessProfileEnabled() : profile.isAutoConnectable()) { - if (profile.isPreferred(mDevice)) { - ++preferredProfiles; - connectInt(profile); + int preferredProfiles = 0; + for (LocalBluetoothProfile profile : mProfiles) { + if (connectAllProfiles ? profile.accessProfileEnabled() + : profile.isAutoConnectable()) { + if (profile.isPreferred(mDevice)) { + ++preferredProfiles; + connectInt(profile); + } } } - } - if (BluetoothUtils.D) Log.d(TAG, "Preferred profiles = " + preferredProfiles); + if (BluetoothUtils.D) Log.d(TAG, "Preferred profiles = " + preferredProfiles); - if (preferredProfiles == 0) { - connectAutoConnectableProfiles(); + if (preferredProfiles == 0) { + connectAutoConnectableProfiles(); + } } } @@ -244,10 +252,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return; } - for (LocalBluetoothProfile profile : mProfiles) { - if (profile.isAutoConnectable()) { - profile.setPreferred(mDevice, true); - connectInt(profile); + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : mProfiles) { + if (profile.isAutoConnectable()) { + profile.setPreferred(mDevice, true); + connectInt(profile); + } } } } @@ -515,14 +525,16 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> * @return Whether it is connected. */ public boolean isConnected() { - for (LocalBluetoothProfile profile : mProfiles) { - int status = getProfileConnectionState(profile); - if (status == BluetoothProfile.STATE_CONNECTED) { - return true; + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : mProfiles) { + int status = getProfileConnectionState(profile); + if (status == BluetoothProfile.STATE_CONNECTED) { + return true; + } } - } - return false; + return false; + } } public boolean isConnectedProfile(LocalBluetoothProfile profile) { @@ -532,14 +544,16 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } public boolean isBusy() { - for (LocalBluetoothProfile profile : mProfiles) { - int status = getProfileConnectionState(profile); - if (status == BluetoothProfile.STATE_CONNECTING - || status == BluetoothProfile.STATE_DISCONNECTING) { - return true; + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : mProfiles) { + int status = getProfileConnectionState(profile); + if (status == BluetoothProfile.STATE_CONNECTING + || status == BluetoothProfile.STATE_DISCONNECTING) { + return true; + } } + return getBondState() == BluetoothDevice.BOND_BONDING; } - return getBondState() == BluetoothDevice.BOND_BONDING; } private boolean updateProfiles() { @@ -554,8 +568,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> */ processPhonebookAccess(); - mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles, - mLocalNapRoleConnected, mDevice); + synchronized (mProfileLock) { + mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles, + mLocalNapRoleConnected, mDevice); + } if (BluetoothUtils.D) { Log.e(TAG, "updating profiles for " + mDevice.getAliasName()); @@ -616,7 +632,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void onBondingStateChanged(int bondState) { if (bondState == BluetoothDevice.BOND_NONE) { - mProfiles.clear(); + synchronized (mProfileLock) { + mProfiles.clear(); + } mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_UNKNOWN); mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_UNKNOWN); mDevice.setSimAccessPermission(BluetoothDevice.ACCESS_UNKNOWN); @@ -646,9 +664,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> public List<LocalBluetoothProfile> getConnectableProfiles() { List<LocalBluetoothProfile> connectableProfiles = new ArrayList<LocalBluetoothProfile>(); - for (LocalBluetoothProfile profile : mProfiles) { - if (profile.accessProfileEnabled()) { - connectableProfiles.add(profile); + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : mProfiles) { + if (profile.accessProfileEnabled()) { + connectableProfiles.add(profile); + } } } return connectableProfiles; @@ -823,10 +843,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> public int getMaxConnectionState() { int maxState = BluetoothProfile.STATE_DISCONNECTED; - for (LocalBluetoothProfile profile : getProfiles()) { - int connectionStatus = getProfileConnectionState(profile); - if (connectionStatus > maxState) { - maxState = connectionStatus; + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : getProfiles()) { + int connectionStatus = getProfileConnectionState(profile); + if (connectionStatus > maxState) { + maxState = connectionStatus; + } } } return maxState; @@ -843,32 +865,34 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean hfpConnected = true; // HFP is connected boolean hearingAidConnected = true; // Hearing Aid is connected - for (LocalBluetoothProfile profile : getProfiles()) { - int connectionStatus = getProfileConnectionState(profile); - - switch (connectionStatus) { - case BluetoothProfile.STATE_CONNECTING: - case BluetoothProfile.STATE_DISCONNECTING: - return mContext.getString( - BluetoothUtils.getConnectionStateSummary(connectionStatus)); - - case BluetoothProfile.STATE_CONNECTED: - profileConnected = true; - break; - - case BluetoothProfile.STATE_DISCONNECTED: - if (profile.isProfileReady()) { - if ((profile instanceof A2dpProfile) || - (profile instanceof A2dpSinkProfile)) { - a2dpConnected = false; - } else if ((profile instanceof HeadsetProfile) || - (profile instanceof HfpClientProfile)) { - hfpConnected = false; - } else if (profile instanceof HearingAidProfile) { - hearingAidConnected = false; + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : getProfiles()) { + int connectionStatus = getProfileConnectionState(profile); + + switch (connectionStatus) { + case BluetoothProfile.STATE_CONNECTING: + case BluetoothProfile.STATE_DISCONNECTING: + return mContext.getString( + BluetoothUtils.getConnectionStateSummary(connectionStatus)); + + case BluetoothProfile.STATE_CONNECTED: + profileConnected = true; + break; + + case BluetoothProfile.STATE_DISCONNECTED: + if (profile.isProfileReady()) { + if (profile instanceof A2dpProfile + || profile instanceof A2dpSinkProfile) { + a2dpConnected = false; + } else if (profile instanceof HeadsetProfile + || profile instanceof HfpClientProfile) { + hfpConnected = false; + } else if (profile instanceof HearingAidProfile) { + hearingAidConnected = false; + } } - } - break; + break; + } } } @@ -924,32 +948,34 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean hfpNotConnected = false; // HFP is preferred but not connected boolean hearingAidNotConnected = false; // Hearing Aid is preferred but not connected - for (LocalBluetoothProfile profile : getProfiles()) { - int connectionStatus = getProfileConnectionState(profile); - - switch (connectionStatus) { - case BluetoothProfile.STATE_CONNECTING: - case BluetoothProfile.STATE_DISCONNECTING: - return mContext.getString( - BluetoothUtils.getConnectionStateSummary(connectionStatus)); - - case BluetoothProfile.STATE_CONNECTED: - profileConnected = true; - break; - - case BluetoothProfile.STATE_DISCONNECTED: - if (profile.isProfileReady()) { - if ((profile instanceof A2dpProfile) || - (profile instanceof A2dpSinkProfile)){ - a2dpNotConnected = true; - } else if ((profile instanceof HeadsetProfile) || - (profile instanceof HfpClientProfile)) { - hfpNotConnected = true; - } else if (profile instanceof HearingAidProfile) { - hearingAidNotConnected = true; + synchronized (mProfileLock) { + for (LocalBluetoothProfile profile : getProfiles()) { + int connectionStatus = getProfileConnectionState(profile); + + switch (connectionStatus) { + case BluetoothProfile.STATE_CONNECTING: + case BluetoothProfile.STATE_DISCONNECTING: + return mContext.getString( + BluetoothUtils.getConnectionStateSummary(connectionStatus)); + + case BluetoothProfile.STATE_CONNECTED: + profileConnected = true; + break; + + case BluetoothProfile.STATE_DISCONNECTED: + if (profile.isProfileReady()) { + if (profile instanceof A2dpProfile + || profile instanceof A2dpSinkProfile) { + a2dpNotConnected = true; + } else if (profile instanceof HeadsetProfile + || profile instanceof HfpClientProfile) { + hfpNotConnected = true; + } else if (profile instanceof HearingAidProfile) { + hearingAidNotConnected = true; + } } - } - break; + break; + } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index f7f65893efb5..3a6283812e0c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -50,7 +50,7 @@ public class CachedBluetoothDeviceManager { } public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() { - return new ArrayList<CachedBluetoothDevice>(mCachedDevices); + return new ArrayList<>(mCachedDevices); } public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 86928fc07cc2..4f81dafe7305 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -154,8 +154,10 @@ public class AccessPoint implements Comparable<AccessPoint> { static final String KEY_CARRIER_NAME = "key_carrier_name"; static final AtomicInteger sLastId = new AtomicInteger(0); - /** - * These values are matched in string arrays -- changes must be kept in sync + /* + * NOTE: These constants for security and PSK types are saved to the bundle in saveWifiState, + * and sent across IPC. The numeric values should remain stable, otherwise the changes will need + * to be synced with other unbundled users of this library. */ public static final int SECURITY_NONE = 0; public static final int SECURITY_WEP = 1; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java index ede248b85083..8757eed8b746 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java @@ -55,6 +55,8 @@ public class SettingsLibRobolectricTestRunner extends RobolectricTestRunner { paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/AppPreference/res")); paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/HelpUtils/res")); paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/RestrictedLockUtils/res")); + paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/" + + "SettingsLayoutPreference/res")); paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/res")); paths.add(resourcePath("file:frameworks/base/core/res/res")); paths.add(resourcePath("file:out/soong/.intermediates/prebuilts/sdk/current/androidx/androidx.appcompat_appcompat-nodeps/android_common/aar/res/")); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java new file mode 100644 index 000000000000..427a611d61da --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.widget; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.view.LayoutInflater; + +import androidx.preference.Preference.OnPreferenceClickListener; +import androidx.preference.PreferenceViewHolder; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class LayoutPreferenceTest { + + private LayoutPreference mPreference; + private PreferenceViewHolder mHolder; + + @Before + public void setUp() { + final Context mContext = RuntimeEnvironment.application; + mPreference = new LayoutPreference(mContext, R.layout.settings_entity_header); + mHolder = PreferenceViewHolder.createInstanceForTests(LayoutInflater.from(mContext) + .inflate(R.layout.layout_preference_frame, null, false)); + } + + @Test + public void setOnPreferenceClickListener_layoutPreferenceShouldListenClickEvent() { + final OnPreferenceClickListener listener = mock(OnPreferenceClickListener.class); + + mPreference.setOnPreferenceClickListener(listener); + mPreference.onBindViewHolder(mHolder); + + mHolder.itemView.callOnClick(); + + verify(listener).onPreferenceClick(mPreference); + assertThat(mHolder.itemView.isFocusable()).isTrue(); + assertThat(mHolder.itemView.isClickable()).isTrue(); + } + + @Test + public void setNonSelectable_viewShouldNotBeSelectable() { + mPreference.setSelectable(false); + mPreference.onBindViewHolder(mHolder); + + assertThat(mHolder.itemView.isFocusable()).isFalse(); + assertThat(mHolder.itemView.isClickable()).isFalse(); + } + + @Test + public void disableSomeView_shouldMaintainStateAfterBind() { + mPreference.findViewById(android.R.id.button1).setEnabled(false); + mPreference.findViewById(android.R.id.button2).setEnabled(true); + + mPreference.onBindViewHolder(mHolder); + + assertThat(mPreference.findViewById(android.R.id.button1).isEnabled()).isFalse(); + assertThat(mPreference.findViewById(android.R.id.button2).isEnabled()).isTrue(); + } + + @Test + public void allowDividerBelow_shouldSaveCorrectDividerStatus() { + mPreference.setAllowDividerBelow(true); + + assertThat(mPreference.isAllowDividerBelow()).isTrue(); + } +} diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index cbb6e82c8f86..b2c12b277dc0 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -855,6 +855,10 @@ class SettingsProtoDumpUtil { GlobalSettingsProto.MultiSim.SMS_PROMPT); p.end(multiSimToken); + dumpSetting(s, p, + Global.NATIVE_FLAGS_HEALTH_CHECK_ENABLED, + GlobalSettingsProto.NATIVE_FLAGS_HEALTH_CHECK_ENABLED); + final long netstatsToken = p.start(GlobalSettingsProto.NETSTATS); dumpSetting(s, p, Settings.Global.NETSTATS_ENABLED, diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SystemServicesProxy.java index f8b61cd6b286..44354bc1d358 100644 --- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -302,11 +302,13 @@ public class SystemServicesProxy { } /** - * Returns whether there is a soft nav bar. + * Returns whether there is a soft nav bar on specified display. + * + * @param displayId the id of display to check if there is a software navigation bar. */ - public boolean hasSoftNavigationBar() { + public boolean hasSoftNavigationBar(int displayId) { try { - return mIwm.hasNavigationBar(); + return mIwm.hasNavigationBar(displayId); } catch (RemoteException e) { e.printStackTrace(); } diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java index dfa38babd63b..8723fb9ea7c8 100644 --- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java @@ -631,7 +631,8 @@ public class RecentsView extends FrameLayout { } }; WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture( - future, animStartedListener, getHandler(), true /* scaleUp */); + future, animStartedListener, getHandler(), true /* scaleUp */, + getContext().getDisplayId()); MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP, event.task.getTopComponent().flattenToShortString()); } else { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java index ba4eb5f48528..88b8dd8e2d0b 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java @@ -52,7 +52,9 @@ public interface SensorManagerPlugin extends Plugin { } class Sensor { - public static int TYPE_WAKE_LOCK_SCREEN = 1; + public static final int TYPE_WAKE_LOCK_SCREEN = 1; + public static final int TYPE_WAKE_DISPLAY = 2; + public static final int TYPE_SWIPE = 3; int mType; @@ -68,6 +70,7 @@ public interface SensorManagerPlugin extends Plugin { class TriggerEvent { Sensor mSensor; int mVendorType; + float[] mValues; /** * Creates a trigger event @@ -76,14 +79,30 @@ public interface SensorManagerPlugin extends Plugin { * e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc. */ public TriggerEvent(Sensor sensor, int vendorType) { + this(sensor, vendorType, null); + } + + /** + * Creates a trigger event + * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN + * @param vendorType The vendor type, which should be unique for each type of sensor, + * e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc. + * @param values Values captured by the sensor. + */ + public TriggerEvent(Sensor sensor, int vendorType, float[] values) { mSensor = sensor; mVendorType = vendorType; + mValues = values; } public Sensor getSensor() { return mSensor; } + public float[] getValues() { + return mValues; + } + public int getVendorType() { return mVendorType; } diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml index 2f7d486a1372..bc15f2c46b47 100644 --- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml +++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml @@ -26,9 +26,7 @@ android:id="@+id/dialog_container" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:padding="@dimen/ongoing_appops_dialog_content_padding"> - + android:orientation="vertical" > <TextView android:id="@+id/title" android:layout_width="match_parent" @@ -37,21 +35,29 @@ android:textDirection="locale" android:textAppearance="@style/TextAppearance.AppOpsDialog.Title" android:textColor="@*android:color/text_color_primary" - android:paddingStart="@dimen/ongoing_appops_dialog_title_padding" - android:paddingEnd="@dimen/ongoing_appops_dialog_title_padding" - android:paddingBottom="@dimen/ongoing_appops_dialog_sep" + android:layout_marginStart="@dimen/ongoing_appops_dialog_title_margin_sides" + android:layout_marginEnd="@dimen/ongoing_appops_dialog_title_margin_sides" + android:layout_marginBottom="@dimen/ongoing_appops_dialog_title_margin_top_bottom" + android:layout_marginTop="@dimen/ongoing_appops_dialog_title_margin_top_bottom" /> <LinearLayout - android:id="@+id/items_container" + android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:gravity="start" - /> + android:layout_marginBottom="@dimen/ongoing_appops_dialog_items_bottom_margin" > + + <LinearLayout + android:id="@+id/items_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="start" + /> - <include android:id="@+id/overflow" layout="@layout/ongoing_privacy_dialog_item" - android:visibility="gone" /> + <include android:id="@+id/overflow" layout="@layout/ongoing_privacy_dialog_item" + android:visibility="gone" /> + </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml index f05f7bad36ba..ecfbfb434800 100644 --- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml +++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml @@ -17,37 +17,39 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="@dimen/ongoing_appops_dialog_line_height" + android:layout_marginStart="@dimen/ongoing_appops_dialog_text_padding" + android:layout_marginEnd="@dimen/ongoing_appops_dialog_text_padding" android:fillViewport="true" android:orientation="horizontal" - android:layout_marginTop="@dimen/ongoing_appops_dialog_text_margin" - android:focusable="true" > + android:focusable="true" + android:layout_gravity="center_vertical"> <ImageView android:id="@+id/app_icon" - android:layout_height="@dimen/ongoing_appops_dialog_icon_height" - android:layout_width="@dimen/ongoing_appops_dialog_icon_height" + android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size" + android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size" + android:layout_gravity="start|center_vertical" /> <TextView android:id="@+id/app_name" - android:layout_height="@dimen/ongoing_appops_dialog_icon_height" + android:layout_height="match_parent" android:layout_width="0dp" android:layout_weight="1" - android:gravity="bottom|start" + android:gravity="start|center_vertical" android:textDirection="locale" android:textAppearance="@style/TextAppearance.AppOpsDialog.Item" android:textColor="@*android:color/text_color_primary" - android:paddingStart="@dimen/ongoing_appops_dialog_text_padding" - android:paddingEnd="@dimen/ongoing_appops_dialog_text_padding" - + android:layout_marginStart="@dimen/ongoing_appops_dialog_text_padding" /> <LinearLayout android:id="@+id/icons" - android:layout_height="@dimen/ongoing_appops_dialog_icon_height" + android:layout_height="match_parent" android:layout_width="wrap_content" android:gravity="end" + android:layout_gravity="end|center_vertical" android:visibility="gone" /> </LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index d8648fa01d25..9e97cd8f4099 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -464,4 +464,6 @@ <string-array name="config_pluginWhitelist" translatable="false"> <item>com.android.systemui</item> </string-array> + + <integer name="ongoing_appops_dialog_max_apps">5</integer> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 0997c5b106ce..b0a519c00943 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -945,14 +945,20 @@ <dimen name="ongoing_appops_dialog_sep">16dp</dimen> <!--Padding around text items in Ongoing App Ops dialog --> <dimen name="ongoing_appops_dialog_text_padding">16dp</dimen> - <!-- Height of icons in Ongoing App Ops dialog. Both App Op icon and application icon --> - <dimen name="ongoing_appops_dialog_icon_height">28dp</dimen> - <!-- Margin between text lines in Ongoing App Ops dialog --> - <dimen name="ongoing_appops_dialog_text_margin">15dp</dimen> - <!-- Side padding of title in Ongoing App Ops dialog --> - <dimen name="ongoing_appops_dialog_title_padding">10dp</dimen> - <!-- Padding around Ongoing App Ops dialog content --> - <dimen name="ongoing_appops_dialog_content_padding">24dp</dimen> + <!-- Height and width of App Opp icons in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_icon_size">24dp</dimen> + <!-- Left margin of App Opp icons in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen> + <!-- Height and width of Application icons in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen> + <!-- Height of line in Ongoing App Ops dialog--> + <dimen name="ongoing_appops_dialog_line_height">48dp</dimen> + <!-- Side margin of title in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_title_margin_sides">24dp</dimen> + <!-- Bottom margin of items in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_items_bottom_margin">24dp</dimen> + <!-- Top and bottom margin of title in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_title_margin_top_bottom">18dp</dimen> <!-- Side margins around the Ongoing App Ops chip--> <dimen name="ongoing_appops_chip_margin">12dp</dimen> <!-- Top and bottom margins around the Ongoing App Ops chip --> @@ -968,9 +974,9 @@ <!-- Radius of Ongoing App Ops chip corners --> <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen> <!-- Text size for Ongoing App Ops dialog title --> - <dimen name="ongoing_appops_dialog_title_size">24sp</dimen> + <dimen name="ongoing_appops_dialog_title_size">20sp</dimen> <!-- Text size for Ongoing App Ops dialog items --> - <dimen name="ongoing_appops_dialog_item_size">20sp</dimen> + <dimen name="ongoing_appops_dialog_item_size">16sp</dimen> <!-- How much a bubble is elevated --> <dimen name="bubble_elevation">8dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 31dd46cd1af0..c5654f01e5fc 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2254,7 +2254,10 @@ <string name="heap_dump_tile_name">Dump SysUI Heap</string> <!-- Text on chip for multiple apps using a single app op [CHAR LIMIT=10] --> - <string name="ongoing_privacy_chip_multiple_apps"><xliff:g id="num_apps" example="3">%d</xliff:g> apps</string> + <plurals name="ongoing_privacy_chip_multiple_apps"> + <item quantity="few"><xliff:g id="num_apps" example="3">%d</xliff:g> apps</item> + <item quantity="other"><xliff:g id="num_apps" example="3">%d</xliff:g> apps</item> + </plurals> <!-- Content description for ongoing privacy chip. Use with a single app [CHAR LIMIT=NONE]--> <string name="ongoing_privacy_chip_content_single_app"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="types_list" example="camera, location">%2$s</xliff:g>.</string> @@ -2263,12 +2266,15 @@ <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string> <!-- Content description for ongoing privacy chip. Use with multiple apps using same app op[CHAR LIMIT=NONE]--> - <string name="ongoing_privacy_chip_content_multiple_apps_single_op"><xliff:g id="num_apps" example="3">%1$d</xliff:g> applications are using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</string> + <plurals name="ongoing_privacy_chip_content_multiple_apps_single_op"> + <item quantity="few"><xliff:g id="num_apps" example="3">%1$d</xliff:g> applications are using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item> + <item quantity="other"><xliff:g id="num_apps" example="3">%1$d</xliff:g> applications are using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item> + </plurals> <!-- Action on Ongoing Privacy Dialog to dismiss [CHAR LIMIT=10]--> <string name="ongoing_privacy_dialog_cancel">Cancel</string> - <!-- Action on Ongoing Privacy Dialog to open privacy hub [CHAR LIMIT=15]--> + <!-- Action on Ongoing Privacy Dialog to open privacy hub [CHAR LIMIT=20]--> <string name="ongoing_privacy_dialog_open_settings">View details</string> <!-- Text for item in Ongoing Privacy Dialog title when only one app is using app ops [CHAR LIMIT=NONE] --> @@ -2295,6 +2301,6 @@ <!-- Text for indicating extra apps using app ops [CHAR LIMIT=NONE] --> <plurals name="ongoing_privacy_dialog_overflow_text"> <item quantity="one"><xliff:g id="num_apps" example="1">%d</xliff:g> other app</item> - <item quantity="other"><xliff:g id="num_apps" example="3">%d</xliff:g> other app</item> + <item quantity="other"><xliff:g id="num_apps" example="3">%d</xliff:g> other apps</item> </plurals> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index e9aa1b65f48a..fede934d7369 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -262,7 +262,7 @@ <style name="TextAppearance.AppOpsDialog.Item"> <item name="android:textSize">@dimen/ongoing_appops_dialog_item_size</item> - <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:fontFamily">sans-serif</item> </style> <style name="BaseBrightnessDialogContainer" parent="@style/Theme.SystemUI"> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index 42e60aa7908b..ff9e84ca29c1 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -100,23 +100,23 @@ public class WindowManagerWrapper { * Overrides a pending app transition. */ public void overridePendingAppTransitionMultiThumbFuture( - AppTransitionAnimationSpecsFuture animationSpecFuture, - Runnable animStartedCallback, Handler animStartedCallbackHandler, boolean scaleUp) { + AppTransitionAnimationSpecsFuture animationSpecFuture, Runnable animStartedCallback, + Handler animStartedCallbackHandler, boolean scaleUp, int displayId) { try { WindowManagerGlobal.getWindowManagerService() .overridePendingAppTransitionMultiThumbFuture(animationSpecFuture.getFuture(), RecentsTransition.wrapStartedListener(animStartedCallbackHandler, - animStartedCallback), scaleUp); + animStartedCallback), scaleUp, displayId); } catch (RemoteException e) { Log.w(TAG, "Failed to override pending app transition (multi-thumbnail future): ", e); } } public void overridePendingAppTransitionRemote( - RemoteAnimationAdapterCompat remoteAnimationAdapter) { + RemoteAnimationAdapterCompat remoteAnimationAdapter, int displayId) { try { WindowManagerGlobal.getWindowManagerService().overridePendingAppTransitionRemote( - remoteAnimationAdapter.getWrapped()); + remoteAnimationAdapter.getWrapped(), displayId); } catch (RemoteException e) { Log.w(TAG, "Failed to override pending app transition (remote): ", e); } @@ -159,11 +159,13 @@ public class WindowManagerWrapper { } /** - * @return whether there is a soft nav bar. + * @param displayId the id of display to check if there is a software navigation bar. + * + * @return whether there is a soft nav bar on specific display. */ - public boolean hasSoftNavigationBar() { + public boolean hasSoftNavigationBar(int displayId) { try { - return WindowManagerGlobal.getWindowManagerService().hasNavigationBar(); + return WindowManagerGlobal.getWindowManagerService().hasNavigationBar(displayId); } catch (RemoteException e) { return false; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 6b0a7a95bba3..b55aa5c8897d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1531,10 +1531,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } mHandler.removeCallbacks(mRetryFingerprintAuthentication); boolean shouldListenForFingerprint = shouldListenForFingerprint(); - if (mFingerprintRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFingerprint) { + boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING + || mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING; + if (runningOrRestarting && !shouldListenForFingerprint) { stopListeningForFingerprint(); - } else if (mFingerprintRunningState != BIOMETRIC_STATE_RUNNING - && shouldListenForFingerprint) { + } else if (!runningOrRestarting && shouldListenForFingerprint) { startListeningForFingerprint(); } } @@ -1589,6 +1590,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING); return; } + if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) { + // Waiting for restart via handleFingerprintError(). + return; + } if (DEBUG) Log.v(TAG, "startListeningForFingerprint()"); int userId = ActivityManager.getCurrentUser(); if (isUnlockWithFingerprintPossible(userId)) { @@ -2418,6 +2423,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { + getStrongAuthTracker().hasUserAuthenticatedSinceBoot()); pw.println(" disabled(DPM)=" + isFingerprintDisabled(userId)); pw.println(" possible=" + isUnlockWithFingerprintPossible(userId)); + pw.println(" listening: actual=" + mFingerprintRunningState + + " expected=" + (shouldListenForFingerprint() ? 1 : 0)); pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags)); pw.println(" trustManaged=" + getUserTrustIsManaged(userId)); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index e868f96426c9..c6dcfc7356be 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -268,7 +268,7 @@ public class BubbleController { for (BubbleView bv : mBubbles.values()) { NotificationData.Entry entry = bv.getEntry(); if (entry != null) { - if (entry.row.isRemoved() || entry.isBubbleDismissed() || entry.row.isDismissed()) { + if (entry.isRowRemoved() || entry.isBubbleDismissed() || entry.isRowDismissed()) { viewsToRemove.add(bv); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index a79e04736337..6c47aac712f6 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -120,7 +120,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float * @return the view to display when the bubble is expanded. */ public ExpandableNotificationRow getRowView() { - return mEntry.row; + return mEntry.getRow(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 21b21d9f5527..eda3c5951754 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -177,9 +177,22 @@ public class DozeLog { log("state " + state); } - public static void traceWakeLockScreenWakeUp() { + /** + * Appends lock screen wake up event to the logs. + * @param wake if we're waking up or sleeping. + */ + public static void traceLockScreenWakeUp(boolean wake) { if (!ENABLED) return; - log("wakeLockScreenWakeUp"); + log("wakeLockScreenWakeUp " + wake); + } + + /** + * Appends wake-display event to the logs. + * @param wake if we're waking up or sleeping. + */ + public static void traceWakeDisplay(boolean wake) { + if (!ENABLED) return; + log("wakeLockScreenWakeUp " + wake); } public static void traceProximityResult(Context context, boolean near, long millis, diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 77f7ad4f3a9e..bf8e04db976b 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -16,6 +16,7 @@ package com.android.systemui.doze; +import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY; import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN; import android.annotation.AnyThread; @@ -67,7 +68,6 @@ public class DozeSensors { private final AmbientDisplayConfiguration mConfig; private final WakeLock mWakeLock; private final Consumer<Boolean> mProxCallback; - private final Consumer<Boolean> mWakeScreenCallback; private final Callback mCallback; private final Handler mHandler = new Handler(); @@ -76,8 +76,7 @@ public class DozeSensors { public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, - Callback callback, Consumer<Boolean> proxCallback, - Consumer<Boolean> wakeScreenCallback, AlwaysOnDisplayPolicy policy) { + Callback callback, Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy) { mContext = context; mAlarmManager = alarmManager; mSensorManager = sensorManager; @@ -85,7 +84,6 @@ public class DozeSensors { mConfig = config; mWakeLock = wakeLock; mProxCallback = proxCallback; - mWakeScreenCallback = wakeScreenCallback; mResolver = mContext.getContentResolver(); mSensors = new TriggerSensor[] { @@ -123,7 +121,13 @@ public class DozeSensors { DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, false /* reports touch coordinates */, false /* touchscreen */), - new WakeScreenSensor(), + new PluginTriggerSensor( + new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY), + Settings.Secure.DOZE_WAKE_SCREEN_GESTURE, + true /* configured */, + DozeLog.REASON_SENSOR_WAKE_UP, + false /* reports touch coordinates */, + false /* touchscreen */), }; mProxSensor = new ProxSensor(policy); @@ -395,7 +399,8 @@ public class DozeSensors { screenX = event.values[0]; screenY = event.values[1]; } - mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY); + mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY, + event.values); updateListener(); // reregister, this sensor only fires once })); } @@ -429,7 +434,14 @@ public class DozeSensors { private final SensorManagerPlugin.Sensor mPluginSensor; private final SensorManagerPlugin.TriggerEventListener mTriggerEventListener = (event) -> { - onTrigger(null); + DozeLog.traceSensor(mContext, mPulseReason); + mHandler.post(mWakeLock.wrap(() -> { + if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event)); + mRegistered = false; + mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1, + event.getValues()); + updateListener(); // reregister, this sensor only fires once + })); }; PluginTriggerSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, @@ -463,28 +475,19 @@ public class DozeSensors { .append(", mSensor=").append(mPluginSensor).append("}").toString(); } - } - - private class WakeScreenSensor extends TriggerSensor { - - WakeScreenSensor() { - super(findSensorWithType(mConfig.wakeScreenSensorType()), - Settings.Secure.DOZE_WAKE_SCREEN_GESTURE, true /* configured */, - DozeLog.REASON_SENSOR_WAKE_UP, false /* reportsTouchCoordinates */, - false /* requiresTouchscreen */); + private String triggerEventToString(SensorManagerPlugin.TriggerEvent event) { + if (event == null) return null; + final StringBuilder sb = new StringBuilder("PluginTriggerEvent[") + .append(event.getSensor()).append(',') + .append(event.getVendorType()); + if (event.getValues() != null) { + for (int i = 0; i < event.getValues().length; i++) { + sb.append(',').append(event.getValues()[i]); + } + } + return sb.append(']').toString(); } - @Override - @AnyThread - public void onTrigger(TriggerEvent event) { - DozeLog.traceSensor(mContext, mPulseReason); - mHandler.post(mWakeLock.wrap(() -> { - if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event)); - mRegistered = false; - mWakeScreenCallback.accept(event.values[0] > 0); - updateListener(); // reregister, this sensor only fires once - })); - } } public interface Callback { @@ -494,11 +497,11 @@ public class DozeSensors { * @param pulseReason Requesting sensor, e.g. {@link DozeLog#PULSE_REASON_SENSOR_PICKUP} * @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity. * @param screenX the location on the screen where the sensor fired or -1 - * if the sensor doesn't support reporting screen locations. + * if the sensor doesn't support reporting screen locations. * @param screenY the location on the screen where the sensor fired or -1 - * if the sensor doesn't support reporting screen locations. + * @param rawValues raw values array from the event. */ void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck, - float screenX, float screenY); + float screenX, float screenY, float[] rawValues); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index d69b1bfa64c3..bad01480d677 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -84,7 +84,7 @@ public class DozeTriggers implements DozeMachine.Part { mWakeLock = wakeLock; mAllowPulseTriggers = allowPulseTriggers; mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters, - config, wakeLock, this::onSensor, this::onProximityFar, this::onWakeScreen, + config, wakeLock, this::onSensor, this::onProximityFar, dozeParameters.getPolicy()); mUiModeManager = mContext.getSystemService(UiModeManager.class); } @@ -124,13 +124,17 @@ public class DozeTriggers implements DozeMachine.Part { } private void onSensor(int pulseReason, boolean sensorPerformedProxCheck, - float screenX, float screenY) { + float screenX, float screenY, float[] rawValues) { boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP; boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP; boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; + boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP; + boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0; - if (isLongPress) { + if (isWakeDisplay) { + onWakeScreen(wakeEvent); + } else if (isLongPress) { requestPulse(pulseReason, sensorPerformedProxCheck); } else { proximityCheckThenCall((result) -> { @@ -141,7 +145,15 @@ public class DozeTriggers implements DozeMachine.Part { if (isDoubleTap) { mDozeHost.onDoubleTap(screenX, screenY); mMachine.wakeUp(); - } else if (isPickup || isWakeLockScreen) { + } else if (isWakeLockScreen) { + if (wakeEvent) { + mDozeHost.setPassiveInterrupt(true); + mMachine.wakeUp(); + DozeLog.traceLockScreenWakeUp(wakeEvent); + } else { + if (DEBUG) Log.d(TAG, "Unpulsing"); + } + } else if (isPickup) { mDozeHost.setPassiveInterrupt(true); mMachine.wakeUp(); } else { @@ -157,8 +169,6 @@ public class DozeTriggers implements DozeMachine.Part { final boolean withinVibrationThreshold = timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold); - } else if (isWakeLockScreen) { - DozeLog.traceWakeLockScreenWakeUp(); } } @@ -184,6 +194,7 @@ public class DozeTriggers implements DozeMachine.Part { } private void onWakeScreen(boolean wake) { + DozeLog.traceWakeDisplay(wake); DozeMachine.State state = mMachine.getState(); boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED); boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index e78951ab5ad1..201c7e69beaf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -18,7 +18,6 @@ package com.android.systemui.keyguard; import android.app.ActivityManager; import android.app.AlarmManager; -import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -175,7 +174,7 @@ public class KeyguardSliceProvider extends SliceProvider implements * @param builder The slice builder. */ protected void addZenMode(ListBuilder builder) { - if (!isDndSuppressingNotifications()) { + if (!isDndOn()) { return; } RowBuilder dndBuilder = new RowBuilder(mDndUri) @@ -187,13 +186,10 @@ public class KeyguardSliceProvider extends SliceProvider implements } /** - * Return true if DND is enabled suppressing notifications. + * Return true if DND is enabled. */ - protected boolean isDndSuppressingNotifications() { - boolean suppressingNotifications = (mZenModeController.getConfig().suppressedVisualEffects - & NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0; - return mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF - && suppressingNotifications; + protected boolean isDndOn() { + return mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 5d33ffdb30af..f0543454073d 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -411,13 +411,8 @@ public class PowerUI extends SystemUI { setNextLogTime(); - // This initialization method may be called on a configuration change. Only one set of - // ongoing callbacks should be occurring, so remove any now. updateTemperatureWarning will - // schedule an ongoing callback. - mHandler.removeCallbacks(mUpdateTempCallback); - // We have passed all of the checks, start checking the temp - updateTemperatureWarning(); + mHandler.post(mUpdateTempCallback); } private void showThermalShutdownDialog() { @@ -448,6 +443,8 @@ public class PowerUI extends SystemUI { logTemperatureStats(); + // Remove any pending callbacks as we only want to enable one + mHandler.removeCallbacks(mUpdateTempCallback); mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL); } @@ -553,11 +550,7 @@ public class PowerUI extends SystemUI { // Thermal event received from vendor thermal management subsystem private final class ThermalEventListener extends IThermalEventListener.Stub { @Override public void notifyThrottling(Temperature temp) { - // Trigger an update of the temperature warning. Only one - // callback can be enabled at a time, so remove any existing - // callback; updateTemperatureWarning will schedule another one. - mHandler.removeCallbacks(mUpdateTempCallback); - updateTemperatureWarning(); + mHandler.post(mUpdateTempCallback); } } } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt index d3715d04b7bc..65ed889f34e1 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -78,8 +78,9 @@ class OngoingPrivacyChip @JvmOverloads constructor( if (builder.app != null) { text.setText(builder.app?.applicationName) } else { - text.text = context.getString(R.string.ongoing_privacy_chip_multiple_apps, - builder.appsAndTypes.size) + text.text = context.resources.getQuantityString( + R.plurals.ongoing_privacy_chip_multiple_apps, + builder.appsAndTypes.size, builder.appsAndTypes.size) } } } else { @@ -100,9 +101,9 @@ class OngoingPrivacyChip @JvmOverloads constructor( context.getString(R.string.ongoing_privacy_chip_content_single_app, builder.app?.applicationName, typesText) } else { - contentDescription = context.getString( - R.string.ongoing_privacy_chip_content_multiple_apps_single_op, - builder.appsAndTypes.size, typesText) + contentDescription = context.resources.getQuantityString( + R.plurals.ongoing_privacy_chip_content_multiple_apps_single_op, + builder.appsAndTypes.size, builder.appsAndTypes.size, typesText) } } } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt index f6a95af4a075..bbdae291d81e 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.DialogInterface import android.content.Intent import android.content.res.ColorStateList +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.widget.ImageView @@ -34,13 +35,13 @@ class OngoingPrivacyDialog constructor( val dialogBuilder: PrivacyDialogBuilder ) { - val iconSize = context.resources.getDimensionPixelSize( - R.dimen.ongoing_appops_dialog_icon_height) - val iconColor = context.resources.getColor( + private val iconSize = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_dialog_icon_size) + private val iconColor = context.resources.getColor( com.android.internal.R.color.text_color_primary, context.theme) - companion object { - private const val MAX_ITEMS = 10 - } + private val iconMargin = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_dialog_icon_margin) + private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps) fun createDialog(): Dialog { val builder = AlertDialog.Builder(context).apply { @@ -105,6 +106,11 @@ class OngoingPrivacyDialog constructor( val appName = item.findViewById(R.id.app_name) as TextView val icons = item.findViewById(R.id.icons) as LinearLayout + var lp = LinearLayout.LayoutParams(iconSize, iconSize).apply { + gravity = Gravity.CENTER_VERTICAL + marginStart = iconMargin + } + app.icon?.let { appIcon.setImageDrawable(it) } @@ -117,7 +123,7 @@ class OngoingPrivacyDialog constructor( imageTintList = ColorStateList.valueOf(iconColor) setImageDrawable(it) } - icons.addView(image, iconSize, LinearLayout.LayoutParams.WRAP_CONTENT) + icons.addView(image, lp) } icons.visibility = View.VISIBLE } else { diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt index 3fa3e8eec0ab..268462ea526e 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt @@ -18,10 +18,14 @@ package com.android.systemui.privacy import android.app.ActivityManager import android.app.AppOpsManager +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.os.Handler import android.os.UserHandle import android.os.UserManager +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.Dependency import com.android.systemui.appops.AppOpItem import com.android.systemui.appops.AppOpsController @@ -33,25 +37,29 @@ class PrivacyItemController(val context: Context, val callback: Callback) { AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_FINE_LOCATION) + val intents = listOf(Intent.ACTION_USER_FOREGROUND, + Intent.ACTION_MANAGED_PROFILE_ADDED, + Intent.ACTION_MANAGED_PROFILE_REMOVED) + const val TAG = "PrivacyItemController" } private var privacyList = emptyList<PrivacyItem>() private val appOpsController = Dependency.get(AppOpsController::class.java) private val userManager = context.getSystemService(UserManager::class.java) - private val currentUser = ActivityManager.getCurrentUser() - private val currentUserIds = userManager.getProfiles(currentUser).map { it.id } + private var currentUserIds = emptyList<Int>() private val bgHandler = Handler(Dependency.get(Dependency.BG_LOOPER)) private val uiHandler = Dependency.get(Dependency.MAIN_HANDLER) + private var listening = false + private val notifyChanges = Runnable { callback.privacyChanged(privacyList) } + private val updateListAndNotifyChanges = Runnable { updatePrivacyList() uiHandler.post(notifyChanges) } - private var listening = false - private val cb = object : AppOpsController.Callback { override fun onActiveStateChanged( code: Int, @@ -61,12 +69,36 @@ class PrivacyItemController(val context: Context, val callback: Callback) { ) { val userId = UserHandle.getUserId(uid) if (userId in currentUserIds) { - update() + update(false) } } } - private fun update() { + @VisibleForTesting + internal var userSwitcherReceiver = Receiver() + set(value) { + context.unregisterReceiver(field) + field = value + registerReceiver() + } + + init { + registerReceiver() + } + + private fun registerReceiver() { + context.registerReceiverAsUser(userSwitcherReceiver, UserHandle.ALL, IntentFilter().apply { + intents.forEach { + addAction(it) + } + }, null, null) + } + + private fun update(updateUsers: Boolean) { + if (updateUsers) { + val currentUser = ActivityManager.getCurrentUser() + currentUserIds = userManager.getProfiles(currentUser).map { it.id } + } bgHandler.post(updateListAndNotifyChanges) } @@ -75,7 +107,7 @@ class PrivacyItemController(val context: Context, val callback: Callback) { listening = listen if (listening) { appOpsController.addCallback(OPS, cb) - update() + update(true) } else { appOpsController.removeCallback(OPS, cb) } @@ -102,4 +134,12 @@ class PrivacyItemController(val context: Context, val callback: Callback) { interface Callback { fun privacyChanged(privacyItems: List<PrivacyItem>) } + + internal inner class Receiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action in intents) { + update(true) + } + } + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 216b9409521f..f796793d908c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -219,7 +219,7 @@ public class ScreenPinningRequest implements View.OnClickListener { mLayout.findViewById(R.id.screen_pinning_text_area) .setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE); View buttons = mLayout.findViewById(R.id.screen_pinning_buttons); - if (WindowManagerWrapper.getInstance().hasSoftNavigationBar()) { + if (WindowManagerWrapper.getInstance().hasSoftNavigationBar(mContext.getDisplayId())) { buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE); swapChildrenIfRtlAndVertical(buttons); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java index 3da6d2e877ed..bc381699494a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java @@ -112,8 +112,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim return; } - alertEntry.mEntry.row.sendAccessibilityEvent( - AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + alertEntry.mEntry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); if (alert) { alertEntry.updateEntry(true /* updatePostTime */); } @@ -186,7 +185,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim alertEntry.setEntry(entry); mAlertEntries.put(entry.key, alertEntry); onAlertEntryAdded(alertEntry); - entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); } /** @@ -207,7 +206,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim Entry entry = alertEntry.mEntry; mAlertEntries.remove(key); onAlertEntryRemoved(alertEntry); - entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); alertEntry.reset(); if (mExtendedLifetimeAlertEntries.contains(entry)) { if (mNotificationLifetimeFinishedCallback != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java index f1c03049202f..a5e7f04be281 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java @@ -79,7 +79,7 @@ public final class AmbientPulseManager extends AlertingNotificationManager { @Override protected void onAlertEntryAdded(AlertEntry alertEntry) { NotificationData.Entry entry = alertEntry.mEntry; - entry.row.setAmbientPulsing(true); + entry.setAmbientPulsing(true); for (OnAmbientChangedListener listener : mListeners) { listener.onAmbientStateChanged(entry, true); } @@ -88,11 +88,11 @@ public final class AmbientPulseManager extends AlertingNotificationManager { @Override protected void onAlertEntryRemoved(AlertEntry alertEntry) { NotificationData.Entry entry = alertEntry.mEntry; - entry.row.setAmbientPulsing(false); + entry.setAmbientPulsing(false); for (OnAmbientChangedListener listener : mListeners) { listener.onAmbientStateChanged(entry, false); } - entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT); + entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java index 3b611a3199d6..2f2610998b35 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java @@ -22,8 +22,11 @@ import android.content.Context; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Handler; +import android.os.RemoteException; +import android.util.Log; import android.util.SparseArray; import android.view.Display; +import android.view.IWindowManager; import android.view.View; import android.view.WindowManagerGlobal; @@ -34,6 +37,8 @@ import com.android.systemui.statusbar.phone.NavigationBarFragment; */ public class DisplayNavigationBarController implements DisplayListener { + private static final String TAG = DisplayNavigationBarController.class.getName(); + private final Context mContext; private final Handler mHandler; private final DisplayManager mDisplayManager; @@ -112,14 +117,23 @@ public class DisplayNavigationBarController implements DisplayListener { } final int displayId = display.getDisplayId(); + final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); + + try { + if (!wms.hasNavigationBar(displayId)) { + return; + } + } catch (RemoteException e) { + // Cannot get wms, just return with warning message. + Log.w(TAG, "Cannot get WindowManager."); + return; + } final Context externalDisplayContext = mContext.createDisplayContext(display); - NavigationBarFragment.create(externalDisplayContext, - (tag, fragment) -> { - final NavigationBarFragment navBar = (NavigationBarFragment) fragment; - // TODO(b/115978725): handle external nav bars sysuiVisibility - navBar.setCurrentSysuiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); - mExternalNavigationBarMap.append(displayId, navBar); - } - ); + NavigationBarFragment.create(externalDisplayContext, (tag, fragment) -> { + final NavigationBarFragment navBar = (NavigationBarFragment) fragment; + // TODO(b/115978725): handle external nav bars sysuiVisibility + navBar.setCurrentSysuiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + mExternalNavigationBarMap.append(displayId, navBar); + }); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java index 745b2f95329d..b9684fcb8a01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java @@ -27,7 +27,6 @@ import android.widget.TextView; import com.android.systemui.R; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; -import com.android.systemui.statusbar.notification.stack.StackScrollState; public class EmptyShadeView extends StackScrollerDecorView { @@ -74,7 +73,7 @@ public class EmptyShadeView extends StackScrollerDecorView { } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { + public ExpandableViewState createExpandableViewState() { return new EmptyShadeViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index fc1e94a08478..f0455481b353 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -199,7 +199,7 @@ public class NotificationMediaManager implements Dumpable { for (int i = 0; i < N; i++) { final NotificationData.Entry entry = activeNotifications.get(i); - if (isMediaNotification(entry)) { + if (entry.isMediaNotification()) { final MediaSession.Token token = entry.notification.getNotification().extras.getParcelable( Notification.EXTRA_MEDIA_SESSION); @@ -336,13 +336,6 @@ public class NotificationMediaManager implements Dumpable { return PlaybackState.STATE_NONE; } - private boolean isMediaNotification(NotificationData.Entry entry) { - // TODO: confirm that there's a valid media key - return entry.row.getExpandedContentView() != null - && entry.row.getExpandedContentView().findViewById( - com.android.internal.R.id.media_actions) != null; - } - private void clearCurrentMediaNotificationSession() { mMediaMetadata = null; if (mMediaController != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 8c53cc2a06a4..2ee5443ab3aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -393,7 +393,7 @@ public class NotificationRemoteInputManager implements Dumpable { } public boolean shouldKeepForRemoteInputHistory(NotificationData.Entry entry) { - if (entry.row == null || entry.row.isDismissed()) { + if (entry.isDismissed()) { return false; } if (!FORCE_REMOTE_INPUT_HISTORY) { @@ -403,7 +403,7 @@ public class NotificationRemoteInputManager implements Dumpable { } public boolean shouldKeepForSmartReplyHistory(NotificationData.Entry entry) { - if (entry.row == null || entry.row.isDismissed()) { + if (entry.isDismissed()) { return false; } if (!FORCE_REMOTE_INPUT_HISTORY) { @@ -532,7 +532,7 @@ public class NotificationRemoteInputManager implements Dumpable { // Ensure the entry hasn't already been removed. This can happen if there is an // inflation exception while updating the remote history - if (entry.row == null || entry.row.isRemoved()) { + if (entry.isRemoved()) { return; } @@ -570,7 +570,7 @@ public class NotificationRemoteInputManager implements Dumpable { mEntryManager.updateNotification(newSbn, null); - if (entry.row == null || entry.row.isRemoved()) { + if (entry.isRemoved()) { return; } @@ -593,7 +593,7 @@ public class NotificationRemoteInputManager implements Dumpable { protected class RemoteInputActiveExtender extends RemoteInputExtender { @Override public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) { - if (entry.row == null || entry.row.isDismissed()) { + if (entry.isDismissed()) { return false; } return mRemoteInputController.isRemoteInputActive(entry); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 37cc299b5880..e7b4904a8ba5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -47,7 +47,6 @@ import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; -import com.android.systemui.statusbar.notification.stack.StackScrollState; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.phone.NotificationIconContainer; @@ -68,7 +67,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private boolean mDark; private NotificationIconContainer mShelfIcons; - private ShelfState mShelfState; private int[] mTmp = new int[2]; private boolean mHideBackground; private int mIconAppearTopPadding; @@ -115,7 +113,6 @@ public class NotificationShelf extends ActivatableNotificationView implements setClipChildren(false); setClipToPadding(false); mShelfIcons.setIsStaticLayout(false); - mShelfState = new ShelfState(); setBottomRoundness(1.0f, false /* animate */); initDimens(); } @@ -187,52 +184,53 @@ public class NotificationShelf extends ActivatableNotificationView implements } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { - return mShelfState; + public ExpandableViewState createExpandableViewState() { + return new ShelfState(); } - public void updateState(StackScrollState resultState, - AmbientState ambientState) { - View lastView = ambientState.getLastVisibleBackgroundChild(); + /** Update the state of the shelf. */ + public void updateState(AmbientState ambientState) { + ExpandableView lastView = ambientState.getLastVisibleBackgroundChild(); + ShelfState viewState = (ShelfState) getViewState(); if (mShowNotificationShelf && lastView != null) { float maxShelfEnd = ambientState.getInnerHeight() + ambientState.getTopPadding() + ambientState.getStackTranslation(); - ExpandableViewState lastViewState = resultState.getViewStateForView(lastView); + ExpandableViewState lastViewState = lastView.getViewState(); float viewEnd = lastViewState.yTranslation + lastViewState.height; - mShelfState.copyFrom(lastViewState); - mShelfState.height = getIntrinsicHeight(); + viewState.copyFrom(lastViewState); + viewState.height = getIntrinsicHeight(); - float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height, + float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height, getFullyClosedTranslation()); float darkTranslation = mAmbientState.getDarkTopPadding(); float yRatio = mAmbientState.hasPulsingNotifications() ? 0 : mAmbientState.getDarkAmount(); - mShelfState.yTranslation = MathUtils.lerp(awakenTranslation, darkTranslation, yRatio); - mShelfState.zTranslation = ambientState.getBaseZHeight(); + viewState.yTranslation = MathUtils.lerp(awakenTranslation, darkTranslation, yRatio); + viewState.zTranslation = ambientState.getBaseZHeight(); // For the small display size, it's not enough to make the icon not covered by // the top cutout so the denominator add the height of cutout. // Totally, (getIntrinsicHeight() * 2 + mCutoutHeight) should be smaller then // mAmbientState.getTopPadding(). - float openedAmount = (mShelfState.yTranslation - getFullyClosedTranslation()) + float openedAmount = (viewState.yTranslation - getFullyClosedTranslation()) / (getIntrinsicHeight() * 2 + mCutoutHeight); openedAmount = Math.min(1.0f, openedAmount); - mShelfState.openedAmount = openedAmount; - mShelfState.clipTopAmount = 0; - mShelfState.alpha = mAmbientState.hasPulsingNotifications() ? 0 : 1; - mShelfState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0; - mShelfState.hideSensitive = false; - mShelfState.xTranslation = getTranslationX(); + viewState.openedAmount = openedAmount; + viewState.clipTopAmount = 0; + viewState.alpha = mAmbientState.hasPulsingNotifications() ? 0 : 1; + viewState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0; + viewState.hideSensitive = false; + viewState.xTranslation = getTranslationX(); if (mNotGoneIndex != -1) { - mShelfState.notGoneIndex = Math.min(mShelfState.notGoneIndex, mNotGoneIndex); + viewState.notGoneIndex = Math.min(viewState.notGoneIndex, mNotGoneIndex); } - mShelfState.hasItemsInStableShelf = lastViewState.inShelf; - mShelfState.hidden = !mAmbientState.isShadeExpanded() + viewState.hasItemsInStableShelf = lastViewState.inShelf; + viewState.hidden = !mAmbientState.isShadeExpanded() || mAmbientState.isQsCustomizerShowing(); - mShelfState.maxShelfEnd = maxShelfEnd; + viewState.maxShelfEnd = maxShelfEnd; } else { - mShelfState.hidden = true; - mShelfState.location = ExpandableViewState.LOCATION_GONE; - mShelfState.hasItemsInStableShelf = false; + viewState.hidden = true; + viewState.location = ExpandableViewState.LOCATION_GONE; + viewState.hasItemsInStableShelf = false; } } @@ -261,7 +259,7 @@ public class NotificationShelf extends ActivatableNotificationView implements int notGoneIndex = 0; int colorOfViewBeforeLast = NO_COLOR; boolean backgroundForceHidden = false; - if (mHideBackground && !mShelfState.hasItemsInStableShelf) { + if (mHideBackground && !((ShelfState) getViewState()).hasItemsInStableShelf) { backgroundForceHidden = true; } int colorTwoBefore = NO_COLOR; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index ea677363a0ba..daa2fd45b142 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -51,6 +51,7 @@ import java.util.Stack; public class NotificationViewHierarchyManager { private static final String TAG = "NotificationViewHierarchyManager"; + //TODO: change this top <Entry, List<Entry>>? private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap = new HashMap<>(); @@ -140,6 +141,7 @@ public class NotificationViewHierarchyManager { /** * Updates the visual representation of the notifications. */ + //TODO: Rewrite this to focus on Entries, or some other data object instead of views public void updateNotificationViews() { ArrayList<NotificationData.Entry> activeNotifications = mEntryManager.getNotificationData() .getActiveNotifications(); @@ -148,12 +150,12 @@ public class NotificationViewHierarchyManager { final int N = activeNotifications.size(); for (int i = 0; i < N; i++) { NotificationData.Entry ent = activeNotifications.get(i); - if (ent.row.isDismissed() || ent.row.isRemoved()) { + if (ent.isRowDismissed() || ent.isRowRemoved()) { // we don't want to update removed notifications because they could // temporarily become children if they were isolated before. continue; } - ent.row.setStatusBarState(mStatusBarStateListener.getCurrentState()); + ent.getRow().setStatusBarState(mStatusBarStateListener.getCurrentState()); boolean showAsBubble = ent.isBubble() && !ent.isBubbleDismissed() && mStatusBarStateListener.getCurrentState() == SHADE; if (showAsBubble) { @@ -175,20 +177,19 @@ public class NotificationViewHierarchyManager { boolean deviceSensitive = devicePublic && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic( mLockscreenUserManager.getCurrentUserId()); - ent.row.setSensitive(sensitive, deviceSensitive); - ent.row.setNeedsRedaction(needsRedaction); - if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) { - ExpandableNotificationRow summary = mGroupManager.getGroupSummary( - ent.row.getStatusBarNotification()); + ent.getRow().setSensitive(sensitive, deviceSensitive); + ent.getRow().setNeedsRedaction(needsRedaction); + if (mGroupManager.isChildInGroupWithSummary(ent.notification)) { + NotificationData.Entry summary = mGroupManager.getGroupSummary(ent.notification); List<ExpandableNotificationRow> orderedChildren = - mTmpChildOrderMap.get(summary); + mTmpChildOrderMap.get(summary.getRow()); if (orderedChildren == null) { orderedChildren = new ArrayList<>(); - mTmpChildOrderMap.put(summary, orderedChildren); + mTmpChildOrderMap.put(summary.getRow(), orderedChildren); } - orderedChildren.add(ent.row); + orderedChildren.add(ent.getRow()); } else { - toShow.add(ent.row); + toShow.add(ent.getRow()); } } @@ -391,19 +392,19 @@ public class NotificationViewHierarchyManager { && !row.isLowPriority())); } - entry.row.setOnAmbient(getShadeController().isDozing()); + entry.getRow().setOnAmbient(getShadeController().isDozing()); int userId = entry.notification.getUserId(); boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup( - entry.notification) && !entry.row.isRemoved(); + entry.notification) && !entry.isRowRemoved(); boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry .notification); if (!showOnKeyguard) { // min priority notifications should show if their summary is showing if (mGroupManager.isChildInGroupWithSummary(entry.notification)) { - ExpandableNotificationRow summary = mGroupManager.getLogicalGroupSummary( + NotificationData.Entry summary = mGroupManager.getLogicalGroupSummary( entry.notification); if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard( - summary.getStatusBarNotification())) { + summary.notification)) { showOnKeyguard = true; } } @@ -411,16 +412,16 @@ public class NotificationViewHierarchyManager { if (suppressedSummary || mLockscreenUserManager.shouldHideNotifications(userId) || (onKeyguard && !showOnKeyguard)) { - entry.row.setVisibility(View.GONE); + entry.getRow().setVisibility(View.GONE); } else { - boolean wasGone = entry.row.getVisibility() == View.GONE; + boolean wasGone = entry.getRow().getVisibility() == View.GONE; if (wasGone) { - entry.row.setVisibility(View.VISIBLE); + entry.getRow().setVisibility(View.VISIBLE); } - if (!isChildNotification && !entry.row.isRemoved()) { + if (!isChildNotification && !entry.getRow().isRemoved()) { if (wasGone) { // notify the scroller of a child addition - mListContainer.generateAddAnimation(entry.row, + mListContainer.generateAddAnimation(entry.getRow(), !showOnKeyguard /* fromMoreCard */); } visibleNotifications++; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java index 929f43e01c0f..e8abcc2bd80e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java @@ -250,16 +250,16 @@ public class RemoteInputController { // Make a copy because closing the remote inputs will modify mOpen. ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size()); for (int i = mOpen.size() - 1; i >= 0; i--) { - NotificationData.Entry item = mOpen.get(i).first.get(); - if (item != null && item.row != null) { - list.add(item); + NotificationData.Entry entry = mOpen.get(i).first.get(); + if (entry != null && entry.rowExists()) { + list.add(entry); } } for (int i = list.size() - 1; i >= 0; i--) { - NotificationData.Entry item = list.get(i); - if (item.row != null) { - item.row.closeRemoteInput(); + NotificationData.Entry entry = list.get(i); + if (entry.rowExists()) { + entry.closeRemoteInput(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index 758c33a5aabe..37bdc1ce7cb9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -41,12 +41,16 @@ public class SmartReplyController { mCallback = callback; } - public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply) { + /** + * Notifies StatusBarService a smart reply is sent. + */ + public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply, + boolean generatedByAssistant) { mCallback.onSmartReplySent(entry, reply); mSendingKeys.add(entry.key); try { - mBarService.onNotificationSmartReplySent(entry.notification.getKey(), - replyIndex); + mBarService.onNotificationSmartReplySent( + entry.notification.getKey(), replyIndex, reply, generatedByAssistant); } catch (RemoteException e) { // Nothing to do, system going down } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java index da6d977f3f5b..d7680b3523ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java @@ -64,6 +64,9 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationGuts; +import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -106,7 +109,6 @@ public class NotificationData { public int importance; public StatusBarIconView icon; public StatusBarIconView expandedIcon; - public ExpandableNotificationRow row; // the outer expanded view private boolean interruption; public boolean autoRedacted; // whether the redacted notification was generated by us public int targetSdk; @@ -119,6 +121,10 @@ public class NotificationData { public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList(); public CharSequence[] smartReplies = new CharSequence[0]; + private Entry parent; // our parent (if we're in a group) + private ArrayList<Entry> children = new ArrayList<Entry>(); + private ExpandableNotificationRow row; // the outer expanded view + private int mCachedContrastColor = COLOR_INVALID; private int mCachedContrastColorIsFor = COLOR_INVALID; private InflationTask mRunningTask = null; @@ -212,6 +218,24 @@ public class NotificationData { } } + public ExpandableNotificationRow getRow() { + return row; + } + + //TODO: This will go away when we have a way to bind an entry to a row + public void setRow(ExpandableNotificationRow row) { + this.row = row; + } + + @Nullable + public List<Entry> getChildren() { + if (children.size() <= 0) { + return null; + } + + return children; + } + public void notifyFullScreenIntentLaunched() { setInterruption(); lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime(); @@ -409,6 +433,198 @@ public class NotificationData { initializationTime = time; } } + + public void sendAccessibilityEvent(int eventType) { + if (row != null) { + row.sendAccessibilityEvent(eventType); + } + } + + /** + * Used by NotificationMediaManager to determine... things + * @return {@code true} if we are a media notification + */ + public boolean isMediaNotification() { + if (row == null) return false; + + return row.isMediaRow(); + } + + /** + * We are a top level child if our parent is the list of notifications duh + * @return {@code true} if we're a top level notification + */ + public boolean isTopLevelChild() { + return row != null && row.isTopLevelChild(); + } + + public void resetUserExpansion() { + if (row != null) row.resetUserExpansion(); + } + + public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) { + if (row != null) row.freeContentViewWhenSafe(inflationFlag); + } + + public void setAmbientPulsing(boolean pulsing) { + if (row != null) row.setAmbientPulsing(pulsing); + } + + public boolean rowExists() { + return row != null; + } + + public boolean isRowDismissed() { + return row != null && row.isDismissed(); + } + + public boolean isRowRemoved() { + return row != null && row.isRemoved(); + } + + /** + * @return {@code true} if the row is null or removed + */ + public boolean isRemoved() { + //TODO: recycling invalidates this + return row == null || row.isRemoved(); + } + + /** + * @return {@code true} if the row is null or dismissed + */ + public boolean isDismissed() { + //TODO: recycling + return row == null || row.isDismissed(); + } + + public boolean isRowPinned() { + return row != null && row.isPinned(); + } + + public void setRowPinned(boolean pinned) { + if (row != null) row.setPinned(pinned); + } + + public boolean isRowAnimatingAway() { + return row != null && row.isHeadsUpAnimatingAway(); + } + + public boolean isRowHeadsUp() { + return row != null && row.isHeadsUp(); + } + + public void setHeadsUp(boolean shouldHeadsUp) { + if (row != null) row.setHeadsUp(shouldHeadsUp); + } + + public boolean mustStayOnScreen() { + return row != null && row.mustStayOnScreen(); + } + + public void setHeadsUpIsVisible() { + if (row != null) row.setHeadsUpIsVisible(); + } + + //TODO: i'm imagining a world where this isn't just the row, but I could be rwong + public ExpandableNotificationRow getHeadsUpAnimationView() { + return row; + } + + public void setUserLocked(boolean userLocked) { + if (row != null) row.setUserLocked(userLocked); + } + + public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) { + if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion); + } + + public void setGroupExpansionChanging(boolean changing) { + if (row != null) row.setGroupExpansionChanging(changing); + } + + public void notifyHeightChanged(boolean needsAnimation) { + if (row != null) row.notifyHeightChanged(needsAnimation); + } + + public void closeRemoteInput() { + if (row != null) row.closeRemoteInput(); + } + + public boolean areChildrenExpanded() { + return row != null && row.areChildrenExpanded(); + } + + public boolean keepInParent() { + return row != null && row.keepInParent(); + } + + //TODO: probably less confusing to say "is group fully visible" + public boolean isGroupNotFullyVisible() { + return row == null || row.isGroupNotFullyVisible(); + } + + public NotificationGuts getGuts() { + if (row != null) return row.getGuts(); + return null; + } + + public boolean hasLowPriorityStateUpdated() { + return row != null && row.hasLowPriorityStateUpdated(); + } + + public void removeRow() { + if (row != null) row.setRemoved(); + } + + public boolean isSummaryWithChildren() { + return row != null && row.isSummaryWithChildren(); + } + + public void setKeepInParent(boolean keep) { + if (row != null) row.setKeepInParent(keep); + } + + public void onDensityOrFontScaleChanged() { + if (row != null) row.onDensityOrFontScaleChanged(); + } + + public boolean areGutsExposed() { + return row != null && row.getGuts().isExposed(); + } + + public boolean isChildInGroup() { + return parent == null; + } + + public void setLowPriorityStateUpdated(boolean updated) { + if (row != null) row.setLowPriorityStateUpdated(updated); + } + + /** + * @return Can the underlying notification be cleared? This can be different from whether the + * notification can be dismissed in case notifications are sensitive on the lockscreen. + * @see #canViewBeDismissed() + */ + public boolean isClearable() { + if (notification == null || !notification.isClearable()) { + return false; + } + if (children.size() > 0) { + for (int i = 0; i < children.size(); i++) { + Entry child = children.get(i); + if (!child.isClearable()) { + return false; + } + } + } + return true; + } + + public boolean canViewBeDismissed() { + if (row == null) return true; + return row.canViewBeDismissed(); + } } private final ArrayMap<String, Entry> mEntries = new ArrayMap<>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 450d34d4007e..e33372957011 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -385,9 +385,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. entry.notification.getUser().getIdentifier()); final StatusBarNotification sbn = entry.notification; - if (entry.row != null) { + if (entry.rowExists()) { entry.reset(); - updateNotification(entry, pmUser, sbn, entry.row); + updateNotification(entry, pmUser, sbn, entry.getRow()); } else { new RowInflaterTask().inflate(mContext, parent, entry, row -> { @@ -543,14 +543,14 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. // Mark as seen immediately setNotificationShown(entry.notification); } else { - entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP); + entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP); } } if ((inflatedFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) { if (shouldPulse(entry)) { mAmbientPulseManager.showNotification(entry); } else { - entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT); + entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT); } } } @@ -561,20 +561,20 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mPendingNotifications.remove(entry.key); // If there was an async task started after the removal, we don't want to add it back to // the list, otherwise we might get leaks. - if (!entry.row.isRemoved()) { + if (!entry.isRowRemoved()) { boolean isNew = mNotificationData.get(entry.key) == null; if (isNew) { showAlertingView(entry, inflatedFlags); addEntry(entry); } else { - if (entry.row.hasLowPriorityStateUpdated()) { + if (entry.getRow().hasLowPriorityStateUpdated()) { mVisualStabilityManager.onLowPriorityUpdated(entry); mPresenter.updateNotificationViews(); } mGroupAlertTransferHelper.onInflationFinished(entry); } } - entry.row.setLowPriorityStateUpdated(false); + entry.setLowPriorityStateUpdated(false); } @Override @@ -633,9 +633,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. getMediaManager().onNotificationRemoved(key); mForegroundServiceController.removeNotification(entry.notification); - if (entry.row != null) { - entry.row.setRemoved(); - mListContainer.cleanUpViewState(entry.row); + if (entry.rowExists()) { + entry.removeRow(); + mListContainer.cleanUpViewStateForEntry(entry); } // Let's remove the children if this was a summary @@ -670,19 +670,19 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. */ private void handleGroupSummaryRemoved(String key) { NotificationData.Entry entry = mNotificationData.get(key); - if (entry != null && entry.row != null - && entry.row.isSummaryWithChildren()) { - if (entry.notification.getOverrideGroupKey() != null && !entry.row.isDismissed()) { + if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) { + if (entry.notification.getOverrideGroupKey() != null && !entry.isRowDismissed()) { // We don't want to remove children for autobundled notifications as they are not // always cancelled. We only remove them if they were dismissed by the user. return; } - List<ExpandableNotificationRow> notificationChildren = - entry.row.getNotificationChildren(); - for (int i = 0; i < notificationChildren.size(); i++) { - ExpandableNotificationRow row = notificationChildren.get(i); - NotificationData.Entry childEntry = row.getEntry(); - boolean isForeground = (row.getStatusBarNotification().getNotification().flags + List<NotificationData.Entry> childEntries = entry.getChildren(); + if (childEntries == null) { + return; + } + for (int i = 0; i < childEntries.size(); i++) { + NotificationData.Entry childEntry = childEntries.get(i); + boolean isForeground = (entry.notification.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; boolean keepForReply = getRemoteInputManager().shouldKeepForRemoteInputHistory(childEntry) @@ -692,10 +692,10 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. // a child we're keeping around for reply! continue; } - row.setKeepInParent(true); + entry.setKeepInParent(true); // we need to set this state earlier as otherwise we might generate some weird // animations - row.setRemoved(); + entry.removeRow(); } } } @@ -705,15 +705,15 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mNotificationData.getNotificationsForCurrentUser(); for (int i = 0; i < userNotifications.size(); i++) { NotificationData.Entry entry = userNotifications.get(i); - boolean exposedGuts = mGutsManager.getExposedGuts() != null - && entry.row.getGuts() == mGutsManager.getExposedGuts(); - entry.row.onDensityOrFontScaleChanged(); + entry.onDensityOrFontScaleChanged(); + boolean exposedGuts = entry.areGutsExposed(); if (exposedGuts) { - mGutsManager.onDensityOrFontScaleChanged(entry.row); + mGutsManager.onDensityOrFontScaleChanged(entry); } } } + //TODO: This method associates a row with an entry, but eventually needs to not do that protected void updateNotification(NotificationData.Entry entry, PackageManager pmUser, StatusBarNotification sbn, ExpandableNotificationRow row) { boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey()); @@ -736,8 +736,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); entry.autoRedacted = entry.notification.getNotification().publicVersion == null; - entry.row = row; - entry.row.setOnActivatedListener(mPresenter); + entry.setRow(row); + row.setOnActivatedListener(mPresenter); boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn, mNotificationData.getImportance(sbn.getKey())); @@ -910,7 +910,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. if (!notification.isClearable()) { // The user may have performed a dismiss action on the notification, since it's // not clearable we should snap it back. - mListContainer.snapViewIfNeeded(entry.row); + mListContainer.snapViewIfNeeded(entry); } if (DEBUG) { @@ -963,11 +963,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. if (NotificationUiAdjustment.needReinflate( oldAdjustments.get(entry.key), newAdjustment)) { - if (entry.row != null) { + if (entry.rowExists()) { entry.reset(); PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext, entry.notification.getUser().getIdentifier()); - updateNotification(entry, pmUser, entry.notification, entry.row); + updateNotification(entry, pmUser, entry.notification, entry.getRow()); } else { // Once the RowInflaterTask is done, it will pick up the updated entry, so // no-op here. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java index 53ebe747c2e9..247c1ababc18 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java @@ -26,8 +26,8 @@ public interface VisibilityLocationProvider { /** * Returns whether an ExpandableNotificationRow is in a visible location or not. * - * @param row + * @param entry * @return true if row is in a visible location */ - boolean isInVisibleLocation(ExpandableNotificationRow row); + boolean isInVisibleLocation(NotificationData.Entry entry); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java index 75613a42eb5e..fce79800193d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java @@ -120,7 +120,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { return true; } if (mAllowedReorderViews.contains(row) - && !mVisibilityLocationProvider.isInVisibleLocation(row)) { + && !mVisibilityLocationProvider.isInVisibleLocation(row.getEntry())) { return true; } return false; @@ -142,12 +142,12 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { if (isHeadsUp) { // Heads up notifications should in general be allowed to reorder if they are out of // view and stay at the current location if they aren't. - mAllowedReorderViews.add(entry.row); + mAllowedReorderViews.add(entry.getRow()); } } public void onLowPriorityUpdated(NotificationData.Entry entry) { - mLowPriorityReorderingViews.add(entry.row); + mLowPriorityReorderingViews.add(entry.getRow()); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index 5dfd5d0da4af..87313b8a0393 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -115,7 +115,7 @@ public class NotificationLogger implements StateListener { for (int i = 0; i < N; i++) { NotificationData.Entry entry = activeNotifications.get(i); String key = entry.notification.getKey(); - boolean isVisible = mListContainer.isInVisibleLocation(entry.row); + boolean isVisible = mListContainer.isInVisibleLocation(entry); NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible); boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj); if (isVisible) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index b6d99b245466..0cd431f9d25b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -17,22 +17,14 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.statusbar.StatusBarState.SHADE; -import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator - .ExpandAnimationParameters; -import static com.android.systemui.statusbar.notification.row.NotificationContentView - .VISIBLE_TYPE_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationContentView - .VISIBLE_TYPE_CONTRACTED; -import static com.android.systemui.statusbar.notification.row.NotificationContentView - .VISIBLE_TYPE_HEADSUP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .FLAG_CONTENT_VIEW_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .FLAG_CONTENT_VIEW_HEADS_UP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .FLAG_CONTENT_VIEW_PUBLIC; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .InflationCallback; +import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -104,7 +96,7 @@ import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; -import com.android.systemui.statusbar.notification.stack.StackScrollState; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -336,7 +328,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private float mTranslationWhenRemoved; private boolean mWasChildInGroupWhenRemoved; private int mNotificationColorAmbient; - private NotificationViewState mNotificationViewState; private SystemNotificationAsyncTask mSystemNotificationAsyncTask = new SystemNotificationAsyncTask(); @@ -893,29 +884,32 @@ public class ExpandableNotificationRow extends ActivatableNotificationView visualStabilityManager, callback); } - public void getChildrenStates(StackScrollState resultState, - AmbientState ambientState) { + /** Updates states of all children. */ + public void updateChildrenStates(AmbientState ambientState) { if (mIsSummaryWithChildren) { - ExpandableViewState parentState = resultState.getViewStateForView(this); - mChildrenContainer.getState(resultState, parentState, ambientState); + ExpandableViewState parentState = getViewState(); + mChildrenContainer.updateState(parentState, ambientState); } } - public void applyChildrenState(StackScrollState state) { + /** Applies children states. */ + public void applyChildrenState() { if (mIsSummaryWithChildren) { - mChildrenContainer.applyState(state); + mChildrenContainer.applyState(); } } - public void prepareExpansionChanged(StackScrollState state) { + /** Prepares expansion changed. */ + public void prepareExpansionChanged() { if (mIsSummaryWithChildren) { - mChildrenContainer.prepareExpansionChanged(state); + mChildrenContainer.prepareExpansionChanged(); } } - public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) { + /** Starts child animations. */ + public void startChildAnimation(AnimationProperties properties) { if (mIsSummaryWithChildren) { - mChildrenContainer.startAnimationToState(finalState, properties); + mChildrenContainer.startAnimationToState(properties); } } @@ -1411,16 +1405,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void performDismiss(boolean fromAccessibility) { if (isOnlyChildInGroup()) { - ExpandableNotificationRow groupSummary = + NotificationData.Entry groupSummary = mGroupManager.getLogicalGroupSummary(getStatusBarNotification()); if (groupSummary.isClearable()) { // If this is the only child in the group, dismiss the group, but don't try to show // the blocking helper affordance! - groupSummary.performDismiss(fromAccessibility); + groupSummary.getRow().performDismiss(fromAccessibility); } } setDismissed(fromAccessibility); - if (isClearable()) { + if (mEntry.isClearable()) { // TODO: track dismiss sentiment if (mOnDismissRunnable != null) { mOnDismissRunnable.run(); @@ -2046,7 +2040,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView .setInterpolator(Interpolators.ALPHA_OUT); setAboveShelf(true); mExpandAnimationRunning = true; - mNotificationViewState.cancelAnimations(this); + getViewState().cancelAnimations(this); mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext()); } else { mExpandAnimationRunning = false; @@ -2244,28 +2238,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setRippleAllowed(allowed); } - /** - * @return Can the underlying notification be cleared? This can be different from whether the - * notification can be dismissed in case notifications are sensitive on the lockscreen. - * @see #canViewBeDismissed() - */ - public boolean isClearable() { - if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) { - return false; - } - if (mIsSummaryWithChildren) { - List<ExpandableNotificationRow> notificationChildren = - mChildrenContainer.getNotificationChildren(); - for (int i = 0; i < notificationChildren.size(); i++) { - ExpandableNotificationRow child = notificationChildren.get(i); - if (!child.isClearable()) { - return false; - } - } - } - return true; - } - @Override public int getIntrinsicHeight() { if (isShownAsBubble()) { @@ -2533,10 +2505,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView /** * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as * otherwise some state might not be updated. To request about the general clearability - * see {@link #isClearable()}. + * see {@link NotificationData.Entry#isClearable()}. */ public boolean canViewBeDismissed() { - return isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); + return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); } private boolean shouldShowPublic() { @@ -2945,13 +2917,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { - mNotificationViewState = new NotificationViewState(stackScrollState); - return mNotificationViewState; - } - - public NotificationViewState getViewState() { - return mNotificationViewState; + public ExpandableViewState createExpandableViewState() { + return new NotificationViewState(); } @Override @@ -3038,6 +3005,21 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mOnAmbient; } + //TODO: this logic can't depend on layout if we are recycling! + public boolean isMediaRow() { + return getExpandedContentView() != null + && getExpandedContentView().findViewById( + com.android.internal.R.id.media_actions) != null; + } + + public boolean isTopLevelChild() { + return getParent() instanceof NotificationStackScrollLayout; + } + + public boolean isGroupNotFullyVisible() { + return getClipTopAmount() > 0 || getTranslationY() < 0; + } + public void setAboveShelf(boolean aboveShelf) { boolean wasAboveShelf = isAboveShelf(); mAboveShelf = aboveShelf; @@ -3046,14 +3028,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } - public static class NotificationViewState extends ExpandableViewState { - - private final StackScrollState mOverallState; - - - private NotificationViewState(StackScrollState stackScrollState) { - mOverallState = stackScrollState; - } + private static class NotificationViewState extends ExpandableViewState { @Override public void applyToView(View view) { @@ -3064,7 +3039,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } handleFixedTranslationZ(row); super.applyToView(view); - row.applyChildrenState(mOverallState); + row.applyChildrenState(); } } @@ -3095,7 +3070,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } handleFixedTranslationZ(row); super.animateTo(child, properties); - row.startChildAnimation(mOverallState, properties); + row.startChildAnimation(properties); } } } @@ -3145,11 +3120,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView pw.print(", alpha: " + getAlpha()); pw.print(", translation: " + getTranslation()); pw.print(", removed: " + isRemoved()); - pw.print(", privateShowing: " + (getShowingLayout() == mPrivateLayout)); + NotificationContentView showingLayout = getShowingLayout(); + pw.print(", privateShowing: " + (showingLayout == mPrivateLayout)); pw.println(); + showingLayout.dump(fd, pw, args); pw.print(" "); - if (mNotificationViewState != null) { - mNotificationViewState.dump(fd, pw, args); + if (getViewState() != null) { + getViewState().dump(fd, pw, args); } else { pw.print("no viewState!!!"); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index 0589e3f63973..1e8de076cbed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -21,23 +21,27 @@ import android.content.Context; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import androidx.annotation.Nullable; + import com.android.systemui.Dumpable; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; -import com.android.systemui.statusbar.notification.stack.StackScrollState; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.List; /** * An abstract view for expandable views. */ public abstract class ExpandableView extends FrameLayout implements Dumpable { + private static final String TAG = "ExpandableView"; public static final float NO_ROUNDNESS = -1; protected OnHeightChangedListener mOnHeightChangedListener; @@ -54,6 +58,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { private ViewGroup mTransientContainer; private boolean mInShelf; private boolean mTransformingInShelf; + @Nullable private ExpandableViewState mViewState; public ExpandableView(Context context, AttributeSet attrs) { super(context, attrs); @@ -511,10 +516,56 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { public void setActualHeightAnimating(boolean animating) {} - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { + protected ExpandableViewState createExpandableViewState() { return new ExpandableViewState(); } + /** Sets {@link ExpandableViewState} to default state. */ + public ExpandableViewState resetViewState() { + // TODO(http://b/119762423): Move the null check to getViewState(). + if (mViewState == null) { + mViewState = createExpandableViewState(); + } + + // initialize with the default values of the view + mViewState.height = getIntrinsicHeight(); + mViewState.gone = getVisibility() == View.GONE; + mViewState.alpha = 1f; + mViewState.notGoneIndex = -1; + mViewState.xTranslation = getTranslationX(); + mViewState.hidden = false; + mViewState.scaleX = getScaleX(); + mViewState.scaleY = getScaleY(); + mViewState.inShelf = false; + mViewState.headsUpIsVisible = false; + + // handling reset for child notifications + if (this instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) this; + List<ExpandableNotificationRow> children = row.getNotificationChildren(); + if (row.isSummaryWithChildren() && children != null) { + for (ExpandableNotificationRow childRow : children) { + childRow.resetViewState(); + } + } + } + + return mViewState; + } + + @Nullable public ExpandableViewState getViewState() { + return mViewState; + } + + /** Applies internal {@link ExpandableViewState} to this view. */ + public void applyViewState() { + if (mViewState == null) { + Log.wtf(TAG, "No child state was found when applying this state to the hostView"); + } else if (!mViewState.gone) { + mViewState.applyToView(this); + } + } + /** * @return whether the current view doesn't add height to the overall content. This means that * if it is added to a list of items, it's content will still have the same height. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java index 1f15ed012551..311bf7a244c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java @@ -24,7 +24,6 @@ import android.view.View; import com.android.systemui.R; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; -import com.android.systemui.statusbar.notification.stack.StackScrollState; public class FooterView extends StackScrollerDecorView { private final int mClearAllTopPadding; @@ -87,7 +86,7 @@ public class FooterView extends StackScrollerDecorView { } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { + public ExpandableViewState createExpandableViewState() { return new FooterViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index d4e65db50b44..a4fdc08d5579 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -55,6 +55,8 @@ import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.statusbar.policy.SmartReplyConstants; import com.android.systemui.statusbar.policy.SmartReplyView; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Collections; import java.util.List; @@ -1228,17 +1230,18 @@ public class NotificationContentView extends FrameLayout { mOnContentViewInactiveListeners.clear(); mBeforeN = entry.targetSdk < Build.VERSION_CODES.N; updateAllSingleLineViews(); + ExpandableNotificationRow row = entry.getRow(); if (mContractedChild != null) { - mContractedWrapper.onContentUpdated(entry.row); + mContractedWrapper.onContentUpdated(row); } if (mExpandedChild != null) { - mExpandedWrapper.onContentUpdated(entry.row); + mExpandedWrapper.onContentUpdated(row); } if (mHeadsUpChild != null) { - mHeadsUpWrapper.onContentUpdated(entry.row); + mHeadsUpWrapper.onContentUpdated(row); } if (mAmbientChild != null) { - mAmbientWrapper.onContentUpdated(entry.row); + mAmbientWrapper.onContentUpdated(row); } applyRemoteInputAndSmartReply(entry); updateLegacy(); @@ -1288,10 +1291,10 @@ public class NotificationContentView extends FrameLayout { return; } - SmartRepliesAndActions smartRepliesAndActions = chooseSmartRepliesAndActions( - mSmartReplyConstants, entry); + SmartRepliesAndActions smartRepliesAndActions = + chooseSmartRepliesAndActions(mSmartReplyConstants, entry); - applyRemoteInput(entry, smartRepliesAndActions.freeformRemoteInputActionPair != null); + applyRemoteInput(entry, smartRepliesAndActions.hasFreeformRemoteInput); applySmartReplyView(smartRepliesAndActions, entry); } @@ -1318,62 +1321,47 @@ public class NotificationContentView extends FrameLayout { boolean appGeneratedSmartRepliesExist = enableAppGeneratedSmartReplies && remoteInputActionPair != null - && !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices()); + && !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices()) + && remoteInputActionPair.second.actionIntent != null; List<Notification.Action> appGeneratedSmartActions = notification.getContextualActions(); boolean appGeneratedSmartActionsExist = !appGeneratedSmartActions.isEmpty(); - List<Notification.Action> sysGeneratedSmartActions = - notification.getAllowSystemGeneratedContextualActions() - ? entry.systemGeneratedSmartActions : Collections.emptyList(); - + SmartReplyView.SmartReplies smartReplies = null; + SmartReplyView.SmartActions smartActions = null; if (appGeneratedSmartRepliesExist) { - return new SmartRepliesAndActions(remoteInputActionPair.first, - remoteInputActionPair.second.actionIntent, + smartReplies = new SmartReplyView.SmartReplies( remoteInputActionPair.first.getChoices(), - appGeneratedSmartActions, - freeformRemoteInputActionPair); - } else if (appGeneratedSmartActionsExist) { - return new SmartRepliesAndActions(null, null, null, appGeneratedSmartActions, - freeformRemoteInputActionPair); - } else if (!ArrayUtils.isEmpty(entry.smartReplies) - && freeformRemoteInputActionPair != null - && freeformRemoteInputActionPair.second.getAllowGeneratedReplies()) { - // App didn't generate anything, use NAS-generated replies and actions - return new SmartRepliesAndActions(freeformRemoteInputActionPair.first, - freeformRemoteInputActionPair.second.actionIntent, - entry.smartReplies, - sysGeneratedSmartActions, - freeformRemoteInputActionPair); - } - // App didn't generate anything, and there are no NAS-generated smart replies. - return new SmartRepliesAndActions(null, null, null, sysGeneratedSmartActions, - freeformRemoteInputActionPair); - } - - @VisibleForTesting - static class SmartRepliesAndActions { - public final RemoteInput remoteInputWithChoices; - public final PendingIntent pendingIntentForSmartReplies; - public final CharSequence[] smartReplies; - public final List<Notification.Action> smartActions; - public final Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair; - - SmartRepliesAndActions(RemoteInput remoteInput, PendingIntent pendingIntent, - CharSequence[] choices, List<Notification.Action> smartActions, - Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair) { - this.remoteInputWithChoices = remoteInput; - this.pendingIntentForSmartReplies = pendingIntent; - this.smartReplies = choices; - this.smartActions = smartActions; - this.freeformRemoteInputActionPair = freeformRemoteInputActionPair; - } - - boolean smartRepliesExist() { - return remoteInputWithChoices != null - && pendingIntentForSmartReplies != null - && !ArrayUtils.isEmpty(smartReplies); + remoteInputActionPair.first, + remoteInputActionPair.second.actionIntent, + false /* fromAssistant */); + } + if (appGeneratedSmartActionsExist) { + smartActions = new SmartReplyView.SmartActions(appGeneratedSmartActions, + false /* fromAssistant */); + } + // Apps didn't provide any smart replies / actions, use those from NAS (if any). + if (!appGeneratedSmartRepliesExist && !appGeneratedSmartActionsExist) { + boolean useGeneratedReplies = !ArrayUtils.isEmpty(entry.smartReplies) + && freeformRemoteInputActionPair != null + && freeformRemoteInputActionPair.second.getAllowGeneratedReplies() + && freeformRemoteInputActionPair.second.actionIntent != null; + if (useGeneratedReplies) { + smartReplies = new SmartReplyView.SmartReplies( + entry.smartReplies, + freeformRemoteInputActionPair.first, + freeformRemoteInputActionPair.second.actionIntent, + true /* fromAssistant */); + } + boolean useSmartActions = !ArrayUtils.isEmpty(entry.systemGeneratedSmartActions) + && notification.getAllowSystemGeneratedContextualActions(); + if (useSmartActions) { + smartActions = new SmartReplyView.SmartActions( + entry.systemGeneratedSmartActions, true /* fromAssistant */); + } } + return new SmartRepliesAndActions( + smartReplies, smartActions, freeformRemoteInputActionPair != null); } private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) { @@ -1480,12 +1468,9 @@ public class NotificationContentView extends FrameLayout { if (mExpandedChild != null) { mExpandedSmartReplyView = applySmartReplyView(mExpandedChild, smartRepliesAndActions, entry); - if (mExpandedSmartReplyView != null - && smartRepliesAndActions.remoteInputWithChoices != null - && smartRepliesAndActions.smartReplies != null - && smartRepliesAndActions.smartReplies.length > 0) { - mSmartReplyController.smartRepliesAdded(entry, - smartRepliesAndActions.smartReplies.length); + if (mExpandedSmartReplyView != null && smartRepliesAndActions.smartReplies != null) { + mSmartReplyController.smartRepliesAdded( + entry, smartRepliesAndActions.smartReplies.choices.length); } } } @@ -1499,8 +1484,8 @@ public class NotificationContentView extends FrameLayout { } LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate; // If there are no smart replies and no smart actions - early out. - if (!smartRepliesAndActions.smartRepliesExist() - && smartRepliesAndActions.smartActions.isEmpty()) { + if (smartRepliesAndActions.smartReplies == null + && smartRepliesAndActions.smartActions == null) { smartReplyContainer.setVisibility(View.GONE); return null; } @@ -1530,10 +1515,13 @@ public class NotificationContentView extends FrameLayout { } if (smartReplyView != null) { smartReplyView.resetSmartSuggestions(smartReplyContainer); - smartReplyView.addRepliesFromRemoteInput(smartRepliesAndActions.remoteInputWithChoices, - smartRepliesAndActions.pendingIntentForSmartReplies, mSmartReplyController, - entry, smartRepliesAndActions.smartReplies); - smartReplyView.addSmartActions(smartRepliesAndActions.smartActions); + if (smartRepliesAndActions.smartReplies != null) { + smartReplyView.addRepliesFromRemoteInput( + smartRepliesAndActions.smartReplies, mSmartReplyController, entry); + } + if (smartRepliesAndActions.smartActions != null) { + smartReplyView.addSmartActions(smartRepliesAndActions.smartActions); + } smartReplyContainer.setVisibility(View.VISIBLE); } return smartReplyView; @@ -1933,4 +1921,41 @@ public class NotificationContentView extends FrameLayout { mExpandedWrapper.setHeaderVisibleAmount(headerVisibleAmount); } } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.print(" "); + pw.print("contentView visibility: " + getVisibility()); + pw.print(", alpha: " + getAlpha()); + pw.print(", clipBounds: " + getClipBounds()); + pw.print(", contentHeight: " + mContentHeight); + pw.print(", visibleType: " + mVisibleType); + View view = getViewForVisibleType(mVisibleType); + pw.print(", visibleView "); + if (view != null) { + pw.print(" visibility: " + view.getVisibility()); + pw.print(", alpha: " + view.getAlpha()); + pw.print(", clipBounds: " + view.getClipBounds()); + } else { + pw.print("null"); + } + pw.println(); + } + + @VisibleForTesting + static class SmartRepliesAndActions { + @Nullable + public final SmartReplyView.SmartReplies smartReplies; + @Nullable + public final SmartReplyView.SmartActions smartActions; + public final boolean hasFreeformRemoteInput; + + SmartRepliesAndActions( + @Nullable SmartReplyView.SmartReplies smartReplies, + @Nullable SmartReplyView.SmartActions smartActions, + boolean hasFreeformRemoteInput) { + this.smartReplies = smartReplies; + this.smartActions = smartActions; + this.hasFreeformRemoteInput = hasFreeformRemoteInput; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 37bf06edde4f..3b407b5f8a65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -18,10 +18,7 @@ package com.android.systemui.statusbar.notification.row; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; -import static android.service.notification.NotificationListenerService.Ranking - .USER_SENTIMENT_NEGATIVE; - -import static com.android.systemui.statusbar.notification.row.NotificationInfo.ACTION_NONE; +import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; import android.app.INotificationManager; import android.app.NotificationChannel; @@ -43,7 +40,6 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; -import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.plugins.ActivityStarter; @@ -86,7 +82,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); // which notification is currently being longpress-examined by the user - private final IStatusBarService mBarService; private NotificationGuts mNotificationGutsExposed; private NotificationMenuRowPlugin.MenuItem mGutsMenuItem; private NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback; @@ -103,8 +98,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); - mBarService = IStatusBarService.Stub.asInterface( - ServiceManager.getService(Context.STATUS_BAR_SERVICE)); } public void setUpWithPresenter(NotificationPresenter presenter, @@ -116,9 +109,9 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mOnSettingsClickListener = onSettingsClick; } - public void onDensityOrFontScaleChanged(ExpandableNotificationRow row) { - setExposedGuts(row.getGuts()); - bindGuts(row); + public void onDensityOrFontScaleChanged(NotificationData.Entry entry) { + setExposedGuts(entry.getGuts()); + bindGuts(entry.getRow()); } /** @@ -191,13 +184,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx } else if (gutsView instanceof AppOpsInfo) { initializeAppOpsInfo(row, (AppOpsInfo) gutsView); } else if (gutsView instanceof NotificationInfo) { - int action; - if (item instanceof NotificationMenuRow.NotificationInfoMenuItem) { - action = ((NotificationMenuRow.NotificationInfoMenuItem) item).mAction; - } else { - action = ACTION_NONE; - } - initializeNotificationInfo(row, (NotificationInfo) gutsView, action); + initializeNotificationInfo(row, (NotificationInfo) gutsView); } return true; } catch (Exception e) { @@ -256,13 +243,11 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx * Sets up the {@link NotificationInfo} inside the notification row's guts. * @param row view to set up the guts for * @param notificationInfoView view to set up/bind within {@code row} - * @param action The action to take immediately upon binding, if any. */ @VisibleForTesting void initializeNotificationInfo( final ExpandableNotificationRow row, - NotificationInfo notificationInfoView, - @NotificationInfo.NotificationInfoAction int action) throws Exception { + NotificationInfo notificationInfoView) throws Exception { NotificationGuts guts = row.getGuts(); StatusBarNotification sbn = row.getStatusBarNotification(); String packageName = sbn.getPackageName(); @@ -306,8 +291,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx isForBlockingHelper, row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE, row.getEntry().noisy, - row.getEntry().importance, - action); + row.getEntry().importance); } @@ -441,8 +425,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx public boolean shouldExtendLifetime(NotificationData.Entry entry) { return entry != null &&(mNotificationGutsExposed != null - && entry.row.getGuts() != null - && mNotificationGutsExposed == entry.row.getGuts() + && entry.getGuts() != null + && mNotificationGutsExposed == entry.getGuts() && !mNotificationGutsExposed.isLeavebehind()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 0d36d2c2f77c..213ac704b06a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -187,14 +187,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G boolean isDeviceProvisioned, boolean isNonblockable, boolean isNoisy, - int importance, - @NotificationInfoAction int action) + int importance) throws RemoteException { bindNotification(pm, iNotificationManager, pkg, notificationChannel, numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick, onAppSettingsClick, isDeviceProvisioned, isNonblockable, false /* isBlockingHelper */, false /* isUserSentimentNegative */, isNoisy, - importance, action); + importance); } public void bindNotification( @@ -212,8 +211,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G boolean isForBlockingHelper, boolean isUserSentimentNegative, boolean isNoisy, - int importance, - @NotificationInfoAction int action) + int importance) throws RemoteException { mINotificationManager = iNotificationManager; mMetricsLogger = Dependency.get(MetricsLogger.class); @@ -255,10 +253,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G bindHeader(); bindPrompt(); bindButtons(); - - if (action != ACTION_NONE) { - swapContent(action, false /* don't animate */); - } } private void bindHeader() throws RemoteException { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index b6ff6fc7f0e5..948d2a5e2a18 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -17,9 +17,6 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION; -import static com.android.systemui.statusbar.notification.row.NotificationInfo.ACTION_BLOCK; -import static com.android.systemui.statusbar.notification.row.NotificationInfo.ACTION_NONE; -import static com.android.systemui.statusbar.notification.row.NotificationInfo.ACTION_TOGGLE_SILENT; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -46,7 +43,6 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.AlphaOptimizedImageView; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent; -import com.android.systemui.statusbar.notification.row.NotificationInfo.NotificationInfoAction; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import java.util.ArrayList; @@ -73,7 +69,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl private Context mContext; private FrameLayout mMenuContainer; - private NotificationInfoMenuItem mInfoItem; + private NotificationMenuItem mInfoItem; private MenuItem mAppOpsItem; private MenuItem mSnoozeItem; private ArrayList<MenuItem> mLeftMenuItems; @@ -248,36 +244,30 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl if (!isForeground) { // Only show snooze for non-foreground notifications mSnoozeItem = createSnoozeItem(mContext); - mLeftMenuItems.add(mSnoozeItem); } - mInfoItem = createInfoItem(mContext); - if (!NotificationUtils.useNewInterruptionModel(mContext)) { - mLeftMenuItems.add(mInfoItem); - } - mAppOpsItem = createAppOpsItem(mContext); - mLeftMenuItems.add(mAppOpsItem); - if (NotificationUtils.useNewInterruptionModel(mContext)) { - if (!mParent.getIsNonblockable()) { - mRightMenuItems.add(createBlockItem(mContext, mInfoItem.getGutsView())); - } - // TODO(kprevas): this is duplicated logic - // but it's currently spread across NotificationGutsManager and NotificationInfo. - // Try to consolidate and reuse here. - boolean canToggleSilent = !mParent.getIsNonblockable() - && !isForeground - && mParent.getEntry().noisy; - if (canToggleSilent) { - int channelImportance = mParent.getEntry().channel.getImportance(); - int effectiveImportance = - channelImportance == NotificationManager.IMPORTANCE_UNSPECIFIED - ? mParent.getEntry().importance : channelImportance; - mRightMenuItems.add(createToggleSilentItem(mContext, mInfoItem.getGutsView(), - effectiveImportance < NotificationManager.IMPORTANCE_DEFAULT)); + int channelImportance = mParent.getEntry().channel.getImportance(); + int effectiveImportance = + channelImportance == NotificationManager.IMPORTANCE_UNSPECIFIED + ? mParent.getEntry().importance : channelImportance; + mInfoItem = createInfoItem(mContext, + effectiveImportance < NotificationManager.IMPORTANCE_DEFAULT); + } else { + mInfoItem = createInfoItem(mContext); + } + + if (!NotificationUtils.useNewInterruptionModel(mContext)) { + if (!isForeground) { + mRightMenuItems.add(mSnoozeItem); } + mRightMenuItems.add(mInfoItem); + mRightMenuItems.add(mAppOpsItem); + mLeftMenuItems.addAll(mRightMenuItems); } else { - mRightMenuItems.addAll(mLeftMenuItems); + mRightMenuItems.add(mInfoItem); + mRightMenuItems.add(mAppOpsItem); + mRightMenuItems.add(mSnoozeItem); } populateMenuViews(); @@ -634,13 +624,24 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl return snooze; } - static NotificationInfoMenuItem createInfoItem(Context context) { + static NotificationMenuItem createInfoItem(Context context) { Resources res = context.getResources(); String infoDescription = res.getString(R.string.notification_menu_gear_description); NotificationInfo infoContent = (NotificationInfo) LayoutInflater.from(context).inflate( R.layout.notification_info, null, false); - return new NotificationInfoMenuItem(context, infoDescription, infoContent, - R.drawable.ic_settings, ACTION_NONE); + return new NotificationMenuItem(context, infoDescription, infoContent, + R.drawable.ic_settings); + } + + static NotificationMenuItem createInfoItem(Context context, boolean isCurrentlySilent) { + Resources res = context.getResources(); + String infoDescription = res.getString(R.string.notification_menu_gear_description); + NotificationInfo infoContent = (NotificationInfo) LayoutInflater.from(context).inflate( + R.layout.notification_info, null, false); + int iconResId = isCurrentlySilent + ? R.drawable.ic_notifications_alert + : R.drawable.ic_notifications_silence; + return new NotificationMenuItem(context, infoDescription, infoContent, iconResId); } static MenuItem createAppOpsItem(Context context) { @@ -651,29 +652,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl return info; } - private static MenuItem createBlockItem(Context context, NotificationInfo gutsView) { - return new NotificationInfoMenuItem( - context, - context.getResources().getString(R.string.inline_stop_button), - gutsView, - R.drawable.ic_notification_block, - ACTION_BLOCK); - } - - private static MenuItem createToggleSilentItem(Context context, NotificationInfo gutsView, - boolean isCurrentlySilent) { - return new NotificationInfoMenuItem( - context, - isCurrentlySilent - ? context.getResources().getString(R.string.inline_silent_button_alert) - : context.getResources().getString(R.string.inline_silent_button_silent), - gutsView, - isCurrentlySilent - ? R.drawable.ic_notifications_alert - : R.drawable.ic_notifications_silence, - ACTION_TOGGLE_SILENT); - } - private void addMenuView(MenuItem item, ViewGroup parent) { View menuView = item.getMenuView(); if (menuView != null) { @@ -789,23 +767,4 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl return mContentDescription; } } - - /** A {@link NotificationMenuItem} with an associated {@link NotificationInfoAction}. */ - public static class NotificationInfoMenuItem extends NotificationMenuItem { - - @NotificationInfoAction - int mAction; - - public NotificationInfoMenuItem(Context context, String contentDescription, - NotificationInfo content, int iconResId, - @NotificationInfoAction int action) { - super(context, contentDescription, content, iconResId); - this.mAction = action; - } - - @Override - public NotificationInfo getGutsView() { - return (NotificationInfo) super.getGutsView(); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index ff1a6fc075d0..670908fe175d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -40,7 +40,7 @@ public class AmbientState { private static final int NO_SECTION_BOUNDARY = -1; - private ArrayList<View> mDraggedViews = new ArrayList<>(); + private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>(); private int mScrollY; private boolean mDimmed; private ActivatableNotificationView mActivatedChild; @@ -131,7 +131,8 @@ public class AmbientState { this.mScrollY = scrollY; } - public void onBeginDrag(View view) { + /** Call when dragging begins. */ + public void onBeginDrag(ExpandableView view) { mDraggedViews.add(view); } @@ -139,7 +140,7 @@ public class AmbientState { mDraggedViews.remove(view); } - public ArrayList<View> getDraggedViews() { + public ArrayList<ExpandableView> getDraggedViews() { return mDraggedViews; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 74b4aa2a7057..0f38bd9804a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -274,7 +274,7 @@ public class NotificationChildrenContainer extends ViewGroup { updateGroupOverflow(); row.setContentTransformationAmount(0, false /* isLastChild */); // It doesn't make sense to keep old animations around, lets cancel them! - ExpandableNotificationRow.NotificationViewState viewState = row.getViewState(); + ExpandableViewState viewState = row.getViewState(); if (viewState != null) { viewState.cancelAnimations(row); row.cancelAppearDrawing(); @@ -562,12 +562,10 @@ public class NotificationChildrenContainer extends ViewGroup { /** * Update the state of all its children based on a linear layout algorithm. - * @param resultState the state to update * @param parentState the state of the parent * @param ambientState */ - public void getState(StackScrollState resultState, ExpandableViewState parentState, - AmbientState ambientState) { + public void updateState(ExpandableViewState parentState, AmbientState ambientState) { int childCount = mChildren.size(); int yPosition = mNotificationHeaderMargin + mCurrentHeaderTranslation; boolean firstChild = true; @@ -605,7 +603,7 @@ public class NotificationChildrenContainer extends ViewGroup { firstChild = false; } - ExpandableViewState childState = resultState.getViewStateForView(child); + ExpandableViewState childState = child.getViewState(); int intrinsicHeight = child.getIntrinsicHeight(); childState.height = intrinsicHeight; childState.yTranslation = yPosition + launchTransitionCompensation; @@ -639,7 +637,7 @@ public class NotificationChildrenContainer extends ViewGroup { if (mOverflowNumber != null) { ExpandableNotificationRow overflowView = mChildren.get(Math.min( getMaxAllowedVisibleChildren(true /* likeCollapsed */), childCount) - 1); - mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView)); + mGroupOverFlowState.copyFrom(overflowView.getViewState()); if (mContainingNotification.isOnAmbient()) { mGroupOverFlowState.alpha = 0.0f; @@ -724,7 +722,8 @@ public class NotificationChildrenContainer extends ViewGroup { return NUMBER_OF_CHILDREN_WHEN_COLLAPSED; } - public void applyState(StackScrollState state) { + /** Applies state to children. */ + public void applyState() { int childCount = mChildren.size(); ViewState tmpState = new ViewState(); float expandFraction = 0.0f; @@ -737,7 +736,7 @@ public class NotificationChildrenContainer extends ViewGroup { && !mHideDividersDuringExpand); for (int i = 0; i < childCount; i++) { ExpandableNotificationRow child = mChildren.get(i); - ExpandableViewState viewState = state.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); viewState.applyToView(child); // layout the divider @@ -799,14 +798,14 @@ public class NotificationChildrenContainer extends ViewGroup { * This is called when the children expansion has changed and positions the children properly * for an appear animation. * - * @param state the new state we animate to */ - public void prepareExpansionChanged(StackScrollState state) { + public void prepareExpansionChanged() { // TODO: do something that makes sense, like placing the invisible views correctly return; } - public void startAnimationToState(StackScrollState state, AnimationProperties properties) { + /** Animate to a given state. */ + public void startAnimationToState(AnimationProperties properties) { int childCount = mChildren.size(); ViewState tmpState = new ViewState(); float expandFraction = getGroupExpandFraction(); @@ -816,7 +815,7 @@ public class NotificationChildrenContainer extends ViewGroup { && !mHideDividersDuringExpand); for (int i = childCount - 1; i >= 0; i--) { ExpandableNotificationRow child = mChildren.get(i); - ExpandableViewState viewState = state.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); viewState.animateTo(child, properties); // layout the divider diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java index 4d100a46c48a..f0a26536d7b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java @@ -45,34 +45,31 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange /** * Change the position of child to a new location - * - * @param child the view to change the position for + * @param child the view to change the position for * @param newIndex the new index */ - void changeViewPosition(View child, int newIndex); + void changeViewPosition(ExpandableView child, int newIndex); /** * Called when a child was added to a group. * * @param row row of the group child that was added */ - void notifyGroupChildAdded(View row); + void notifyGroupChildAdded(ExpandableView row); /** * Called when a child was removed from a group. - * - * @param row row of the child that was removed + * @param row row of the child that was removed * @param childrenContainer ViewGroup of the group that the child was removed from */ - void notifyGroupChildRemoved(View row, ViewGroup childrenContainer); + void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer); /** * Generate an animation for an added child view. - * - * @param child The view to be added. + * @param child The view to be added. * @param fromMoreCard Whether this add is coming from the "more" card on lockscreen. */ - void generateAddAnimation(View child, boolean fromMoreCard); + void generateAddAnimation(ExpandableView child, boolean fromMoreCard); /** * Generate a child order changed event. @@ -118,9 +115,9 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange /** * Handle snapping a non-dismissable row back if the user tried to dismiss it. * - * @param row row to snap back + * @param entry the entry whose row needs to snap back */ - void snapViewIfNeeded(ExpandableNotificationRow row); + void snapViewIfNeeded(NotificationData.Entry entry); /** * Get the view parent for a notification entry. For example, NotificationStackScrollLayout. @@ -149,9 +146,9 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange * Called when a notification is removed from the shade. This cleans up the state for a * given view. * - * @param view view to clean up view state for + * @param entry the entry whose view's view state needs to be cleaned up (say that 5 times fast) */ - void cleanUpViewState(View view); + void cleanUpViewStateForEntry(NotificationData.Entry entry); /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index c867a41e7264..4f0831f1043c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -16,13 +16,12 @@ package com.android.systemui.statusbar.notification.stack; -import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout - .NUM_SECTIONS; - -import android.view.View; +import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS; +import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import java.util.HashSet; @@ -37,7 +36,7 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener { private ActivatableNotificationView[] mLastInSectionViews; private ActivatableNotificationView[] mTmpFirstInSectionViews; private ActivatableNotificationView[] mTmpLastInSectionViews; - private HashSet<View> mAnimatedChildren; + private HashSet<ExpandableView> mAnimatedChildren; private Runnable mRoundingChangedCallback; private ExpandableNotificationRow mTrackedHeadsUp; private float mAppearFraction; @@ -50,13 +49,13 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener { } @Override - public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { - updateView(headsUp, false /* animate */); + public void onHeadsUpPinned(NotificationData.Entry headsUp) { + updateView(headsUp.getRow(), false /* animate */); } @Override - public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { - updateView(headsUp, true /* animate */); + public void onHeadsUpUnPinned(NotificationData.Entry headsUp) { + updateView(headsUp.getRow(), true /* animate */); } public void onHeadsupAnimatingAwayChanged(ExpandableNotificationRow row, @@ -211,7 +210,7 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener { return anyChanged; } - public void setAnimatedChildren(HashSet<View> animatedChildren) { + public void setAnimatedChildren(HashSet<ExpandableView> animatedChildren) { mAnimatedChildren = animatedChildren; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index ecd0d98bdcf4..626e68850c12 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -208,16 +208,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd */ protected final StackScrollAlgorithm mStackScrollAlgorithm; - /** - * The current State this Layout is in - */ - private StackScrollState mCurrentStackScrollState = new StackScrollState(this); private final AmbientState mAmbientState; private NotificationGroupManager mGroupManager; - private HashSet<View> mChildrenToAddAnimated = new HashSet<>(); + private HashSet<ExpandableView> mChildrenToAddAnimated = new HashSet<>(); private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>(); - private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<>(); - private ArrayList<View> mChildrenChangingPositions = new ArrayList<>(); + private ArrayList<ExpandableView> mChildrenToRemoveAnimated = new ArrayList<>(); + private ArrayList<ExpandableView> mChildrenChangingPositions = new ArrayList<>(); private HashSet<View> mFromMoreCardAdditions = new HashSet<>(); private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>(); private ArrayList<View> mSwipedOutViews = new ArrayList<>(); @@ -275,7 +271,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean mDontReportNextOverScroll; private boolean mDontClampNextScroll; private boolean mNeedViewResizeAnimation; - private View mExpandedGroupView; + private ExpandableView mExpandedGroupView; private boolean mEverythingNeedsAnimation; /** @@ -382,7 +378,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean mGroupExpandedForMeasure; private boolean mScrollable; private View mForcedScroll; - private View mNeedingPulseAnimation; + private ExpandableView mNeedingPulseAnimation; /** * @see #setDarkAmount(float, float) @@ -600,12 +596,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public void setRemoteInputActive(NotificationData.Entry entry, boolean remoteInputActive) { mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive); - entry.row.notifyHeightChanged(true /* needsAnimation */); + entry.notifyHeightChanged(true /* needsAnimation */); updateFooter(); } public void lockScrollTo(NotificationData.Entry entry) { - NotificationStackScrollLayout.this.lockScrollTo(entry.row); + NotificationStackScrollLayout.this.lockScrollTo(entry.getRow()); } public void requestDisallowLongPressAndDismiss() { @@ -897,8 +893,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM) - public boolean isInVisibleLocation(ExpandableNotificationRow row) { - ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(row); + public boolean isInVisibleLocation(NotificationData.Entry entry) { + ExpandableNotificationRow row = entry.getRow(); + ExpandableViewState childViewState = row.getViewState(); + if (childViewState == null) { return false; } @@ -944,7 +942,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ? 0 : mScroller.getCurrVelocity()); mAmbientState.setScrollY(mOwnScrollY); - mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState); + mStackScrollAlgorithm.resetViewStates(mAmbientState); if (!isCurrentlyAnimating() && !mNeedsAnimation) { applyCurrentState(); } else { @@ -1213,12 +1211,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd if (topEntry == null) { return 0; } - ExpandableNotificationRow row = topEntry.row; + ExpandableNotificationRow row = topEntry.getRow(); if (row.isChildInGroup()) { - final ExpandableNotificationRow groupSummary + final NotificationData.Entry groupSummary = mGroupManager.getGroupSummary(row.getStatusBarNotification()); if (groupSummary != null) { - row = groupSummary; + row = groupSummary.getRow(); } } return row.getPinnedHeadsUpHeight(); @@ -1390,11 +1388,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd && touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) { if (slidingChild instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild; + NotificationData.Entry entry = row.getEntry(); if (!mIsExpanded && row.isHeadsUp() && row.isPinned() - && mHeadsUpManager.getTopEntry().row != row + && mHeadsUpManager.getTopEntry().getRow() != row && mGroupManager.getGroupSummary( - mHeadsUpManager.getTopEntry().row.getStatusBarNotification()) - != row) { + mHeadsUpManager.getTopEntry().notification) + != entry) { continue; } return row.getViewAtPosition(touchY - childTop); @@ -1524,7 +1523,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void snapViewIfNeeded(ExpandableNotificationRow child) { + public void snapViewIfNeeded(NotificationData.Entry entry) { + ExpandableNotificationRow child = entry.getRow(); boolean animate = mIsExpanded || isPinnedHeadsUp(child); // If the child is showing the notification menu snap to that float targetLeft = child.getProvider().isMenuVisible() ? child.getTranslation() : 0; @@ -1934,12 +1934,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * @return the last child which has visibility unequal to GONE */ @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public View getLastChildNotGone() { + public ExpandableView getLastChildNotGone() { int childCount = getChildCount(); for (int i = childCount - 1; i >= 0; i--) { View child = getChildAt(i); if (child.getVisibility() != View.GONE && child != mShelf) { - return child; + return (ExpandableView) child; } } return null; @@ -2508,35 +2508,33 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd // we only call our internal methods if this is actually a removal and not just a // notification which becomes a child notification if (!mChildTransferInProgress) { - onViewRemovedInternal(child, this); + onViewRemovedInternal((ExpandableView) child, this); } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @Override - public void cleanUpViewState(View child) { + public void cleanUpViewStateForEntry(NotificationData.Entry entry) { + View child = entry.getRow(); if (child == mSwipeHelper.getTranslatingParentView()) { mSwipeHelper.clearTranslatingParentView(); } - mCurrentStackScrollState.removeViewStateForView(child); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void onViewRemovedInternal(View child, ViewGroup container) { + private void onViewRemovedInternal(ExpandableView child, ViewGroup container) { if (mChangePositionInProgress) { // This is only a position change, don't do anything special return; } - ExpandableView expandableView = (ExpandableView) child; - expandableView.setOnHeightChangedListener(null); - mCurrentStackScrollState.removeViewStateForView(child); - updateScrollStateForRemovedChild(expandableView); + child.setOnHeightChangedListener(null); + updateScrollStateForRemovedChild(child); boolean animationGenerated = generateRemoveAnimation(child); if (animationGenerated) { if (!mSwipedOutViews.contains(child) - || Math.abs(expandableView.getTranslation()) != expandableView.getWidth()) { + || Math.abs(child.getTranslation()) != child.getWidth()) { container.addTransientView(child, 0); - expandableView.setTransientContainer(container); + child.setTransientContainer(container); } } else { mSwipedOutViews.remove(child); @@ -2580,14 +2578,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * @return Whether an animation was generated. */ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - private boolean generateRemoveAnimation(View child) { + private boolean generateRemoveAnimation(ExpandableView child) { if (removeRemovedChildFromHeadsUpChangeAnimations(child)) { mAddedHeadsUpChildren.remove(child); return false; } if (isClickedHeadsUp(child)) { // An animation is already running, add it transiently - mClearTransientViewsWhenFinished.add((ExpandableView) child); + mClearTransientViewsWhenFinished.add(child); return true; } if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) { @@ -2644,9 +2642,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean isChildInInvisibleGroup(View child) { if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; - ExpandableNotificationRow groupSummary = + NotificationData.Entry groupSummary = mGroupManager.getGroupSummary(row.getStatusBarNotification()); - if (groupSummary != null && groupSummary != row) { + if (groupSummary != null && groupSummary.getRow() != row) { return row.getVisibility() == View.INVISIBLE; } } @@ -2761,7 +2759,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void onViewAdded(View child) { super.onViewAdded(child); - onViewAddedInternal(child); + onViewAddedInternal((ExpandableView) child); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @@ -2831,31 +2829,28 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void onViewAddedInternal(View child) { + private void onViewAddedInternal(ExpandableView child) { updateHideSensitiveForChild(child); - ((ExpandableView) child).setOnHeightChangedListener(this); + child.setOnHeightChangedListener(this); generateAddAnimation(child, false /* fromMoreCard */); updateAnimationState(child); updateChronometerForChild(child); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void updateHideSensitiveForChild(View child) { - if (child instanceof ExpandableView) { - ExpandableView expandableView = (ExpandableView) child; - expandableView.setHideSensitiveForIntrinsicHeight(mAmbientState.isHideSensitive()); - } + private void updateHideSensitiveForChild(ExpandableView child) { + child.setHideSensitiveForIntrinsicHeight(mAmbientState.isHideSensitive()); } @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void notifyGroupChildRemoved(View row, ViewGroup childrenContainer) { + public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) { onViewRemovedInternal(row, childrenContainer); } @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void notifyGroupChildAdded(View row) { + public void notifyGroupChildAdded(ExpandableView row) { onViewAddedInternal(row); } @@ -2927,7 +2922,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void generateAddAnimation(View child, boolean fromMoreCard) { + public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) { if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress) { // Generate Animations mChildrenToAddAnimated.add(child); @@ -2944,7 +2939,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void changeViewPosition(View child, int newIndex) { + public void changeViewPosition(ExpandableView child, int newIndex) { int currentIndex = indexOfChild(child); if (currentIndex == -1) { @@ -2983,8 +2978,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } if (!mAnimationEvents.isEmpty() || isCurrentlyAnimating()) { setAnimationRunning(true); - mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState, - mGoToFullShadeDelay); + mStateAnimator.startAnimationForEvents(mAnimationEvents, mGoToFullShadeDelay); mAnimationEvents.clear(); updateBackground(); updateViewShadows(); @@ -3031,7 +3025,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd continue; } } else { - ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(row); + ExpandableViewState viewState = row.getViewState(); if (viewState == null) { // A view state was never generated for this view, so we don't need to animate // this. This may happen with notification children. @@ -3097,7 +3091,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void generateChildRemovalEvents() { - for (View child : mChildrenToRemoveAnimated) { + for (ExpandableView child : mChildrenToRemoveAnimated) { boolean childWasSwipedOut = mSwipedOutViews.contains(child); // we need to know the view after this one @@ -3139,7 +3133,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void generatePositionChangeEvents() { - for (View child : mChildrenChangingPositions) { + for (ExpandableView child : mChildrenChangingPositions) { mAnimationEvents.add(new AnimationEvent(child, AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION)); } @@ -3153,7 +3147,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void generateChildAdditionEvents() { - for (View child : mChildrenToAddAnimated) { + for (ExpandableView child : mChildrenToAddAnimated) { if (mFromMoreCardAdditions.contains(child)) { mAnimationEvents.add(new AnimationEvent(child, AnimationEvent.ANIMATION_TYPE_ADD, @@ -3245,7 +3239,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM) protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) { - return new StackScrollAlgorithm(context); + return new StackScrollAlgorithm(context, this); } /** @@ -3910,7 +3904,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mStatusBar.resetUserExpandedStates(); clearTemporaryViews(); clearUserLockedViews(); - ArrayList<View> draggedViews = mAmbientState.getDraggedViews(); + ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews(); if (draggedViews.size() > 0) { draggedViews.clear(); updateContinuousShadowDrawing(); @@ -4194,7 +4188,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void applyCurrentState() { - mCurrentStackScrollState.apply(); + int numChildren = getChildCount(); + for (int i = 0; i < numChildren; i++) { + ExpandableView child = (ExpandableView) getChildAt(i); + child.applyViewState(); + } + if (mListener != null) { mListener.onChildLocationsChanged(); } @@ -4662,6 +4661,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed); } + public void generateHeadsUpAnimation(NotificationData.Entry entry, boolean isHeadsUp) { + ExpandableNotificationRow row = entry.getHeadsUpAnimationView(); + generateHeadsUpAnimation(row, isHeadsUp); + } + @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) { if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) { @@ -4933,8 +4937,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd if (!(child instanceof ExpandableNotificationRow)) { pw.println(" " + child.getClass().getSimpleName()); // Notifications dump it's viewstate as part of their dump to support children - ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView( - child); + ExpandableViewState viewState = child.getViewState(); if (viewState == null) { pw.println(" no viewState!!!"); } else { @@ -4951,7 +4954,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ExpandableView child = (ExpandableView) getTransientView(i); child.dump(fd, pw, args); } - ArrayList<View> draggedViews = mAmbientState.getDraggedViews(); + ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews(); int draggedCount = draggedViews.size(); pw.println(" Dragged Views: " + draggedCount); for (int i = 0; i < draggedCount; i++) { @@ -5487,7 +5490,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2; final long eventStartTime; - final View changingView; + final ExpandableView mChangingView; final int animationType; final AnimationFilter filter; final long length; @@ -5495,21 +5498,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd int darkAnimationOriginIndex; boolean headsUpFromBottom; - AnimationEvent(View view, int type) { + AnimationEvent(ExpandableView view, int type) { this(view, type, LENGTHS[type]); } - AnimationEvent(View view, int type, AnimationFilter filter) { + AnimationEvent(ExpandableView view, int type, AnimationFilter filter) { this(view, type, LENGTHS[type], filter); } - AnimationEvent(View view, int type, long length) { + AnimationEvent(ExpandableView view, int type, long length) { this(view, type, length, FILTERS[type]); } - AnimationEvent(View view, int type, long length, AnimationFilter filter) { + AnimationEvent(ExpandableView view, int type, long length, AnimationFilter filter) { eventStartTime = AnimationUtils.currentAnimationTimeMillis(); - changingView = view; + mChangingView = view; animationType = type; this.length = length; this.filter = filter; @@ -5692,7 +5695,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd && (parent.areGutsExposed() || mSwipeHelper.getExposedMenuView() == parent || (parent.getNotificationChildren().size() == 1 - && parent.isClearable()))) { + && parent.getEntry().isClearable()))) { // In this case the group is expanded and showing the menu for the // group, further interaction should apply to the group, not any // child notifications so we use the parent of the child. We also do the same @@ -5707,7 +5710,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public void onBeginDrag(View v) { mFalsingManager.onNotificatonStartDismissing(); setSwipingInProgress(true); - mAmbientState.onBeginDrag(v); + mAmbientState.onBeginDrag((ExpandableView) v); updateContinuousShadowDrawing(); requestChildrenUpdate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 87c361af9f66..25fb7f9197e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -42,6 +42,7 @@ import java.util.List; public class StackScrollAlgorithm { private static final String LOG_TAG = "StackScrollAlgorithm"; + private final ViewGroup mHostView; private int mPaddingBetweenElements; private int mIncreasedPaddingBetweenElements; @@ -55,7 +56,8 @@ public class StackScrollAlgorithm { private float mHeadsUpInset; private int mPinnedZTranslationExtra; - public StackScrollAlgorithm(Context context) { + public StackScrollAlgorithm(Context context, ViewGroup hostView) { + mHostView = hostView; initView(context); } @@ -79,49 +81,59 @@ public class StackScrollAlgorithm { mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height); } - public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) { + /** + * Updates the state of all children in the hostview based on this algorithm. + */ + public void resetViewStates(AmbientState ambientState) { // The state of the local variables are saved in an algorithmState to easily subdivide it // into multiple phases. StackScrollAlgorithmState algorithmState = mTempAlgorithmState; // First we reset the view states to their default values. - resultState.resetViewStates(); + resetChildViewStates(); - initAlgorithmState(resultState, algorithmState, ambientState); + initAlgorithmState(mHostView, algorithmState, ambientState); - updatePositionsForState(resultState, algorithmState, ambientState); + updatePositionsForState(algorithmState, ambientState); - updateZValuesForState(resultState, algorithmState, ambientState); + updateZValuesForState(algorithmState, ambientState); - updateHeadsUpStates(resultState, algorithmState, ambientState); + updateHeadsUpStates(algorithmState, ambientState); - updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState); - updateClipping(resultState, algorithmState, ambientState); - updateSpeedBumpState(resultState, algorithmState, ambientState); - updateShelfState(resultState, ambientState); - getNotificationChildrenStates(resultState, algorithmState, ambientState); + updateDimmedActivatedHideSensitive(ambientState, algorithmState); + updateClipping(algorithmState, ambientState); + updateSpeedBumpState(algorithmState, ambientState); + updateShelfState(ambientState); + getNotificationChildrenStates(algorithmState, ambientState); } - private void getNotificationChildrenStates(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, + private void resetChildViewStates() { + int numChildren = mHostView.getChildCount(); + for (int i = 0; i < numChildren; i++) { + ExpandableView child = (ExpandableView) mHostView.getChildAt(i); + child.resetViewState(); + } + } + + private void getNotificationChildrenStates(StackScrollAlgorithmState algorithmState, AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { ExpandableView v = algorithmState.visibleChildren.get(i); if (v instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) v; - row.getChildrenStates(resultState, ambientState); + row.updateChildrenStates(ambientState); } } } - private void updateSpeedBumpState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateSpeedBumpState(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); int belowSpeedBump = ambientState.getSpeedBumpIndex(); for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableView child = algorithmState.visibleChildren.get(i); + ExpandableViewState childViewState = child.getViewState(); // The speed bump can also be gone, so equality needs to be taken when comparing // indices. @@ -129,15 +141,16 @@ public class StackScrollAlgorithm { } } - private void updateShelfState(StackScrollState resultState, AmbientState ambientState) { + + private void updateShelfState(AmbientState ambientState) { NotificationShelf shelf = ambientState.getShelf(); if (shelf != null) { - shelf.updateState(resultState, ambientState); + shelf.updateState(ambientState); } } - private void updateClipping(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateClipping(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding() + ambientState.getStackTranslation() + ambientState.getExpandAnimationTopChange() : 0; @@ -146,7 +159,7 @@ public class StackScrollAlgorithm { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { ExpandableView child = algorithmState.visibleChildren.get(i); - ExpandableViewState state = resultState.getViewStateForView(child); + ExpandableViewState state = child.getViewState(); if (!child.mustStayOnScreen() || state.headsUpIsVisible) { previousNotificationEnd = Math.max(drawStart, previousNotificationEnd); previousNotificationStart = Math.max(drawStart, previousNotificationStart); @@ -190,15 +203,15 @@ public class StackScrollAlgorithm { * Updates the dimmed, activated and hiding sensitive states of the children. */ private void updateDimmedActivatedHideSensitive(AmbientState ambientState, - StackScrollState resultState, StackScrollAlgorithmState algorithmState) { + StackScrollAlgorithmState algorithmState) { boolean dimmed = ambientState.isDimmed(); boolean dark = ambientState.isFullyDark(); boolean hideSensitive = ambientState.isHideSensitive(); View activatedChild = ambientState.getActivatedChild(); int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableView child = algorithmState.visibleChildren.get(i); + ExpandableViewState childViewState = child.getViewState(); childViewState.dimmed = dimmed; childViewState.dark = dark; childViewState.hideSensitive = hideSensitive; @@ -212,7 +225,7 @@ public class StackScrollAlgorithm { /** * Initialize the algorithm state like updating the visible children. */ - private void initAlgorithmState(StackScrollState resultState, StackScrollAlgorithmState state, + private void initAlgorithmState(ViewGroup hostView, StackScrollAlgorithmState state, AmbientState ambientState) { float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */); @@ -224,7 +237,6 @@ public class StackScrollAlgorithm { state.scrollY = (int) (scrollY + bottomOverScroll); //now init the visible children and update paddings - ViewGroup hostView = resultState.getHostView(); int childCount = hostView.getChildCount(); state.visibleChildren.clear(); state.visibleChildren.ensureCapacity(childCount); @@ -249,7 +261,7 @@ public class StackScrollAlgorithm { // we need normal padding now, to be in sync with what the stack calculates lastView = null; } - notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v); + notGoneIndex = updateNotGoneIndex(state, notGoneIndex, v); float increasedPadding = v.getIncreasedPaddingAmount(); if (increasedPadding != 0.0f) { state.paddingMap.put(v, increasedPadding); @@ -282,13 +294,11 @@ public class StackScrollAlgorithm { ExpandableNotificationRow row = (ExpandableNotificationRow) v; // handle the notgoneIndex for the children as well - List<ExpandableNotificationRow> children = - row.getNotificationChildren(); + List<ExpandableNotificationRow> children = row.getNotificationChildren(); if (row.isSummaryWithChildren() && children != null) { for (ExpandableNotificationRow childRow : children) { if (childRow.getVisibility() != View.GONE) { - ExpandableViewState childState - = resultState.getViewStateForView(childRow); + ExpandableViewState childState = childRow.getViewState(); childState.notGoneIndex = notGoneIndex; notGoneIndex++; } @@ -301,8 +311,8 @@ public class StackScrollAlgorithm { ExpandableNotificationRow expandingNotification = ambientState.getExpandingNotification(); state.indexOfExpandingNotification = expandingNotification != null ? expandingNotification.isChildInGroup() - ? state.visibleChildren.indexOf(expandingNotification.getNotificationParent()) - : state.visibleChildren.indexOf(expandingNotification) + ? state.visibleChildren.indexOf(expandingNotification.getNotificationParent()) + : state.visibleChildren.indexOf(expandingNotification) : -1; } @@ -322,10 +332,9 @@ public class StackScrollAlgorithm { } } - private int updateNotGoneIndex(StackScrollState resultState, - StackScrollAlgorithmState state, int notGoneIndex, + private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex, ExpandableView v) { - ExpandableViewState viewState = resultState.getViewStateForView(v); + ExpandableViewState viewState = v.getViewState(); viewState.notGoneIndex = notGoneIndex; state.visibleChildren.add(v); notGoneIndex++; @@ -335,27 +344,27 @@ public class StackScrollAlgorithm { /** * Determine the positions for the views. This is the main part of the algorithm. * - * @param resultState The result state to update if a change to the properties of a child occurs * @param algorithmState The state in which the current pass of the algorithm is currently in - * @param ambientState The current ambient state + * @param ambientState The current ambient state */ - private void updatePositionsForState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updatePositionsForState(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { // The y coordinate of the current child. float currentYPosition = -algorithmState.scrollY; int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { - currentYPosition = updateChild(i, resultState, algorithmState, ambientState, - currentYPosition); + currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition); } } - protected float updateChild(int i, StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState, + protected float updateChild( + int i, + StackScrollAlgorithmState algorithmState, + AmbientState ambientState, float currentYPosition) { ExpandableView child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableViewState childViewState = child.getViewState(); childViewState.location = ExpandableViewState.LOCATION_UNKNOWN; int paddingAfterChild = getPaddingAfterChild(algorithmState, child); int childHeight = getMaxAllowedChildHeight(child); @@ -404,8 +413,8 @@ public class StackScrollAlgorithm { return algorithmState.getPaddingAfterChild(child); } - private void updateHeadsUpStates(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateHeadsUpStates(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); ExpandableNotificationRow topHeadsUpEntry = null; for (int i = 0; i < childCount; i++) { @@ -417,7 +426,7 @@ public class StackScrollAlgorithm { if (!row.isHeadsUp()) { break; } - ExpandableViewState childState = resultState.getViewStateForView(row); + ExpandableViewState childState = row.getViewState(); if (topHeadsUpEntry == null && row.mustStayOnScreen() && !childState.headsUpIsVisible) { topHeadsUpEntry = row; childState.location = ExpandableViewState.LOCATION_FIRST_HUN; @@ -439,7 +448,8 @@ public class StackScrollAlgorithm { childState.yTranslation = Math.max(childState.yTranslation, mHeadsUpInset); childState.height = Math.max(row.getIntrinsicHeight(), childState.height); childState.hidden = false; - ExpandableViewState topState = resultState.getViewStateForView(topHeadsUpEntry); + ExpandableViewState topState = + topHeadsUpEntry == null ? null : topHeadsUpEntry.getViewState(); if (topState != null && !isTopEntry && (!mIsExpanded || unmodifiedEndLocation < topState.yTranslation + topState.height)) { // Ensure that a headsUp doesn't vertically extend further than the heads-up at @@ -491,9 +501,8 @@ public class StackScrollAlgorithm { * Clamp the height of the child down such that its end is at most on the beginning of * the shelf. * - * @param child * @param childViewState the view state of the child - * @param ambientState the ambient state + * @param ambientState the ambient state */ private void clampPositionToShelf(ExpandableView child, ExpandableViewState childViewState, @@ -521,31 +530,31 @@ public class StackScrollAlgorithm { ExpandableView expandableView = (ExpandableView) child; return expandableView.getIntrinsicHeight(); } - return child == null? mCollapsedSize : child.getHeight(); + return child == null ? mCollapsedSize : child.getHeight(); } /** * Calculate the Z positions for all children based on the number of items in both stacks and * save it in the resultState - * @param resultState The result state to update the zTranslation values + * * @param algorithmState The state in which the current pass of the algorithm is currently in - * @param ambientState The ambient state of the algorithm + * @param ambientState The ambient state of the algorithm */ - private void updateZValuesForState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateZValuesForState(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); float childrenOnTop = 0.0f; for (int i = childCount - 1; i >= 0; i--) { childrenOnTop = updateChildZValue(i, childrenOnTop, - resultState, algorithmState, ambientState); + algorithmState, ambientState); } } protected float updateChildZValue(int i, float childrenOnTop, - StackScrollState resultState, StackScrollAlgorithmState algorithmState, + StackScrollAlgorithmState algorithmState, AmbientState ambientState) { ExpandableView child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableViewState childViewState = child.getViewState(); int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements(); float baseZ = ambientState.getBaseZHeight(); if (child.mustStayOnScreen() && !childViewState.headsUpIsVisible diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollState.java deleted file mode 100644 index e55707ce10d9..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollState.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.notification.stack; - -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; - -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableView; - -import java.util.List; -import java.util.WeakHashMap; - -/** - * A state of a - * {@link com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout} which - * can be applied to a viewGroup. - */ -public class StackScrollState { - - private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild"; - - private final ViewGroup mHostView; - private WeakHashMap<ExpandableView, ExpandableViewState> mStateMap; - - public StackScrollState(ViewGroup hostView) { - mHostView = hostView; - mStateMap = new WeakHashMap<>(); - } - - public ViewGroup getHostView() { - return mHostView; - } - - public void resetViewStates() { - int numChildren = mHostView.getChildCount(); - for (int i = 0; i < numChildren; i++) { - ExpandableView child = (ExpandableView) mHostView.getChildAt(i); - resetViewState(child); - - // handling reset for child notifications - if (child instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) child; - List<ExpandableNotificationRow> children = - row.getNotificationChildren(); - if (row.isSummaryWithChildren() && children != null) { - for (ExpandableNotificationRow childRow : children) { - resetViewState(childRow); - } - } - } - } - } - - private void resetViewState(ExpandableView view) { - ExpandableViewState viewState = mStateMap.get(view); - if (viewState == null) { - viewState = view.createNewViewState(this); - mStateMap.put(view, viewState); - } - // initialize with the default values of the view - viewState.height = view.getIntrinsicHeight(); - viewState.gone = view.getVisibility() == View.GONE; - viewState.alpha = 1f; - viewState.notGoneIndex = -1; - viewState.xTranslation = view.getTranslationX(); - viewState.hidden = false; - viewState.scaleX = view.getScaleX(); - viewState.scaleY = view.getScaleY(); - viewState.inShelf = false; - viewState.headsUpIsVisible = false; - } - - public ExpandableViewState getViewStateForView(View requestedView) { - return mStateMap.get(requestedView); - } - - public void removeViewStateForView(View child) { - mStateMap.remove(child); - } - - /** - * Apply the properties saved in {@link #mStateMap} to the children of the {@link #mHostView}. - * The properties are only applied if they effectively changed. - */ - public void apply() { - int numChildren = mHostView.getChildCount(); - for (int i = 0; i < numChildren; i++) { - ExpandableView child = (ExpandableView) mHostView.getChildAt(i); - ExpandableViewState state = mStateMap.get(child); - if (state == null) { - Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " + - "to the hostView"); - continue; - } - if (state.gone) { - continue; - } - state.applyToView(child); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index 34dab53d4869..713bd90b30c3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -128,25 +128,25 @@ public class StackStateAnimator { public void startAnimationForEvents( ArrayList<NotificationStackScrollLayout.AnimationEvent> mAnimationEvents, - StackScrollState finalState, long additionalDelay) { + long additionalDelay) { - processAnimationEvents(mAnimationEvents, finalState); + processAnimationEvents(mAnimationEvents); int childCount = mHostLayout.getChildCount(); mAnimationFilter.applyCombination(mNewEvents); mCurrentAdditionalDelay = additionalDelay; mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents); - mCurrentLastNotAddedIndex = findLastNotAddedIndex(finalState); + mCurrentLastNotAddedIndex = findLastNotAddedIndex(); for (int i = 0; i < childCount; i++) { final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); - ExpandableViewState viewState = finalState.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); if (viewState == null || child.getVisibility() == View.GONE - || applyWithoutAnimation(child, viewState, finalState)) { + || applyWithoutAnimation(child, viewState)) { continue; } - initAnimationProperties(finalState, child, viewState); + initAnimationProperties(child, viewState); viewState.animateTo(child, mAnimationProperties); } if (!isRunning()) { @@ -159,7 +159,7 @@ public class StackStateAnimator { mNewAddChildren.clear(); } - private void initAnimationProperties(StackScrollState finalState, ExpandableView child, + private void initAnimationProperties(ExpandableView child, ExpandableViewState viewState) { boolean wasAdded = mAnimationProperties.wasAdded(child); mAnimationProperties.duration = mCurrentLength; @@ -173,7 +173,7 @@ public class StackStateAnimator { || viewState.clipTopAmount != child.getClipTopAmount() || viewState.dark != child.isDark())) { mAnimationProperties.delay = mCurrentAdditionalDelay - + calculateChildAnimationDelay(viewState, finalState); + + calculateChildAnimationDelay(viewState); } } @@ -193,8 +193,7 @@ public class StackStateAnimator { * * @return true if no animation should be performed */ - private boolean applyWithoutAnimation(ExpandableView child, ExpandableViewState viewState, - StackScrollState finalState) { + private boolean applyWithoutAnimation(ExpandableView child, ExpandableViewState viewState) { if (mShadeExpanded) { return false; } @@ -214,12 +213,12 @@ public class StackStateAnimator { return true; } - private int findLastNotAddedIndex(StackScrollState finalState) { + private int findLastNotAddedIndex() { int childCount = mHostLayout.getChildCount(); for (int i = childCount - 1; i >= 0; i--) { final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); - ExpandableViewState viewState = finalState.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); if (viewState == null || child.getVisibility() == View.GONE) { continue; } @@ -230,8 +229,7 @@ public class StackStateAnimator { return -1; } - private long calculateChildAnimationDelay(ExpandableViewState viewState, - StackScrollState finalState) { + private long calculateChildAnimationDelay(ExpandableViewState viewState) { if (mAnimationFilter.hasGoToFullShadeEvent) { return calculateDelayGoToFullShade(viewState); } @@ -244,8 +242,8 @@ public class StackStateAnimator { switch (event.animationType) { case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD: { int ownIndex = viewState.notGoneIndex; - int changingIndex = finalState - .getViewStateForView(event.changingView).notGoneIndex; + int changingIndex = + ((ExpandableView) (event.mChangingView)).getViewState().notGoneIndex; int difference = Math.abs(ownIndex - changingIndex); difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE, difference - 1)); @@ -258,9 +256,9 @@ public class StackStateAnimator { case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE: { int ownIndex = viewState.notGoneIndex; boolean noNextView = event.viewAfterChangingView == null; - View viewAfterChangingView = noNextView + ExpandableView viewAfterChangingView = noNextView ? mHostLayout.getLastChildNotGone() - : event.viewAfterChangingView; + : (ExpandableView) event.viewAfterChangingView; if (viewAfterChangingView == null) { // This can happen when the last view in the list is removed. // Since the shelf is still around and the only view, the code still goes @@ -268,8 +266,7 @@ public class StackStateAnimator { // have changed. continue; } - int nextIndex = finalState - .getViewStateForView(viewAfterChangingView).notGoneIndex; + int nextIndex = viewAfterChangingView.getViewState().notGoneIndex; if (ownIndex >= nextIndex) { // we only have the view afterwards ownIndex++; @@ -351,20 +348,17 @@ public class StackStateAnimator { /** * Process the animationEvents for a new animation * - * @param animationEvents the animation events for the animation to perform - * @param finalState the final state to animate to + * @param animationEvents the animation events for the animation to perform */ private void processAnimationEvents( - ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents, - StackScrollState finalState) { + ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents) { for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) { - final ExpandableView changingView = (ExpandableView) event.changingView; + final ExpandableView changingView = (ExpandableView) event.mChangingView; if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) { // This item is added, initialize it's properties. - ExpandableViewState viewState = finalState - .getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); if (viewState == null || viewState.gone) { // The position for this child was never generated, let's continue. continue; @@ -381,8 +375,8 @@ public class StackStateAnimator { // Find the amount to translate up. This is needed in order to understand the // direction of the remove animation (either downwards or upwards) - ExpandableViewState viewState = finalState - .getViewStateForView(event.viewAfterChangingView); + ExpandableViewState viewState = + ((ExpandableView) event.viewAfterChangingView).getViewState(); int actualHeight = changingView.getActualHeight(); // upwards by default float translationDirection = -1.0f; @@ -426,11 +420,11 @@ public class StackStateAnimator { } } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) { - ExpandableNotificationRow row = (ExpandableNotificationRow) event.changingView; - row.prepareExpansionChanged(finalState); + ExpandableNotificationRow row = (ExpandableNotificationRow) event.mChangingView; + row.prepareExpansionChanged(); } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR) { - ExpandableViewState viewState = finalState.getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); if (viewState != null) { mTmpState.copyFrom(viewState); mTmpState.yTranslation += mPulsingAppearingTranslation; @@ -439,7 +433,7 @@ public class StackStateAnimator { } } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) { - ExpandableViewState viewState = finalState.getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); if (viewState != null) { viewState.alpha = 0; // We want to animate the alpha away before the view starts translating, @@ -454,7 +448,7 @@ public class StackStateAnimator { } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) { // This item is added, initialize it's properties. - ExpandableViewState viewState = finalState.getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); mTmpState.copyFrom(viewState); if (event.headsUpFromBottom) { mTmpState.yTranslation = mHeadsUpAppearHeightBottom; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index 40f9f45bf8bb..3c8cad7cb60b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -143,9 +143,9 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } @Override - public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { + public void onHeadsUpPinned(NotificationData.Entry entry) { updateTopEntry(); - updateHeader(headsUp.getEntry()); + updateHeader(entry); } /** To count the distance from the window right boundary to scroller right boundary. The @@ -298,9 +298,9 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } @Override - public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { + public void onHeadsUpUnPinned(NotificationData.Entry entry) { updateTopEntry(); - updateHeader(headsUp.getEntry()); + updateHeader(entry); } public void setExpandedHeight(float expandedHeight, float appearFraction) { @@ -339,7 +339,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } public void updateHeader(NotificationData.Entry entry) { - ExpandableNotificationRow row = entry.row; + ExpandableNotificationRow row = entry.getRow(); float headerVisibleAmount = 1.0f; if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) { headerVisibleAmount = mExpandFraction; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 00d6b14f50c5..9faada05294b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -304,18 +304,19 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, return; } if (hasPinnedHeadsUp()) { - ExpandableNotificationRow topEntry = getTopEntry().row; + NotificationData.Entry topEntry = getTopEntry(); if (topEntry.isChildInGroup()) { - final ExpandableNotificationRow groupSummary - = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification()); + final NotificationData.Entry groupSummary + = mGroupManager.getGroupSummary(topEntry.notification); if (groupSummary != null) { topEntry = groupSummary; } } - topEntry.getLocationOnScreen(mTmpTwoArray); + ExpandableNotificationRow topRow = topEntry.getRow(); + topRow.getLocationOnScreen(mTmpTwoArray); int minX = mTmpTwoArray[0]; - int maxX = mTmpTwoArray[0] + topEntry.getWidth(); - int height = topEntry.getIntrinsicHeight(); + int maxX = mTmpTwoArray[0] + topRow.getWidth(); + int height = topRow.getIntrinsicHeight(); info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(minX, 0, maxX, mHeadsUpInset + height); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index be4df458ecb9..9c1c71a2dec8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -84,8 +84,8 @@ public class HeadsUpTouchHelper implements Gefingerpoken { // We might touch above the visible heads up child, but then we still would // like to capture it. NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry(); - if (topEntry != null && topEntry.row.isPinned()) { - mPickedChild = topEntry.row; + if (topEntry != null && topEntry.isRowPinned()) { + mPickedChild = topEntry.getRow(); mTouchingHeadsUpView = true; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index d8280baa4e74..a81b7e572a79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -22,6 +22,7 @@ import static com.android.systemui.statusbar.notification.NotificationUtils.inte import android.content.res.Resources; import android.util.MathUtils; +import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -229,6 +230,11 @@ public class KeyguardClockPositionAlgorithm { - mBurnInPreventionOffsetX; } + @VisibleForTesting + void setPulsingPadding(int padding) { + mPulsingPadding = padding; + } + public static class Result { /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 0cf1b3ddc213..8657003891be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -56,7 +56,6 @@ import android.telecom.TelecomManager; import android.text.TextUtils; import android.util.Log; import android.view.Display; -import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -863,16 +862,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { public static View create(Context context, FragmentListener listener) { final int displayId = context.getDisplay().getDisplayId(); - final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); - final int height = isDefaultDisplay - ? LayoutParams.MATCH_PARENT - : context.getResources().getDimensionPixelSize(R.dimen.navigation_bar_height); WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - LayoutParams.MATCH_PARENT, height, - // TODO(b/117478341): Resolve one status bar/ navigation bar assumption - isDefaultDisplay - ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR - : WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL @@ -884,10 +876,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks { lp.setTitle("NavigationBar" + displayId); lp.accessibilityTitle = context.getString(R.string.nav_bar); lp.windowAnimations = 0; - if (!isDefaultDisplay) { - lp.flags |= LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; - lp.gravity = Gravity.BOTTOM; - } View navigationBarView = LayoutInflater.from(context).inflate( R.layout.navigation_bar_window, null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index c74514e05b20..3e31fa06ef27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -198,7 +198,7 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen alertNotificationWhenPossible(entry, getActiveAlertManager()); } else { // The transfer is no longer valid. Free the content. - entry.row.freeContentViewWhenSafe(alertInfo.mAlertManager.getContentFlag()); + entry.getRow().freeContentViewWhenSafe(alertInfo.mAlertManager.getContentFlag()); } } } @@ -299,9 +299,9 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen Entry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next(); if (child != null) { - if (child.row.keepInParent() - || child.row.isRemoved() - || child.row.isDismissed()) { + if (child.getRow().keepInParent() + || child.isRowRemoved() + || child.isRowDismissed()) { // The notification is actually already removed. No need to alert it. return; } @@ -390,10 +390,10 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen private void alertNotificationWhenPossible(@NonNull Entry entry, @NonNull AlertingNotificationManager alertManager) { @InflationFlag int contentFlag = alertManager.getContentFlag(); - if (!entry.row.isInflationFlagSet(contentFlag)) { + if (!entry.getRow().isInflationFlagSet(contentFlag)) { mPendingAlerts.put(entry.key, new PendingAlertInfo(entry, alertManager)); - entry.row.updateInflationFlag(contentFlag, true /* shouldInflate */); - entry.row.inflateViews(); + entry.getRow().updateInflationFlag(contentFlag, true /* shouldInflate */); + entry.getRow().inflateViews(); return; } if (alertManager.isAlerting(entry.key)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index 8ceabf809df8..448b5c38da51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -87,8 +87,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, group.expanded = expanded; if (group.summary != null) { for (OnGroupChangeListener listener : mListeners) { - listener.onGroupExpansionChanged(group.summary.row, - expanded); + listener.onGroupExpansionChanged(group.summary.getRow(), expanded); } } } @@ -133,7 +132,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } public void onEntryAdded(final NotificationData.Entry added) { - if (added.row.isRemoved()) { + if (added.isRowRemoved()) { added.setDebugThrowable(new Throwable()); } final StatusBarNotification sbn = added.notification; @@ -152,17 +151,17 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, if (existing != null && existing != added) { Throwable existingThrowable = existing.getDebugThrowable(); Log.wtf(TAG, "Inconsistent entries found with the same key " + added.key - + "existing removed: " + existing.row.isRemoved() + + "existing removed: " + existing.isRowRemoved() + (existingThrowable != null ? Log.getStackTraceString(existingThrowable) + "\n": "") - + " added removed" + added.row.isRemoved() + + " added removed" + added.isRowRemoved() , new Throwable()); } group.children.put(added.key, added); updateSuppression(group); } else { group.summary = added; - group.expanded = added.row.areChildrenExpanded(); + group.expanded = added.areChildrenExpanded(); updateSuppression(group); if (!group.children.isEmpty()) { ArrayList<NotificationData.Entry> childrenCopy @@ -263,9 +262,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, if (!isOnlyChild(sbn)) { return false; } - ExpandableNotificationRow logicalGroupSummary = getLogicalGroupSummary(sbn); + NotificationData.Entry logicalGroupSummary = getLogicalGroupSummary(sbn); return logicalGroupSummary != null - && !logicalGroupSummary.getStatusBarNotification().equals(sbn); + && !logicalGroupSummary.notification.equals(sbn); } private int getTotalNumberOfChildren(StatusBarNotification sbn) { @@ -339,7 +338,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * Get the summary of a specified status bar notification. For isolated notification this return * itself. */ - public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) { + public NotificationData.Entry getGroupSummary(StatusBarNotification sbn) { return getGroupSummary(getGroupKey(sbn)); } @@ -348,16 +347,17 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * but the logical summary, i.e when a child is isolated, it still returns the summary as if * it wasn't isolated. */ - public ExpandableNotificationRow getLogicalGroupSummary(StatusBarNotification sbn) { + public NotificationData.Entry getLogicalGroupSummary(StatusBarNotification sbn) { return getGroupSummary(sbn.getGroupKey()); } @Nullable - private ExpandableNotificationRow getGroupSummary(String groupKey) { + private NotificationData.Entry getGroupSummary(String groupKey) { NotificationGroup group = mGroupMap.get(groupKey); + //TODO: see if this can become an Entry return group == null ? null : group.summary == null ? null - : group.summary.row; + : group.summary; } /** @@ -438,11 +438,11 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } @Override - public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { + public void onHeadsUpPinned(NotificationData.Entry entry) { } @Override - public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { + public void onHeadsUpUnPinned(NotificationData.Entry entry) { } @Override @@ -533,8 +533,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, private boolean isGroupNotFullyVisible(NotificationGroup notificationGroup) { return notificationGroup.summary == null - || notificationGroup.summary.row.getClipTopAmount() > 0 - || notificationGroup.summary.row.getTranslationY() < 0; + || notificationGroup.summary.isGroupNotFullyVisible(); } public void setHeadsUpManager(HeadsUpManager headsUpManager) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 184766c6c7a3..2d5d56274640 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -192,13 +192,13 @@ public class NotificationIconAreaController implements DarkReceiver { && !mEntryManager.getNotificationData().isHighPriority(entry.notification)) { return false; } - if (!StatusBar.isTopLevelChild(entry)) { + if (!entry.isTopLevelChild()) { return false; } - if (entry.row.getVisibility() == View.GONE) { + if (entry.getRow().getVisibility() == View.GONE) { return false; } - if (entry.row.isDismissed() && hideDismissed) { + if (entry.isRowDismissed() && hideDismissed) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 851e6d0b4dea..33d176a580da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -2500,25 +2500,26 @@ public class NotificationPanelView extends PanelView implements } @Override - public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { - mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true); + public void onHeadsUpPinned(NotificationData.Entry entry) { + mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), true); } @Override - public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { + public void onHeadsUpUnPinned(NotificationData.Entry entry) { // When we're unpinning the notification via active edge they remain heads-upped, // we need to make sure that an animation happens in this case, otherwise the notification // will stick to the top without any interaction. - if (isFullyCollapsed() && headsUp.isHeadsUp()) { - mNotificationStackScroller.generateHeadsUpAnimation(headsUp, false); - headsUp.setHeadsUpIsVisible(); + if (isFullyCollapsed() && entry.isRowHeadsUp()) { + mNotificationStackScroller.generateHeadsUpAnimation( + entry.getHeadsUpAnimationView(), false); + entry.setHeadsUpIsVisible(); } } @Override public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { - mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp); + mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index bdddf5b9794f..82f9e0340490 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -22,6 +22,7 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.windowStateToString; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static android.view.Display.DEFAULT_DISPLAY; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; @@ -484,7 +485,7 @@ public class StatusBar extends SystemUI implements DemoMode, private Runnable mLaunchTransitionEndRunnable; protected boolean mLaunchTransitionFadingAway; - private ExpandableNotificationRow mDraggedDownRow; + private NotificationData.Entry mDraggedDownEntry; private boolean mLaunchCameraOnScreenTurningOn; private boolean mLaunchCameraOnFinishedGoingToSleep; private int mLastCameraLaunchSource; @@ -843,16 +844,7 @@ public class StatusBar extends SystemUI implements DemoMode, mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager); putComponent(HeadsUpManager.class, mHeadsUpManager); - - try { - boolean showNav = mWindowManagerService.hasNavigationBar(); - if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); - if (showNav) { - createNavigationBar(); - } - } catch (RemoteException ex) { - // no window manager? good luck with that - } + createNavigationBar(); if (ENABLE_LOCKSCREEN_WALLPAPER) { mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler); @@ -1061,13 +1053,24 @@ public class StatusBar extends SystemUI implements DemoMode, } protected void createNavigationBar() { - mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> { - mNavigationBar = (NavigationBarFragment) fragment; - if (mLightBarController != null) { - mNavigationBar.setLightBarController(mLightBarController); - } - mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility); - }); + try { + // TODO(117478341): Move this into DisplayNavigationBarController#createNavigationBars + // for-loop. We will also move the whole navigation bar logic together. + final boolean showNav = mWindowManagerService.hasNavigationBar(DEFAULT_DISPLAY); + if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); + if (!showNav) return; + + mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> { + mNavigationBar = (NavigationBarFragment) fragment; + if (mLightBarController != null) { + mNavigationBar.setLightBarController(mLightBarController); + } + mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility); + }); + } catch (RemoteException ex) { + // no window manager? good luck with that + } + mNavigationBarController.createNavigationBars(); } /** @@ -1265,10 +1268,6 @@ public class StatusBar extends SystemUI implements DemoMode, mQSPanel.clickTile(tile); } - public static boolean isTopLevelChild(Entry entry) { - return entry.row.getParent() instanceof NotificationStackScrollLayout; - } - public boolean areNotificationsHidden() { return mZenController.areNotificationsHiddenInShade(); } @@ -1491,12 +1490,12 @@ public class StatusBar extends SystemUI implements DemoMode, } @Override - public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { + public void onHeadsUpPinned(NotificationData.Entry entry) { dismissVolumeDialog(); } @Override - public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { + public void onHeadsUpUnPinned(NotificationData.Entry entry) { } @Override @@ -2605,9 +2604,7 @@ public class StatusBar extends SystemUI implements DemoMode, final int notificationCount = activeNotifications.size(); for (int i = 0; i < notificationCount; i++) { NotificationData.Entry entry = activeNotifications.get(i); - if (entry.row != null) { - entry.row.resetUserExpansion(); - } + entry.resetUserExpansion(); } } @@ -3038,10 +3035,10 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarStateController.setState(StatusBarState.KEYGUARD); } updatePanelExpansionForKeyguard(); - if (mDraggedDownRow != null) { - mDraggedDownRow.setUserLocked(false); - mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */); - mDraggedDownRow = null; + if (mDraggedDownEntry != null) { + mDraggedDownEntry.setUserLocked(false); + mDraggedDownEntry.notifyHeightChanged(false /* needsAnimation */); + mDraggedDownEntry = null; } } @@ -3181,9 +3178,9 @@ public class StatusBar extends SystemUI implements DemoMode, } long delay = mKeyguardMonitor.calculateGoingToFullShadeDelay(); mNotificationPanel.animateToFullShade(delay); - if (mDraggedDownRow != null) { - mDraggedDownRow.setUserLocked(false); - mDraggedDownRow = null; + if (mDraggedDownEntry != null) { + mDraggedDownEntry.setUserLocked(false); + mDraggedDownEntry = null; } // TODO(115978725): Support animations on external nav bars. @@ -3575,14 +3572,15 @@ public class StatusBar extends SystemUI implements DemoMode, int userId = mLockscreenUserManager.getCurrentUserId(); ExpandableNotificationRow row = null; + NotificationData.Entry entry = null; if (expandView instanceof ExpandableNotificationRow) { - row = (ExpandableNotificationRow) expandView; - row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); + entry = ((ExpandableNotificationRow) expandView).getEntry(); + entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); // Indicate that the group expansion is changing at this time -- this way the group // and children backgrounds / divider animations will look correct. - row.setGroupExpansionChanging(true); - if (row.getStatusBarNotification() != null) { - userId = row.getStatusBarNotification().getUserId(); + entry.setGroupExpansionChanging(true); + if (entry.notification != null) { + userId = entry.notification.getUserId(); } } boolean fullShadeNeedsBouncer = !mLockscreenUserManager. @@ -3592,7 +3590,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); showBouncerIfKeyguard(); - mDraggedDownRow = row; + mDraggedDownEntry = entry; mPendingRemoteInputView = null; } else { mNotificationPanel.animateToFullShade(0 /* delay */); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index edfc0496149b..588c3a8a33ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -418,7 +418,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter { StatusBarNotification parentToCancel = null; if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) { StatusBarNotification summarySbn = - mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification(); + mGroupManager.getLogicalGroupSummary(sbn).notification; if (shouldAutoCancel(summarySbn)) { parentToCancel = summarySbn; } @@ -591,7 +591,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter { public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) { mHeadsUpManager.setExpanded(clickedEntry, nowExpanded); if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) { - mShadeController.goToLockedShade(clickedEntry.row); + mShadeController.goToLockedShade(clickedEntry.getRow()); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index fdab6168d05a..e72806438f54 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -123,15 +123,15 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "setEntryPinned: " + isPinned); } - ExpandableNotificationRow row = headsUpEntry.mEntry.row; - if (row.isPinned() != isPinned) { - row.setPinned(isPinned); + NotificationData.Entry entry = headsUpEntry.mEntry; + if (entry.isRowPinned() != isPinned) { + entry.setRowPinned(isPinned); updatePinnedMode(); for (OnHeadsUpChangedListener listener : mListeners) { if (isPinned) { - listener.onHeadsUpPinned(row); + listener.onHeadsUpPinned(entry); } else { - listener.onHeadsUpUnPinned(row); + listener.onHeadsUpUnPinned(entry); } } } @@ -144,7 +144,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { @Override protected void onAlertEntryAdded(AlertEntry alertEntry) { NotificationData.Entry entry = alertEntry.mEntry; - entry.row.setHeadsUp(true); + entry.setHeadsUp(true); setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry)); for (OnHeadsUpChangedListener listener : mListeners) { listener.onHeadsUpStateChanged(entry, true); @@ -154,12 +154,12 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { @Override protected void onAlertEntryRemoved(AlertEntry alertEntry) { NotificationData.Entry entry = alertEntry.mEntry; - entry.row.setHeadsUp(false); + entry.setHeadsUp(false); setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */); for (OnHeadsUpChangedListener listener : mListeners) { listener.onHeadsUpStateChanged(entry, false); } - entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP); + entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP); } protected void updatePinnedMode() { @@ -282,7 +282,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { private boolean hasPinnedNotificationInternal() { for (String key : mAlertEntries.keySet()) { AlertEntry entry = getHeadsUpEntry(key); - if (entry.mEntry.row.isPinned()) { + if (entry.mEntry.isRowPinned()) { return true; } } @@ -302,10 +302,9 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { // when the user unpinned all of HUNs by moving one HUN, all of HUNs should not stay // on the screen. - if (userUnPinned && entry.mEntry != null && entry.mEntry.row != null) { - ExpandableNotificationRow row = entry.mEntry.row; - if (row.mustStayOnScreen()) { - row.setHeadsUpIsVisible(); + if (userUnPinned && entry.mEntry != null) { + if (entry.mEntry.mustStayOnScreen()) { + entry.mEntry.setHeadsUpIsVisible(); } } } @@ -341,7 +340,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { */ public void setExpanded(@NonNull NotificationData.Entry entry, boolean expanded) { HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key); - if (headsUpEntry != null && entry.row.isPinned()) { + if (headsUpEntry != null && entry.isRowPinned()) { headsUpEntry.setExpanded(expanded); } } @@ -365,15 +364,15 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { @Override protected boolean isSticky() { - return (mEntry.row.isPinned() && expanded) + return (mEntry.isRowPinned() && expanded) || remoteInputActive || hasFullScreenIntent(mEntry); } @Override public int compareTo(@NonNull AlertEntry alertEntry) { HeadsUpEntry headsUpEntry = (HeadsUpEntry) alertEntry; - boolean isPinned = mEntry.row.isPinned(); - boolean otherPinned = headsUpEntry.mEntry.row.isPinned(); + boolean isPinned = mEntry.isRowPinned(); + boolean otherPinned = headsUpEntry.mEntry.isRowPinned(); if (isPinned && !otherPinned) { return -1; } else if (!isPinned && otherPinned) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java index d43476885979..7ad547afdb53 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java @@ -33,12 +33,12 @@ public interface OnHeadsUpChangedListener { /** * A notification was just pinned to the top. */ - default void onHeadsUpPinned(ExpandableNotificationRow headsUp) {} + default void onHeadsUpPinned(NotificationData.Entry entry) {} /** * A notification was just unpinned from the top. */ - default void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {} + default void onHeadsUpUnPinned(NotificationData.Entry entry) {} /** * A notification just became a heads up or turned back to its normal state. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index a485fa89ebe8..866015e84af0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -245,7 +245,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - if (mEntry.row.isChangingPosition()) { + if (mEntry.getRow().isChangingPosition()) { if (getVisibility() == VISIBLE && mEditText.isFocusable()) { mEditText.requestFocus(); } @@ -255,7 +255,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (mEntry.row.isChangingPosition() || isTemporarilyDetached()) { + if (mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) { return; } mController.removeRemoteInput(mEntry, mToken); @@ -495,7 +495,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene } private void defocusIfNeeded(boolean animate) { - if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition() + if (mRemoteInputView != null && mRemoteInputView.mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) { if (isTemporarilyDetached()) { // We might get reattached but then the other one of HUN / expanded might steal diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 018668377a50..88ff0780c974 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -1,6 +1,7 @@ package com.android.systemui.statusbar.policy; import android.annotation.ColorInt; +import android.annotation.NonNull; import android.app.Notification; import android.app.PendingIntent; import android.app.RemoteInput; @@ -189,15 +190,13 @@ public class SmartReplyView extends ViewGroup { * into the notification are shown. */ public void addRepliesFromRemoteInput( - RemoteInput remoteInput, PendingIntent pendingIntent, - SmartReplyController smartReplyController, NotificationData.Entry entry, - CharSequence[] choices) { - if (remoteInput != null && pendingIntent != null) { - if (choices != null) { - for (int i = 0; i < choices.length; ++i) { + SmartReplies smartReplies, + SmartReplyController smartReplyController, NotificationData.Entry entry) { + if (smartReplies.remoteInput != null && smartReplies.pendingIntent != null) { + if (smartReplies.choices != null) { + for (int i = 0; i < smartReplies.choices.length; ++i) { Button replyButton = inflateReplyButton( - getContext(), this, i, choices[i], remoteInput, pendingIntent, - smartReplyController, entry); + getContext(), this, i, smartReplies, smartReplyController, entry); addView(replyButton); } } @@ -209,10 +208,10 @@ public class SmartReplyView extends ViewGroup { * Add smart actions to be shown next to smart replies. Only the actions that fit into the * notification are shown. */ - public void addSmartActions(List<Notification.Action> smartActions) { - int numSmartActions = smartActions.size(); + public void addSmartActions(SmartActions smartActions) { + int numSmartActions = smartActions.actions.size(); for (int n = 0; n < numSmartActions; n++) { - Notification.Action action = smartActions.get(n); + Notification.Action action = smartActions.actions.get(n); if (action.actionIntent != null) { Button actionButton = inflateActionButton(getContext(), this, action); addView(actionButton); @@ -228,22 +227,25 @@ public class SmartReplyView extends ViewGroup { @VisibleForTesting Button inflateReplyButton(Context context, ViewGroup root, int replyIndex, - CharSequence choice, RemoteInput remoteInput, PendingIntent pendingIntent, - SmartReplyController smartReplyController, NotificationData.Entry entry) { + SmartReplies smartReplies, SmartReplyController smartReplyController, + NotificationData.Entry entry) { Button b = (Button) LayoutInflater.from(context).inflate( R.layout.smart_reply_button, root, false); + CharSequence choice = smartReplies.choices[replyIndex]; b.setText(choice); OnDismissAction action = () -> { - smartReplyController.smartReplySent(entry, replyIndex, b.getText()); + smartReplyController.smartReplySent( + entry, replyIndex, b.getText(), smartReplies.fromAssistant); Bundle results = new Bundle(); - results.putString(remoteInput.getResultKey(), choice.toString()); + results.putString(smartReplies.remoteInput.getResultKey(), choice.toString()); Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - RemoteInput.addResultsToIntent(new RemoteInput[]{remoteInput}, intent, results); + RemoteInput.addResultsToIntent(new RemoteInput[]{smartReplies.remoteInput}, intent, + results); RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE); entry.setHasSentReply(); try { - pendingIntent.send(context, 0, intent); + smartReplies.pendingIntent.send(context, 0, intent); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Unable to send smart reply", e); } @@ -741,4 +743,40 @@ public class SmartReplyView extends ViewGroup { return show; } } + + /** + * Data class for smart replies. + */ + public static class SmartReplies { + @NonNull + public final RemoteInput remoteInput; + @NonNull + public final PendingIntent pendingIntent; + @NonNull + public final CharSequence[] choices; + public final boolean fromAssistant; + + public SmartReplies(CharSequence[] choices, RemoteInput remoteInput, + PendingIntent pendingIntent, boolean fromAssistant) { + this.choices = choices; + this.remoteInput = remoteInput; + this.pendingIntent = pendingIntent; + this.fromAssistant = fromAssistant; + } + } + + + /** + * Data class for smart actions. + */ + public static class SmartActions { + @NonNull + public final List<Notification.Action> actions; + public final boolean fromAssistant; + + public SmartActions(List<Notification.Action> actions, boolean fromAssistant) { + this.actions = actions; + this.fromAssistant = fromAssistant; + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index a26b1b55b30c..095395185f86 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -19,11 +19,9 @@ package com.android.systemui.keyguard; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.app.AlarmManager; import android.content.ContentResolver; @@ -34,10 +32,15 @@ import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; -import android.util.Log; + +import androidx.slice.Slice; +import androidx.slice.SliceItem; +import androidx.slice.SliceProvider; +import androidx.slice.SliceSpecs; +import androidx.slice.builders.ListBuilder; +import androidx.slice.core.SliceQuery; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.policy.ZenModeController; import org.junit.Assert; import org.junit.Before; @@ -50,13 +53,6 @@ import java.util.Arrays; import java.util.HashSet; import java.util.concurrent.TimeUnit; -import androidx.slice.Slice; -import androidx.slice.SliceItem; -import androidx.slice.SliceProvider; -import androidx.slice.SliceSpecs; -import androidx.slice.builders.ListBuilder; -import androidx.slice.core.SliceQuery; - @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) @@ -164,7 +160,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { } @Override - protected boolean isDndSuppressingNotifications() { + protected boolean isDndOn() { return mIsZenMode; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java index 221cbe9427ba..c28e74e7c6a1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java @@ -37,6 +37,7 @@ import android.os.PowerManager; import android.provider.Settings; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableResources; @@ -127,6 +128,8 @@ public class PowerUITest extends SysuiTestCase { resources.addOverride(R.integer.config_warningTemperature, 55); mPowerUI.start(); + // Guarantees mHandler has processed all messages. + TestableLooper.get(this).processAllMessages(); verify(mMockWarnings).showHighTemperatureWarning(); } @@ -139,6 +142,8 @@ public class PowerUITest extends SysuiTestCase { resources.addOverride(R.integer.config_warningTemperature, 55); mPowerUI.start(); + // Guarantees mHandler has processed all messages. + TestableLooper.get(this).processAllMessages(); verify(mMockWarnings).showHighTemperatureWarning(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt index 48491d7ac88c..24bcca50d34a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt @@ -16,8 +16,12 @@ package com.android.systemui.privacy +import android.app.ActivityManager import android.app.AppOpsManager +import android.content.Intent import android.os.Handler +import android.os.UserHandle +import android.os.UserManager import android.support.test.filters.SmallTest import android.testing.AndroidTestingRunner import android.testing.TestableLooper @@ -34,9 +38,11 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyList import org.mockito.ArgumentMatchers.eq import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.doReturn +import org.mockito.Mockito.never +import org.mockito.Mockito.spy import org.mockito.Mockito.verify - import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -44,10 +50,18 @@ import org.mockito.MockitoAnnotations @RunWithLooper class PrivacyItemControllerTest : SysuiTestCase() { + companion object { + val CURRENT_USER_ID = ActivityManager.getCurrentUser() + val OTHER_USER = UserHandle(CURRENT_USER_ID + 1) + const val TAG = "PrivacyItemControllerTest" + } + @Mock private lateinit var appOpsController: AppOpsController @Mock private lateinit var callback: PrivacyItemController.Callback + @Mock + private lateinit var userManager: UserManager private lateinit var testableLooper: TestableLooper private lateinit var privacyItemController: PrivacyItemController @@ -57,15 +71,17 @@ class PrivacyItemControllerTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) - appOpsController = mDependency.injectMockDependency(AppOpsController:: class.java) + appOpsController = mDependency.injectMockDependency(AppOpsController::class.java) mDependency.injectTestDependency(Dependency.BG_LOOPER, testableLooper.looper) mDependency.injectTestDependency(Dependency.MAIN_HANDLER, Handler(testableLooper.looper)) + mContext.addMockSystemService(UserManager::class.java, userManager) doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, 0, "", 0))) .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) privacyItemController = PrivacyItemController(mContext, callback) } + @Test fun testSetListeningTrue() { privacyItemController.setListening(true) @@ -80,6 +96,38 @@ class PrivacyItemControllerTest : SysuiTestCase() { privacyItemController.setListening(true) privacyItemController.setListening(false) verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS), - any(AppOpsController.Callback:: class.java)) + any(AppOpsController.Callback::class.java)) + } + + @Test + fun testRegisterReceiver_allUsers() { + val spiedContext = spy(mContext) + val itemController = PrivacyItemController(spiedContext, callback) + + verify(spiedContext, atLeastOnce()).registerReceiverAsUser( + eq(itemController.userSwitcherReceiver), eq(UserHandle.ALL), any(), eq(null), + eq(null)) + verify(spiedContext, never()).unregisterReceiver(eq(itemController.userSwitcherReceiver)) + } + + @Test + fun testReceiver_ACTION_USER_FOREGROUND() { + privacyItemController.userSwitcherReceiver.onReceive(context, + Intent(Intent.ACTION_USER_FOREGROUND)) + verify(userManager).getProfiles(anyInt()) + } + + @Test + fun testReceiver_ACTION_MANAGED_PROFILE_ADDED() { + privacyItemController.userSwitcherReceiver.onReceive(context, + Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)) + verify(userManager).getProfiles(anyInt()) + } + + @Test + fun testReceiver_ACTION_MANAGED_PROFILE_REMOVED() { + privacyItemController.userSwitcherReceiver.onReceive(context, + Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED)) + verify(userManager).getProfiles(anyInt()) } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java index f49c5b47deda..9d0556f61398 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java @@ -120,7 +120,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase { mTestHandler = Handler.createAsync(Looper.myLooper()); mSbn = createNewNotification(0 /* id */); mEntry = new NotificationData.Entry(mSbn); - mEntry.row = mRow; + mEntry.setRow(mRow); mAlertingNotificationManager = createAlertingNotificationManager(); } @@ -171,7 +171,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase { for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) { StatusBarNotification sbn = createNewNotification(i); NotificationData.Entry entry = new NotificationData.Entry(sbn); - entry.row = mRow; + entry.setRow(mRow); mAlertingNotificationManager.showNotification(entry); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index d409e2b254df..b5d305d864e8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -78,7 +78,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, new Notification(), UserHandle.CURRENT, null, 0); mEntry = new NotificationData.Entry(mSbn); - mEntry.row = mRow; + mEntry.setRow(mRow); mRemoteInputManager.setUpWithPresenterForTest(mPresenter, mCallback, mDelegate, mController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index aca1f90b5aa8..9bed59b16f6e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -227,7 +227,7 @@ public class NotificationTestHelper { null /* overrideGroupKey */, System.currentTimeMillis()); NotificationData.Entry entry = new NotificationData.Entry(sbn); - entry.row = row; + entry.setRow(row); entry.createIcons(mContext, sbn); entry.channel = new NotificationChannel( notification.getChannelId(), notification.getChannelId(), IMPORTANCE_DEFAULT); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 602e613388fd..72d6cd8eaeea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -37,6 +37,7 @@ import com.android.systemui.InitController; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -73,7 +74,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { @Mock private ShadeController mShadeController; private NotificationViewHierarchyManager mViewHierarchyManager; - private NotificationTestHelper mHelper = new NotificationTestHelper(mContext);; + private NotificationTestHelper mHelper = new NotificationTestHelper(mContext); @Before public void setUp() { @@ -95,7 +96,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { private NotificationData.Entry createEntry() throws Exception { ExpandableNotificationRow row = mHelper.createRow(); NotificationData.Entry entry = new NotificationData.Entry(row.getStatusBarNotification()); - entry.row = row; + entry.setRow(row); return entry; } @@ -108,9 +109,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { NotificationData.Entry entry2 = createEntry(); // Set up the prior state to look like three top level notifications. - mListContainer.addContainerView(entry0.row); - mListContainer.addContainerView(entry1.row); - mListContainer.addContainerView(entry2.row); + mListContainer.addContainerView(entry0.getRow()); + mListContainer.addContainerView(entry1.getRow()); + mListContainer.addContainerView(entry2.getRow()); when(mNotificationData.getActiveNotifications()).thenReturn( Lists.newArrayList(entry0, entry1, entry2)); @@ -118,15 +119,15 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { when(mGroupManager.isChildInGroupWithSummary(entry0.notification)).thenReturn(false); when(mGroupManager.isChildInGroupWithSummary(entry1.notification)).thenReturn(true); when(mGroupManager.isChildInGroupWithSummary(entry2.notification)).thenReturn(true); - when(mGroupManager.getGroupSummary(entry1.notification)).thenReturn(entry0.row); - when(mGroupManager.getGroupSummary(entry2.notification)).thenReturn(entry0.row); + when(mGroupManager.getGroupSummary(entry1.notification)).thenReturn(entry0); + when(mGroupManager.getGroupSummary(entry2.notification)).thenReturn(entry0); // Run updateNotifications - the view hierarchy should be reorganized. mViewHierarchyManager.updateNotificationViews(); - verify(mListContainer).notifyGroupChildAdded(entry1.row); - verify(mListContainer).notifyGroupChildAdded(entry2.row); - assertTrue(Lists.newArrayList(entry0.row).equals(mListContainer.mRows)); + verify(mListContainer).notifyGroupChildAdded(entry1.getRow()); + verify(mListContainer).notifyGroupChildAdded(entry2.getRow()); + assertTrue(Lists.newArrayList(entry0.getRow()).equals(mListContainer.mRows)); } @Test @@ -135,11 +136,11 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { NotificationData.Entry entry0 = createEntry(); NotificationData.Entry entry1 = createEntry(); NotificationData.Entry entry2 = createEntry(); - entry0.row.addChildNotification(entry1.row); - entry0.row.addChildNotification(entry2.row); + entry0.getRow().addChildNotification(entry1.getRow()); + entry0.getRow().addChildNotification(entry2.getRow()); // Set up the prior state to look like one top level notification. - mListContainer.addContainerView(entry0.row); + mListContainer.addContainerView(entry0.getRow()); when(mNotificationData.getActiveNotifications()).thenReturn( Lists.newArrayList(entry0, entry1, entry2)); @@ -152,10 +153,12 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mViewHierarchyManager.updateNotificationViews(); verify(mListContainer).notifyGroupChildRemoved( - entry1.row, entry0.row.getChildrenContainer()); + entry1.getRow(), entry0.getRow().getChildrenContainer()); verify(mListContainer).notifyGroupChildRemoved( - entry2.row, entry0.row.getChildrenContainer()); - assertTrue(Lists.newArrayList(entry0.row, entry1.row, entry2.row).equals(mListContainer.mRows)); + entry2.getRow(), entry0.getRow().getChildrenContainer()); + assertTrue( + Lists.newArrayList(entry0.getRow(), entry1.getRow(), entry2.getRow()) + .equals(mListContainer.mRows)); } @Test @@ -163,10 +166,10 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { // Tests two top level notifications becoming a suppressed summary and a child. NotificationData.Entry entry0 = createEntry(); NotificationData.Entry entry1 = createEntry(); - entry0.row.addChildNotification(entry1.row); + entry0.getRow().addChildNotification(entry1.getRow()); // Set up the prior state to look like a top level notification. - mListContainer.addContainerView(entry0.row); + mListContainer.addContainerView(entry0.getRow()); when(mNotificationData.getActiveNotifications()).thenReturn( Lists.newArrayList(entry0, entry1)); @@ -179,23 +182,23 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mViewHierarchyManager.updateNotificationViews(); verify(mListContainer).notifyGroupChildRemoved( - entry1.row, entry0.row.getChildrenContainer()); - assertTrue(Lists.newArrayList(entry0.row, entry1.row).equals(mListContainer.mRows)); - assertEquals(View.GONE, entry0.row.getVisibility()); - assertEquals(View.VISIBLE, entry1.row.getVisibility()); + entry1.getRow(), entry0.getRow().getChildrenContainer()); + assertTrue(Lists.newArrayList(entry0.getRow(), entry1.getRow()).equals(mListContainer.mRows)); + assertEquals(View.GONE, entry0.getRow().getVisibility()); + assertEquals(View.VISIBLE, entry1.getRow().getVisibility()); } @Test public void testUpdateNotificationViews_appOps() throws Exception { NotificationData.Entry entry0 = createEntry(); - entry0.row = spy(entry0.row); + entry0.setRow(spy(entry0.getRow())); when(mNotificationData.getActiveNotifications()).thenReturn( Lists.newArrayList(entry0)); - mListContainer.addContainerView(entry0.row); + mListContainer.addContainerView(entry0.getRow()); mViewHierarchyManager.updateNotificationViews(); - verify(entry0.row, times(1)).showAppOpsIcons(any()); + verify(entry0.getRow(), times(1)).showAppOpsIcons(any()); } private class FakeListContainer implements NotificationListContainer { @@ -206,19 +209,19 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public void setChildTransferInProgress(boolean childTransferInProgress) {} @Override - public void changeViewPosition(View child, int newIndex) { + public void changeViewPosition(ExpandableView child, int newIndex) { mRows.remove(child); mRows.add(newIndex, child); } @Override - public void notifyGroupChildAdded(View row) {} + public void notifyGroupChildAdded(ExpandableView row) {} @Override - public void notifyGroupChildRemoved(View row, ViewGroup childrenContainer) {} + public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) {} @Override - public void generateAddAnimation(View child, boolean fromMoreCard) {} + public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) {} @Override public void generateChildOrderChangedEvent() {} @@ -252,7 +255,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public void setMaxDisplayedNotifications(int maxNotifications) {} @Override - public void snapViewIfNeeded(ExpandableNotificationRow row) {} + public void snapViewIfNeeded(Entry entry) {} @Override public ViewGroup getViewParentForNotification(NotificationData.Entry entry) { @@ -271,10 +274,10 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { } @Override - public void cleanUpViewState(View view) {} + public void cleanUpViewStateForEntry(Entry entry) { } @Override - public boolean isInVisibleLocation(ExpandableNotificationRow row) { + public boolean isInVisibleLocation(Entry entry) { return true; } @@ -286,5 +289,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public boolean hasPulsingNotifications() { return false; } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java index 1d977d8c5dad..76b992f42090 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java @@ -16,18 +16,15 @@ package com.android.systemui.statusbar; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; + import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.Notification; import android.os.RemoteException; import android.os.UserHandle; -import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; @@ -38,7 +35,6 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import org.junit.Before; import org.junit.Test; @@ -93,7 +89,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { @Test public void testSendSmartReply_updatesRemoteInput() { - mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT); + mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false); // Sending smart reply should make calls to NotificationEntryManager // to update the notification with reply and spinner. @@ -103,11 +99,21 @@ public class SmartReplyControllerTest extends SysuiTestCase { @Test public void testSendSmartReply_logsToStatusBar() throws RemoteException { - mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT); + mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false); + + // Check we log the result to the status bar service. + verify(mIStatusBarService).onNotificationSmartReplySent(mSbn.getKey(), + TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false); + } + + + @Test + public void testSendSmartReply_logsToStatusBar_generatedByAssistant() throws RemoteException { + mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, true); // Check we log the result to the status bar service. verify(mIStatusBarService).onNotificationSmartReplySent(mSbn.getKey(), - TEST_CHOICE_INDEX); + TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, true); } @Test @@ -121,14 +127,14 @@ public class SmartReplyControllerTest extends SysuiTestCase { @Test public void testSendSmartReply_reportsSending() { - mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT); + mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false); assertTrue(mSmartReplyController.isSendingSmartReply(mSbn.getKey())); } @Test public void testSendingSmartReply_afterRemove_shouldReturnFalse() { - mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT); + mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false); mSmartReplyController.stopSending(mEntry); assertFalse(mSmartReplyController.isSendingSmartReply(mSbn.getKey())); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index d1fe5af406d3..8706e214db8e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -262,14 +262,14 @@ public class NotificationEntryManagerTest extends SysuiTestCase { NotificationData.Entry.class); verify(mCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any()); NotificationData.Entry entry = entryCaptor.getValue(); - verify(mRemoteInputManager).bindRow(entry.row); + verify(mRemoteInputManager).bindRow(entry.getRow()); // Row content inflation: verify(mCallback).onNotificationAdded(entry); verify(mPresenter).updateNotificationViews(); assertEquals(mEntryManager.getNotificationData().get(mSbn.getKey()), entry); - assertNotNull(entry.row); + assertNotNull(entry.getRow()); assertEquals(mEntry.userSentiment, NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL); } @@ -294,7 +294,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mPresenter).updateNotificationViews(); verify(mForegroundServiceController).updateNotification(eq(mSbn), anyInt()); verify(mCallback).onNotificationUpdated(mSbn); - assertNotNull(mEntry.row); + assertNotNull(mEntry.getRow()); assertEquals(mEntry.userSentiment, NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE); } @@ -303,7 +303,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { public void testRemoveNotification() throws Exception { com.android.systemui.util.Assert.isNotMainThread(); - mEntry.row = mRow; + mEntry.setRow(mRow); mEntryManager.getNotificationData().add(mEntry); mEntryManager.removeNotification(mSbn.getKey(), mRankingMap); @@ -313,7 +313,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mMediaManager).onNotificationRemoved(mSbn.getKey()); verify(mForegroundServiceController).removeNotification(mSbn); - verify(mListContainer).cleanUpViewState(mRow); + verify(mListContainer).cleanUpViewStateForEntry(mEntry); verify(mPresenter).updateNotificationViews(); verify(mCallback).onNotificationRemoved(mSbn.getKey(), mSbn); verify(mRow).setRemoved(); @@ -332,7 +332,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { extenders.clear(); extenders.add(extender); - mEntry.row = mRow; + mEntry.setRow(mRow); mEntryManager.getNotificationData().add(mEntry); mEntryManager.removeNotification(mSbn.getKey(), mRankingMap); @@ -347,7 +347,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) .thenReturn(mEntry.key); - mEntry.row = mRow; + mEntry.setRow(mRow); mEntryManager.getNotificationData().add(mEntry); mEntryManager.updateNotificationsForAppOp( @@ -372,7 +372,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Test public void testAddNotificationExistingAppOps() { - mEntry.row = mRow; + mEntry.setRow(mRow); mEntryManager.getNotificationData().add(mEntry); ArraySet<Integer> expected = new ArraySet<>(); expected.add(3); @@ -395,7 +395,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Test public void testAdd_noExistingAppOps() { - mEntry.row = mRow; + mEntry.setRow(mRow); mEntryManager.getNotificationData().add(mEntry); when(mForegroundServiceController.getStandardLayoutKey( mEntry.notification.getUserId(), @@ -409,7 +409,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Test public void testAdd_existingAppOpsNotForegroundNoti() { - mEntry.row = mRow; + mEntry.setRow(mRow); mEntryManager.getNotificationData().add(mEntry); ArraySet<Integer> ops = new ArraySet<>(); ops.add(3); @@ -431,7 +431,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mEnvironment.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - mEntry.row = mRow; + mEntry.setRow(mRow); mEntry.setInflationTask(mAsyncInflationTask); mEntryManager.getNotificationData().add(mEntry); setSmartActions(mEntry.key, new ArrayList<>(Arrays.asList(createAction()))); @@ -447,7 +447,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - mEntry.row = mRow; + mEntry.setRow(mRow); mEntryManager.getNotificationData().add(mEntry); setSmartActions(mEntry.key, null); @@ -461,7 +461,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - mEntry.row = null; + mEntry.setRow(null); mEntryManager.getNotificationData().add(mEntry); setSmartActions(mEntry.key, new ArrayList<>(Arrays.asList(createAction()))); @@ -476,7 +476,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - mEntry.row = null; + mEntry.setRow(null); mEntryManager.mPendingNotifications.put(mEntry.key, mEntry); setSmartActions(mEntry.key, new ArrayList<>(Arrays.asList(createAction()))); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java index ffb1c2d26af2..f19097934fd6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java @@ -47,7 +47,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase { public void setUp() { mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider); mEntry = new NotificationData.Entry(mock(StatusBarNotification.class)); - mEntry.row = mRow; + mEntry.setRow(mRow); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java index 1c7a8e8185a3..3710fa833d50 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java @@ -89,7 +89,7 @@ public class NotificationLoggerTest extends SysuiTestCase { mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, new Notification(), UserHandle.CURRENT, null, 0); mEntry = new NotificationData.Entry(mSbn); - mEntry.row = mRow; + mEntry.setRow(mRow); mLogger = new TestableNotificationLogger(mBarService); mLogger.setUpWithContainer(mListContainer); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java index 5e137a7de65a..7fee0ee8c664 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java @@ -16,11 +16,10 @@ package com.android.systemui.statusbar.notification.row; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; +import static com.google.common.truth.Truth.assertThat; + +import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.Mockito.doNothing; @@ -170,8 +169,10 @@ public class NotificationContentViewTest extends SysuiTestCase { private void setupAppGeneratedReplies( CharSequence[] smartReplyTitles, Notification.Action freeFormRemoteInputAction) { + PendingIntent pendingIntent = + PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0); Notification.Action action = - new Notification.Action.Builder(null, "Test Action", null).build(); + new Notification.Action.Builder(null, "Test Action", pendingIntent).build(); when(mRemoteInput.getChoices()).thenReturn(smartReplyTitles); Pair<RemoteInput, Notification.Action> remoteInputActionPair = Pair.create(mRemoteInput, action); @@ -191,7 +192,7 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertFalse(repliesAndActions.smartRepliesExist()); + assertThat(repliesAndActions.smartReplies).isNull(); } @Test @@ -203,7 +204,9 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertThat(repliesAndActions.smartReplies, equalTo(smartReplies)); + assertThat(repliesAndActions.smartReplies.choices).isEqualTo(smartReplies); + assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse(); + assertThat(repliesAndActions.smartActions).isNull(); } @Test @@ -219,8 +222,10 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertThat(repliesAndActions.smartReplies, equalTo(smartReplies)); - assertThat(repliesAndActions.smartActions, equalTo(smartActions)); + assertThat(repliesAndActions.smartReplies.choices).isEqualTo(smartReplies); + assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse(); + assertThat(repliesAndActions.smartActions.actions).isEqualTo(smartActions); + assertThat(repliesAndActions.smartActions.fromAssistant).isFalse(); } @Test @@ -237,8 +242,9 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertThat(repliesAndActions.smartReplies, equalTo(mEntry.smartReplies)); - assertThat(repliesAndActions.smartActions, is(empty())); + assertThat(repliesAndActions.smartReplies.choices).isEqualTo(mEntry.smartReplies); + assertThat(repliesAndActions.smartReplies.fromAssistant).isTrue(); + assertThat(repliesAndActions.smartActions).isNull(); } @Test @@ -255,8 +261,8 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertThat(repliesAndActions.smartReplies, equalTo(null)); - assertThat(repliesAndActions.smartActions, is(empty())); + assertThat(repliesAndActions.smartReplies).isNull(); + assertThat(repliesAndActions.smartActions).isNull(); } @Test @@ -270,8 +276,10 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertThat(repliesAndActions.smartReplies, equalTo(null)); - assertThat(repliesAndActions.smartActions, equalTo(mEntry.systemGeneratedSmartActions)); + assertThat(repliesAndActions.smartReplies).isNull(); + assertThat(repliesAndActions.smartActions.actions) + .isEqualTo(mEntry.systemGeneratedSmartActions); + assertThat(repliesAndActions.smartActions.fromAssistant).isTrue(); } @Test @@ -296,8 +304,10 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertThat(repliesAndActions.smartReplies, equalTo(appGenSmartReplies)); - assertThat(repliesAndActions.smartActions, equalTo(appGenSmartActions)); + assertThat(repliesAndActions.smartReplies.choices).isEqualTo(appGenSmartReplies); + assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse(); + assertThat(repliesAndActions.smartActions.actions).isEqualTo(appGenSmartActions); + assertThat(repliesAndActions.smartActions.fromAssistant).isFalse(); } @Test @@ -313,8 +323,8 @@ public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView.SmartRepliesAndActions repliesAndActions = NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry); - assertThat(repliesAndActions.smartReplies, equalTo(null)); - assertThat(repliesAndActions.smartActions, is(empty())); + assertThat(repliesAndActions.smartActions).isNull(); + assertThat(repliesAndActions.smartReplies).isNull(); } private Notification.Action.Builder createActionBuilder(String actionTitle) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 3d2ea708e90e..84bfae650ce3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -20,8 +20,7 @@ import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; -import static android.service.notification.NotificationListenerService.Ranking - .USER_SENTIMENT_NEGATIVE; +import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; @@ -62,8 +61,7 @@ import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager - .OnSettingsClickListener; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -177,10 +175,17 @@ public class NotificationGutsManagerTest extends SysuiTestCase { NotificationMenuRowPlugin.MenuItem menuItem = createTestMenuItem(realRow); ExpandableNotificationRow row = spy(realRow); + when(row.getWindowToken()).thenReturn(new Binder()); when(row.getGuts()).thenReturn(guts); doNothing().when(row).inflateGuts(); + NotificationData.Entry realEntry = realRow.getEntry(); + NotificationData.Entry entry = spy(realEntry); + + when(entry.getRow()).thenReturn(row); + when(entry.getGuts()).thenReturn(guts); + mGutsManager.openGuts(row, 0, 0, menuItem); mTestableLooper.processAllMessages(); verify(guts).openControls( @@ -190,13 +195,19 @@ public class NotificationGutsManagerTest extends SysuiTestCase { anyBoolean(), any(Runnable.class)); + // called once by mGutsManager.bindGuts() in mGutsManager.openGuts() + verify(row).setGutsView(any()); + row.onDensityOrFontScaleChanged(); - mGutsManager.onDensityOrFontScaleChanged(row); + mGutsManager.onDensityOrFontScaleChanged(entry); + mTestableLooper.processAllMessages(); mGutsManager.closeAndSaveGuts(false, false, false, 0, 0, false); verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean()); + + // called again by mGutsManager.bindGuts(), in mGutsManager.onDensityOrFontScaleChanged() verify(row, times(2)).setGutsView(any()); } @@ -284,8 +295,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView, - NotificationInfo.ACTION_NONE); + mGutsManager.initializeNotificationInfo(row, notificationInfoView); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -302,8 +312,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(0), - eq(NotificationInfo.ACTION_NONE)); + eq(0)); } @Test @@ -315,8 +324,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView, - NotificationInfo.ACTION_NONE); + mGutsManager.initializeNotificationInfo(row, notificationInfoView); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -333,8 +341,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(0), - eq(NotificationInfo.ACTION_NONE)); + eq(0)); } @Test @@ -347,8 +354,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView, - NotificationInfo.ACTION_NONE); + mGutsManager.initializeNotificationInfo(row, notificationInfoView); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -365,8 +371,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(true) /*isNoisy */, - eq(0), - eq(NotificationInfo.ACTION_NONE)); + eq(0)); } @Test @@ -379,8 +384,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView, - NotificationInfo.ACTION_NONE); + mGutsManager.initializeNotificationInfo(row, notificationInfoView); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -397,8 +401,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(IMPORTANCE_DEFAULT), - eq(NotificationInfo.ACTION_NONE)); + eq(IMPORTANCE_DEFAULT)); } @Test @@ -411,8 +414,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { StatusBarNotification statusBarNotification = row.getStatusBarNotification(); when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); - mGutsManager.initializeNotificationInfo(row, notificationInfoView, - NotificationInfo.ACTION_NONE); + mGutsManager.initializeNotificationInfo(row, notificationInfoView); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -429,8 +431,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(0), - eq(NotificationInfo.ACTION_NONE)); + eq(0)); } @Test @@ -442,8 +443,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView, - NotificationInfo.ACTION_BLOCK); + mGutsManager.initializeNotificationInfo(row, notificationInfoView); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -460,8 +460,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(0), - eq(NotificationInfo.ACTION_BLOCK)); + eq(0)); } @Test @@ -470,7 +469,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { ExpandableNotificationRow row = spy(createTestNotificationRow()); doReturn(guts).when(row).getGuts(); NotificationData.Entry entry = row.getEntry(); - entry.row = row; + entry.setRow(row); mGutsManager.setExposedGuts(guts); assertTrue(mGutsManager.shouldExtendLifetime(entry)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 985827a9cd54..3dd493f0cd44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -187,7 +187,7 @@ public class NotificationInfoTest extends SysuiTestCase { when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView textView = mNotificationInfo.findViewById(R.id.pkgname); assertTrue(textView.getText().toString().contains("App Name")); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -200,7 +200,7 @@ public class NotificationInfoTest extends SysuiTestCase { .thenReturn(iconDrawable); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon); assertEquals(iconDrawable, iconView.getDrawable()); } @@ -209,7 +209,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_noDelegate() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(GONE, nameView.getVisibility()); final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider); @@ -228,7 +228,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(VISIBLE, nameView.getVisibility()); assertTrue(nameView.getText().toString().contains("Other")); @@ -240,7 +240,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(GONE, groupNameView.getVisibility()); final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider); @@ -257,7 +257,7 @@ public class NotificationInfoTest extends SysuiTestCase { .thenReturn(notificationChannelGroup); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(View.VISIBLE, groupNameView.getVisibility()); assertEquals("Test Group Name", groupNameView.getText()); @@ -269,7 +269,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SetsTextChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(TEST_CHANNEL_NAME, textView.getText()); } @@ -278,7 +278,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true, - false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, false, IMPORTANCE_DEFAULT); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(GONE, textView.getVisibility()); } @@ -291,7 +291,7 @@ public class NotificationInfoTest extends SysuiTestCase { eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true, - false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, false, IMPORTANCE_DEFAULT); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(VISIBLE, textView.getVisibility()); } @@ -300,7 +300,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(VISIBLE, textView.getVisibility()); } @@ -309,7 +309,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_BlockButton() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final View block = mNotificationInfo.findViewById(R.id.block); final View toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); final View minimize = mNotificationInfo.findViewById(R.id.minimize); @@ -323,7 +323,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -335,7 +335,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_LOW, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_LOW); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -347,7 +347,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -360,7 +360,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_LOW, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_LOW); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -372,7 +372,7 @@ public class NotificationInfoTest extends SysuiTestCase { mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final View block = mNotificationInfo.findViewById(R.id.block); final View minimize = mNotificationInfo.findViewById(R.id.minimize); assertEquals(GONE, block.getVisibility()); @@ -387,7 +387,7 @@ public class NotificationInfoTest extends SysuiTestCase { (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); latch.countDown(); - }, null, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + }, null, true, false, false, IMPORTANCE_DEFAULT); final View settingsButton = mNotificationInfo.findViewById(R.id.info); settingsButton.performClick(); @@ -399,7 +399,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -411,7 +411,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); - }, null, false, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + }, null, false, false, false, IMPORTANCE_DEFAULT); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -420,11 +420,11 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, (View v, NotificationChannel c, int appUid) -> { - }, null, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + }, null, true, false, false, IMPORTANCE_DEFAULT); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertEquals(View.VISIBLE, settingsButton.getVisibility()); } @@ -433,7 +433,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger, times(0)).count(anyString(), anyInt()); } @@ -442,7 +442,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true, - true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, true, false, IMPORTANCE_DEFAULT); mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger, times(1)).count(anyString(), anyInt()); } @@ -455,7 +455,7 @@ public class NotificationInfoTest extends SysuiTestCase { (View v, NotificationChannel c, int appUid) -> { assertEquals(null, c); latch.countDown(); - }, null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + }, null, true, true, false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.info).performClick(); // Verify that listener was triggered. @@ -468,7 +468,7 @@ public class NotificationInfoTest extends SysuiTestCase { throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null, - null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + null, true, true, false, IMPORTANCE_DEFAULT); final TextView channelNameView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(GONE, channelNameView.getVisibility()); @@ -479,7 +479,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null, - null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + null, true, true, false, IMPORTANCE_DEFAULT); final TextView blockView = mNotificationInfo.findViewById(R.id.block); assertEquals(GONE, blockView.getVisibility()); } @@ -488,7 +488,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testbindNotification_BlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false, - true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, true, false, IMPORTANCE_DEFAULT); final TextView view = mNotificationInfo.findViewById(R.id.block_prompt); assertEquals(View.VISIBLE, view.getVisibility()); assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText()); @@ -498,7 +498,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView view = mNotificationInfo.findViewById(R.id.block_prompt); assertEquals(View.VISIBLE, view.getVisibility()); assertEquals(mContext.getString(R.string.notification_unblockable_desc), @@ -509,7 +509,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( anyString(), eq(TEST_UID), any()); @@ -520,7 +520,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -534,7 +534,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.minimize).performClick(); mTestableLooper.processAllMessages(); @@ -548,7 +548,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); mTestableLooper.processAllMessages(); @@ -562,7 +562,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); mTestableLooper.processAllMessages(); @@ -576,7 +576,7 @@ public class NotificationInfoTest extends SysuiTestCase { int originalImportance = mNotificationChannel.getImportance(); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -591,7 +591,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.handleCloseControls(true, false); @@ -609,8 +609,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */ , - true, false /* isNonblockable */, false /* isNoisy */, IMPORTANCE_DEFAULT, - NotificationInfo.ACTION_NONE); + true, false /* isNonblockable */, false /* isNoisy */, IMPORTANCE_DEFAULT + ); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -631,8 +631,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, - true, false /* isNonblockable */, false /* isNoisy */, IMPORTANCE_DEFAULT, - NotificationInfo.ACTION_NONE); + true, false /* isNonblockable */, false /* isNoisy */, IMPORTANCE_DEFAULT + ); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -653,8 +653,7 @@ public class NotificationInfoTest extends SysuiTestCase { null /* onSettingsClick */, null /* onAppSettingsClick */ , true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT, - NotificationInfo.ACTION_NONE); + true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT); NotificationGuts guts = spy(new NotificationGuts(mContext, null)); when(guts.getWindowToken()).thenReturn(mock(IBinder.class)); @@ -682,8 +681,7 @@ public class NotificationInfoTest extends SysuiTestCase { 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */ , true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT, - NotificationInfo.ACTION_NONE); + true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT); NotificationGuts guts = spy(new NotificationGuts(mContext, null)); when(guts.getWindowToken()).thenReturn(mock(IBinder.class)); @@ -712,7 +710,7 @@ public class NotificationInfoTest extends SysuiTestCase { null /* onSettingsClick */, null /* onAppSettingsClick */ , false /* isNonblockable */, true /* isForBlockingHelper */, true, true /* isUserSentimentNegative */, false /* isNoisy */, - IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + IMPORTANCE_DEFAULT); mNotificationInfo.handleCloseControls(true /* save */, false /* force */); @@ -731,8 +729,7 @@ public class NotificationInfoTest extends SysuiTestCase { null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT, - NotificationInfo.ACTION_NONE); + true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -755,7 +752,7 @@ public class NotificationInfoTest extends SysuiTestCase { true /* isForBlockingHelper */, true, false /* isUserSentimentNegative */, - false /* isNoisy */, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false /* isNoisy */, IMPORTANCE_DEFAULT); NotificationGuts guts = mock(NotificationGuts.class); doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean()); mNotificationInfo.setGutsParent(guts); @@ -770,7 +767,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -784,7 +781,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -817,7 +814,7 @@ public class NotificationInfoTest extends SysuiTestCase { false /* isNonblockable */, true /* isForBlockingHelper */, true /* isUserSentimentNegative */, - false/* isNoisy */, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false/* isNoisy */, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -839,7 +836,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -854,7 +851,7 @@ public class NotificationInfoTest extends SysuiTestCase { mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -875,7 +872,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.handleCloseControls(true, false); @@ -893,7 +890,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -915,7 +912,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -937,7 +934,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -958,7 +955,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -980,7 +977,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -1002,7 +999,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_LOW, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_LOW); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -1023,7 +1020,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -1039,7 +1036,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1056,7 +1053,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { - }, null, null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + }, null, null, true, true, false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -1074,8 +1071,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); - }, null, null, true, false, false, IMPORTANCE_DEFAULT, - NotificationInfo.ACTION_NONE); + }, null, null, true, false, false, IMPORTANCE_DEFAULT + ); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -1111,7 +1108,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, (View v, Intent intent) -> { latch.countDown(); - }, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + }, true, false, false, IMPORTANCE_DEFAULT); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(View.VISIBLE, settingsLink.getVisibility()); settingsLink.performClick(); @@ -1139,7 +1136,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null, (View v, Intent intent) -> { latch.countDown(); - }, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + }, true, false, false, IMPORTANCE_DEFAULT); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(View.VISIBLE, settingsLink.getVisibility()); settingsLink.performClick(); @@ -1158,7 +1155,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null, - null, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + null, true, false, false, IMPORTANCE_DEFAULT); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(GONE, settingsLink.getVisibility()); } @@ -1179,7 +1176,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(GONE, settingsLink.getVisibility()); } @@ -1202,7 +1199,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, false, true, - true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, true, false, IMPORTANCE_DEFAULT); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(GONE, settingsLink.getVisibility()); } @@ -1219,7 +1216,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -1232,7 +1229,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1245,7 +1242,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -1259,7 +1256,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + true, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -1273,7 +1270,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1285,7 +1282,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); + false, IMPORTANCE_DEFAULT); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1293,60 +1290,4 @@ public class NotificationInfoTest extends SysuiTestCase { waitForStopButton(); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); } - - @Test - public void testBindNotificationWithInitialBlockAction() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_BLOCK); - waitForUndoButton(); - mNotificationInfo.handleCloseControls(true, false); - - mTestableLooper.processAllMessages(); - ArgumentCaptor<NotificationChannel> updated = - ArgumentCaptor.forClass(NotificationChannel.class); - verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), updated.capture()); - assertTrue((updated.getValue().getUserLockedFields() - & USER_LOCKED_IMPORTANCE) != 0); - assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance()); - } - - @Test - public void testBindNotificationWithInitialSilenceAction() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_TOGGLE_SILENT); - waitForUndoButton(); - mNotificationInfo.handleCloseControls(true, false); - - mTestableLooper.processAllMessages(); - ArgumentCaptor<NotificationChannel> updated = - ArgumentCaptor.forClass(NotificationChannel.class); - verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), updated.capture()); - assertTrue((updated.getValue().getUserLockedFields() - & USER_LOCKED_IMPORTANCE) != 0); - assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance()); - } - - @Test - public void testBindNotificationWithInitialUnSilenceAction() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_LOW, NotificationInfo.ACTION_TOGGLE_SILENT); - waitForUndoButton(); - mNotificationInfo.handleCloseControls(true, false); - - mTestableLooper.processAllMessages(); - ArgumentCaptor<NotificationChannel> updated = - ArgumentCaptor.forClass(NotificationChannel.class); - verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), updated.capture()); - assertTrue((updated.getValue().getUserLockedFields() - & USER_LOCKED_IMPORTANCE) != 0); - assertEquals(IMPORTANCE_HIGH, updated.getValue().getImportance()); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java index a4a111aa58f0..662e016b77ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java @@ -26,11 +26,11 @@ import static org.mockito.Mockito.when; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; -import android.view.View; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.ExpandableView; import org.junit.Assert; import org.junit.Before; @@ -45,7 +45,7 @@ import java.util.HashSet; public class NotificationRoundnessManagerTest extends SysuiTestCase { private NotificationRoundnessManager mRoundnessManager = new NotificationRoundnessManager(); - private HashSet<View> mAnimatedChildren = new HashSet<>(); + private HashSet<ExpandableView> mAnimatedChildren = new HashSet<>(); private Runnable mRoundnessCallback = mock(Runnable.class); private ExpandableNotificationRow mFirst; private ExpandableNotificationRow mSecond; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 74ce5f63f01a..e65e806da93a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -325,7 +325,9 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { // add notification ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); - when(row.isClearable()).thenReturn(true); + NotificationData.Entry entry = mock(NotificationData.Entry.class); + when(row.getEntry()).thenReturn(entry); + when(entry.isClearable()).thenReturn(true); mStackScroller.addContainerView(row); mStackScroller.onUpdateRowStates(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index 10b0d834b36b..c99e766ac697 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -81,12 +81,12 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mFirst.setPinned(true); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry()); - mHeadsUpAppearanceController.onHeadsUpPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry()); Assert.assertEquals(mFirst.getEntry(), mHeadsUpStatusBarView.getShowingEntry()); mFirst.setPinned(false); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry()); Assert.assertEquals(null, mHeadsUpStatusBarView.getShowingEntry()); } @@ -95,12 +95,12 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mFirst.setPinned(true); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry()); - mHeadsUpAppearanceController.onHeadsUpPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry()); Assert.assertTrue(mHeadsUpAppearanceController.isShown()); mFirst.setPinned(false); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry()); Assert.assertFalse(mHeadsUpAppearanceController.isShown()); } @@ -109,12 +109,12 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mFirst.setPinned(true); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry()); - mHeadsUpAppearanceController.onHeadsUpPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry()); Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 0.0f, 0.0f); mFirst.setPinned(false); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry()); Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 1.0f, 0.0f); } @@ -125,12 +125,12 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mFirst.setPinned(true); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry()); - mHeadsUpAppearanceController.onHeadsUpPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpPinned(mFirst.getEntry()); Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility()); mFirst.setPinned(false); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst); + mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst.getEntry()); Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 10707957521e..44deb10941ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -97,7 +97,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { @Test public void testCanRemoveImmediately_notTopEntry() { NotificationData.Entry laterEntry = new NotificationData.Entry(createNewNotification(1)); - laterEntry.row = mRow; + laterEntry.setRow(mRow); mHeadsUpManager.showNotification(mEntry); mHeadsUpManager.showNotification(laterEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java index f8ad298c144d..31014b8a62e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java @@ -37,7 +37,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private static final int EMPTY_MARGIN = 0; private static final int EMPTY_HEIGHT = 0; private static final boolean SECURE_LOCKED = false; - private static final boolean PULSING_NO = false; private static final float ZERO_DRAG = 0.f; private static final float OPAQUE = 1.f; private static final float TRANSPARENT = 0.f; @@ -48,6 +47,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private float mPanelExpansion; private int mKeyguardStatusHeight; private float mDark; + private boolean mPulsing; @Before public void setUp() { @@ -171,6 +171,156 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT); } + @Test + public void notifPositionMiddleOfScreenOnAOD() { + // GIVEN on AOD and both stack scroll and clock have 0 height + givenAOD(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding is half of the screen (SCREEN_HEIGHT / 2). + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000); + } + + @Test + public void notifPositionIndependentOfKeyguardStatusHeightOnAOD() { + // GIVEN on AOD and clock has a nonzero height + givenAOD(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = 100; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding is half of the screen (SCREEN_HEIGHT / 2). + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000); + } + + @Test + public void notifPositionWithLargeClockOnAOD() { + // GIVEN on AOD and clock has a nonzero height + givenAOD(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = SCREEN_HEIGHT; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding is, unfortunately, the entire screen. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(SCREEN_HEIGHT); + } + + @Test + public void notifPositionWhilePulsingOnAOD() { + // GIVEN on AOD and pulsing + givenAOD(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + mPulsing = true; + mClockPositionAlgorithm.setPulsingPadding(200); + // WHEN the clock position algorithm is run + positionClock(); + // THEN the notif padding doesn't adjust for pulsing. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000); + } + + @Test + public void notifPositionMiddleOfScreenOnLockScreen() { + // GIVEN on lock screen and both stack scroll and clock have 0 height + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding is half of the screen (SCREEN_HEIGHT / 2). + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000); + } + + @Test + public void notifPositionAdjustsForStackHeightOnLockScreen() { + // GIVEN on lock screen and stack scroller has a nonzero height + givenLockScreen(); + mNotificationStackHeight = 500; + mKeyguardStatusHeight = EMPTY_HEIGHT; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding adjusts for the expanded notif stack. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(750); + } + + @Test + public void notifPositionAdjustsForClockHeightOnLockScreen() { + // GIVEN on lock screen and stack scroller has a nonzero height + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = 200; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding adjusts for both clock and notif stack. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000); + } + + @Test + public void notifPositionAdjustsForStackHeightAndClockHeightOnLockScreen() { + // GIVEN on lock screen and stack scroller has a nonzero height + givenLockScreen(); + mNotificationStackHeight = 500; + mKeyguardStatusHeight = 200; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding adjusts for both clock and notif stack. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(810); + } + + @Test + public void notifPositionWithLargeClockOnLockScreen() { + // GIVEN on lock screen and clock has a nonzero height + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = SCREEN_HEIGHT; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding is half of the screen (SCREEN_HEIGHT / 2). + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000); + } + + @Test + public void notifPositionWithFullDragOnLockScreen() { + // GIVEN the lock screen is dragged up + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + mPanelExpansion = 0.f; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the notif padding is zero. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0); + } + + @Test + public void notifPositionWithLargeClockFullDragOnLockScreen() { + // GIVEN the lock screen is dragged up and a full screen clock + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = SCREEN_HEIGHT; + mPanelExpansion = 0.f; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the notif padding is zero. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0); + } + + @Test + public void notifPositionWhilePulsingOnLockScreen() { + // GIVEN on lock screen and pulsing + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + mPulsing = true; + mClockPositionAlgorithm.setPulsingPadding(200); + // WHEN the clock position algorithm is run + positionClock(); + // THEN the notif padding adjusts for pulsing. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1200); + } + private void givenAOD() { mPanelExpansion = 1.f; mDark = 1.f; @@ -184,7 +334,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private void positionClock() { mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight, mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mDark, SECURE_LOCKED, - PULSING_NO, ZERO_DRAG); + mPulsing, ZERO_DRAG); mClockPositionAlgorithm.run(mClockPosition); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java index 96c57f2b7991..c3bc5110febe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java @@ -149,7 +149,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); mHeadsUpManager.showNotification(summaryEntry); Entry childEntry = mGroupTestHelper.createChildNotification(); - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(false); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(false); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); @@ -166,12 +167,14 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); mHeadsUpManager.showNotification(summaryEntry); Entry childEntry = mGroupTestHelper.createChildNotification(); - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(false); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(false); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(true); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(true); mGroupAlertTransferHelper.onInflationFinished(childEntry); // Alert is immediately removed from summary, and we show child as its content is inflated. @@ -185,7 +188,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(false); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(false); NotificationData.Entry childEntry2 = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); mHeadsUpManager.showNotification(summaryEntry); @@ -199,10 +203,12 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupManager.onEntryAdded(childEntry2); // Child entry finishes its inflation. - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(true); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(true); mGroupAlertTransferHelper.onInflationFinished(childEntry); - verify(childEntry.row, times(1)).freeContentViewWhenSafe(mHeadsUpManager.getContentFlag()); + verify(childEntry.getRow(), times(1)).freeContentViewWhenSafe(mHeadsUpManager + .getContentFlag()); assertFalse(mHeadsUpManager.isAlerting(childEntry.key)); } @@ -212,7 +218,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(false); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(false); mHeadsUpManager.showNotification(summaryEntry); // Trigger a transfer of alert state from summary to child. mGroupManager.onEntryAdded(summaryEntry); @@ -229,7 +236,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(false); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(false); mHeadsUpManager.showNotification(summaryEntry); // Trigger a transfer of alert state from summary to child. mGroupManager.onEntryAdded(summaryEntry); @@ -251,7 +259,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - when(childEntry.row.isInflationFlagSet(mHeadsUpManager.getContentFlag())).thenReturn(false); + when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) + .thenReturn(false); mHeadsUpManager.showNotification(summaryEntry); // Trigger a transfer of alert state from summary to child. mGroupManager.onEntryAdded(summaryEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java index 1483ae5f2a12..b0bd1fba3760 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java @@ -100,7 +100,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase { mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); assertTrue(mGroupManager.isSummaryOfGroup(summaryEntry.notification)); - assertEquals(summaryEntry.row, mGroupManager.getGroupSummary(childEntry.notification)); + assertEquals(summaryEntry, mGroupManager.getGroupSummary(childEntry.notification)); } @Test @@ -143,9 +143,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { // Child entries that are heads upped should be considered separate groups visually even if // they are the same group logically - assertEquals(childEntry.row, mGroupManager.getGroupSummary(childEntry.notification)); - assertEquals(summaryEntry.row, - mGroupManager.getLogicalGroupSummary(childEntry.notification)); + assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry.notification)); + assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry.notification)); } @Test @@ -161,8 +160,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase { // Child entries that are heads upped should be considered separate groups visually even if // they are the same group logically - assertEquals(childEntry.row, mGroupManager.getGroupSummary(childEntry.notification)); - assertEquals(summaryEntry.row, - mGroupManager.getLogicalGroupSummary(childEntry.notification)); + assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry.notification)); + assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry.notification)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java index 01f44fd4d0cc..7ad68eb1c9a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java @@ -81,7 +81,7 @@ public final class NotificationGroupTestHelper { 0 /* postTime */); NotificationData.Entry entry = new NotificationData.Entry(sbn); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); - entry.row = row; + entry.setRow(row); when(row.getEntry()).thenReturn(entry); when(row.getStatusBarNotification()).thenReturn(sbn); when(row.isInflationFlagSet(anyInt())).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index 9e659c880b9f..b6e3fc172c69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -181,7 +181,16 @@ public class SmartReplyViewTest extends SysuiTestCase { public void testSendSmartReply_controllerCalled() { setSmartReplies(TEST_CHOICES); mView.getChildAt(2).performClick(); - verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2]); + verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2], + false /* generatedByAsssitant */); + } + + @Test + public void testSendSmartReply_controllerCalled_generatedByAssistant() { + setSmartReplies(TEST_CHOICES, true); + mView.getChildAt(2).performClick(); + verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2], + true /* generatedByAsssitant */); } @Test @@ -392,11 +401,17 @@ public class SmartReplyViewTest extends SysuiTestCase { } private void setSmartReplies(CharSequence[] choices) { + setSmartReplies(choices, false); + } + + private void setSmartReplies(CharSequence[] choices, boolean fromAssistant) { PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0); RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(choices).build(); + SmartReplyView.SmartReplies smartReplies = + new SmartReplyView.SmartReplies(choices, input, pendingIntent, fromAssistant); mView.resetSmartSuggestions(mContainer); - mView.addRepliesFromRemoteInput(input, pendingIntent, mLogger, mEntry, choices); + mView.addRepliesFromRemoteInput(smartReplies, mLogger, mEntry); } private Notification.Action createAction(String actionTitle) { @@ -415,12 +430,12 @@ public class SmartReplyViewTest extends SysuiTestCase { private void setSmartActions(String[] actionTitles) { mView.resetSmartSuggestions(mContainer); - mView.addSmartActions(createActions(actionTitles)); + mView.addSmartActions(new SmartReplyView.SmartActions(createActions(actionTitles), false)); } private void setSmartRepliesAndActions(CharSequence[] choices, String[] actionTitles) { setSmartReplies(choices); - mView.addSmartActions(createActions(actionTitles)); + mView.addSmartActions(new SmartReplyView.SmartActions(createActions(actionTitles), false)); } private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) { @@ -453,9 +468,11 @@ public class SmartReplyViewTest extends SysuiTestCase { // Add smart replies Button previous = null; + SmartReplyView.SmartReplies smartReplies = + new SmartReplyView.SmartReplies(choices, null, null, false); for (int i = 0; i < choices.length; ++i) { - Button current = mView.inflateReplyButton(mContext, mView, i, choices[i], - null, null, null, null); + Button current = mView.inflateReplyButton(mContext, mView, i, smartReplies, + null, null); current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal, current.getPaddingBottom()); if (previous != null) { diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java index 8d691ffd194d..12e7376b750f 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java @@ -273,33 +273,6 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (DEBUG_ALL) Slog.i(LOG_TAG, "dispatchTransformedEvent(event = " + event + ")"); - - // If the touchscreen event is within the magnified portion of the screen we have - // to change its location to be where the user thinks he is poking the - // UI which may have been magnified and panned. - if (mMagnificationController.isMagnifying() - && event.isFromSource(SOURCE_TOUCHSCREEN) - && mMagnificationController.magnificationRegionContains( - event.getX(), event.getY())) { - final float scale = mMagnificationController.getScale(); - final float scaledOffsetX = mMagnificationController.getOffsetX(); - final float scaledOffsetY = mMagnificationController.getOffsetY(); - final int pointerCount = event.getPointerCount(); - PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount); - PointerProperties[] properties = getTempPointerPropertiesWithMinSize( - pointerCount); - for (int i = 0; i < pointerCount; i++) { - event.getPointerCoords(i, coords[i]); - coords[i].x = (coords[i].x - scaledOffsetX) / scale; - coords[i].y = (coords[i].y - scaledOffsetY) / scale; - event.getPointerProperties(i, properties[i]); - } - event = MotionEvent.obtain(event.getDownTime(), - event.getEventTime(), event.getAction(), pointerCount, properties, - coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(), - event.getFlags()); - } if (DEBUG_EVENT_STREAM) { storeEventInto(mDebugOutputEventHistory, event); try { diff --git a/services/art-profile b/services/art-profile index bdd49de3ef02..af9d7a91ad60 100644 --- a/services/art-profile +++ b/services/art-profile @@ -18849,7 +18849,7 @@ PLcom/android/server/wm/WindowManagerService;->onRectangleOnScreenRequested(Land PLcom/android/server/wm/WindowManagerService;->onSystemUiStarted()V PLcom/android/server/wm/WindowManagerService;->openSession(Landroid/view/IWindowSessionCallback;Lcom/android/internal/view/IInputMethodClient;Lcom/android/internal/view/IInputContext;)Landroid/view/IWindowSession; PLcom/android/server/wm/WindowManagerService;->overridePendingAppTransition(Ljava/lang/String;IILandroid/os/IRemoteCallback;)V -PLcom/android/server/wm/WindowManagerService;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;)V +PLcom/android/server/wm/WindowManagerService;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;I)V PLcom/android/server/wm/WindowManagerService;->performBootTimeout()V PLcom/android/server/wm/WindowManagerService;->performEnableScreen()V PLcom/android/server/wm/WindowManagerService;->postWindowRemoveCleanupLocked(Lcom/android/server/wm/WindowState;)V diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 17d8ea7eb77c..c56f31efd953 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -18,11 +18,13 @@ package com.android.server.autofill; import static android.Manifest.permission.MANAGE_AUTO_FILL; import static android.content.Context.AUTOFILL_MANAGER_SERVICE; +import static android.util.DebugUtils.flagsToString; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sFullScreenMode; import static com.android.server.autofill.Helper.sVerbose; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -72,9 +74,12 @@ import com.android.server.AbstractMasterSystemService; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.autofill.ui.AutoFillUI; +import com.android.server.intelligence.IntelligenceManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -95,6 +100,27 @@ public final class AutofillManagerService private static final Object sLock = AutofillManagerService.class; + + /** + * IME supports Smart Suggestions. + */ + // NOTE: must be public because of flagsToString() + public static final int FLAG_SMART_SUGGESTION_IME = 0x1; + + /** + * System supports Smarts Suggestions (as a popup-window similar to standard Autofill). + */ + // NOTE: must be public because of flagsToString() + public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x2; + + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = { + FLAG_SMART_SUGGESTION_IME, + FLAG_SMART_SUGGESTION_SYSTEM + }) + @Retention(RetentionPolicy.SOURCE) + @interface SmartSuggestionMode {} + static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; private static final char COMPAT_PACKAGE_DELIMITER = ':'; @@ -102,7 +128,6 @@ public final class AutofillManagerService private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '['; private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']'; - /** * Maximum number of partitions that can be allowed in a session. * @@ -130,6 +155,7 @@ public final class AutofillManagerService private final AutofillCompatState mAutofillCompatState = new AutofillCompatState(); private final LocalService mLocalService = new LocalService(); + final IntelligenceManagerInternal mIntelligenceManagerInternal; private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -153,13 +179,21 @@ public final class AutofillManagerService @GuardedBy("mLock") private boolean mAllowInstantService; + /** + * Supported modes for Augmented Autofill Smart Suggestions. + */ + @GuardedBy("mLock") + private int mSupportedSmartSuggestionModes; + public AutofillManagerService(Context context) { super(context, UserManager.DISALLOW_AUTOFILL); mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext()); + mIntelligenceManagerInternal = LocalServices.getService(IntelligenceManagerInternal.class); setLogLevelFromSettings(); setMaxPartitionsFromSettings(); setMaxVisibleDatasetsFromSettings(); + setSmartSuggestionEmulationFromSettings(); final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); @@ -186,6 +220,9 @@ public final class AutofillManagerService resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS), false, observer, + UserHandle.USER_ALL); } @Override // from AbstractMasterSystemService @@ -200,6 +237,9 @@ public final class AutofillManagerService case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS: setMaxVisibleDatasetsFromSettings(); break; + case Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS: + setSmartSuggestionEmulationFromSettings(); + break; default: Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead"); // fall through @@ -243,6 +283,10 @@ public final class AutofillManagerService mUi.hideAll(null); } + @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() { + return mSupportedSmartSuggestionModes; + } + // Called by Shell command. void destroySessions(@UserIdInt int userId, IResultReceiver receiver) { Slog.i(TAG, "destroySessions() for userId " + userId); @@ -420,6 +464,19 @@ public final class AutofillManagerService } } + private void setSmartSuggestionEmulationFromSettings() { + final int flags = Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, 0); + if (sDebug) { + Slog.d(TAG, "setSmartSuggestionEmulationFromSettings(): " + + smartSuggestionFlagsToString(flags)); + } + + synchronized (mLock) { + mSupportedSmartSuggestionModes = flags; + } + } + // Called by Shell command. void getScore(@Nullable String algorithmName, @NonNull String value1, @NonNull String value2, @NonNull RemoteCallback callback) { @@ -610,6 +667,10 @@ public final class AutofillManagerService } } + static String smartSuggestionFlagsToString(int flags) { + return flagsToString(AutofillManagerService.class, "FLAG_SMART_SUGGESTION_", flags); + } + private final class LocalService extends AutofillManagerInternal { @Override public void onBackKeyPressed() { @@ -1158,6 +1219,10 @@ public final class AutofillManagerService pw.print("from settings: "); pw.println(getWhitelistedCompatModePackagesFromSettings()); pw.print("Allow instant service: "); pw.println(mAllowInstantService); + if (mSupportedSmartSuggestionModes != 0) { + pw.print("Smart Suggestion modes: "); + pw.println(smartSuggestionFlagsToString(mSupportedSmartSuggestionModes)); + } if (showHistory) { pw.println(); pw.println("Requests history:"); pw.println(); mRequestsHistory.reverseDump(fd, pw, args); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 67ccc9b18543..0df99d4b6642 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -73,6 +73,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.AbstractPerUserSystemService; import com.android.server.LocalServices; import com.android.server.autofill.AutofillManagerService.AutofillCompatState; +import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode; import com.android.server.autofill.ui.AutoFillUI; import java.io.PrintWriter; @@ -268,8 +269,8 @@ final class AutofillManagerServiceImpl pruneAbandonedSessionsLocked(); final Session newSession = createSessionByTokenLocked(activityToken, taskId, uid, - appCallbackToken, hasCallback, componentName, compatMode, bindInstantServiceAllowed, - flags); + appCallbackToken, hasCallback, componentName, compatMode, + bindInstantServiceAllowed, flags); if (newSession == null) { return NO_SESSION; } @@ -823,6 +824,12 @@ final class AutofillManagerServiceImpl return true; } + @GuardedBy("mLock") + @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() { + // TODO(b/111330312): once we support IME, we need to set it per-user (OR'ed with master) + return mMaster.getSupportedSmartSuggestionModesLocked(); + } + @Override @GuardedBy("mLock") protected void dumpLocked(String prefix, PrintWriter pw) { @@ -962,6 +969,9 @@ final class AutofillManagerServiceImpl if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id); session.forceRemoveSelfLocked(); } + else { + session.destroyAugmentedAutofillWindowsLocked(); + } } } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 1ff1acdb3b57..8676f7f5bea0 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -25,6 +25,9 @@ import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED; import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import static com.android.server.autofill.AutofillManagerService.FLAG_SMART_SUGGESTION_IME; +import static com.android.server.autofill.AutofillManagerService.FLAG_SMART_SUGGESTION_SYSTEM; +import static com.android.server.autofill.AutofillManagerService.smartSuggestionFlagsToString; import static com.android.server.autofill.Helper.getNumericValue; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sVerbose; @@ -93,8 +96,11 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; import com.android.server.AbstractRemoteService; +import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode; import com.android.server.autofill.ui.AutoFillUI; import com.android.server.autofill.ui.PendingUi; +import com.android.server.intelligence.IntelligenceManagerInternal; +import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback; import java.io.PrintWriter; import java.util.ArrayList; @@ -242,6 +248,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private final SparseArray<LogMaker> mRequestLogs = new SparseArray<>(1); + @GuardedBy("mLock") + @Nullable + private AugmentedAutofillCallback mAugmentedAutofillCallback; + /** * Receiver of assist data from the app's {@link Activity}. */ @@ -2497,15 +2507,83 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState processResponseLocked(newResponse, newClientState, 0); } + @GuardedBy("mLock") private void processNullResponseLocked(int flags) { - if (sVerbose) Slog.v(TAG, "canceling session " + id + " when server returned null"); if ((flags & FLAG_MANUAL_REQUEST) != 0) { getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this); } mService.resetLastResponse(); - // Nothing to be done, but need to notify client. - notifyUnavailableToClient(AutofillManager.STATE_FINISHED); - removeSelf(); + + // The default autofill service cannot fullfill the request, let's check if the intelligence + // service can. + mAugmentedAutofillCallback = triggerAugmentedAutofillLocked(); + if (mAugmentedAutofillCallback == null) { + if (sVerbose) { + Slog.v(TAG, "canceling session " + id + " when server returned null and there is no" + + " AugmentedAutofill for user"); + } + // Nothing to be done, but need to notify client. + notifyUnavailableToClient(AutofillManager.STATE_FINISHED); + removeSelf(); + } else { + // TODO(b/111330312, b/119638958): must set internal state so when user focus other + // fields it does not generate a new call to the standard autofill service (right now + // it does). Must also add CTS tests to exercise this scenario. + if (sVerbose) { + Slog.v(TAG, "keeping session " + id + " when server returned null but " + + "there is an AugmentedAutofill for user"); + } + } + } + + /** + * Tries to trigger Augmented Autofill when the standard service could not fulfill a request. + * + * @return callback to the Augmented Autofill service, or {@code null} if not supported. + */ + // TODO(b/111330312): might need to call it in other places, like when the service returns a + // non-null response but without datasets (for example, just SaveInfo) + @GuardedBy("mLock") + private AugmentedAutofillCallback triggerAugmentedAutofillLocked() { + // Check if Smart Suggestions is supported... + final @SmartSuggestionMode int supportedModes = mService + .getSupportedSmartSuggestionModesLocked(); + if (supportedModes == 0) return null; + + // ...then if the service is set for the user + final IntelligenceManagerInternal intelligenceManagerInternal = mService + .getMaster().mIntelligenceManagerInternal; + if (intelligenceManagerInternal == null) return null; + + // Define which mode will be used + final int mode; + if ((supportedModes & FLAG_SMART_SUGGESTION_IME) != 0) { + // TODO(b/111330312): support it :-) + Slog.w(TAG, "Smart Suggestions on IME not supported yet"); + return null; + } else if ((supportedModes & FLAG_SMART_SUGGESTION_SYSTEM) != 0) { + mode = FLAG_SMART_SUGGESTION_SYSTEM; + } else { + Slog.w(TAG, "Unsupported Smart Suggestion Mode: " + supportedModes); + return null; + } + + if (mCurrentViewId == null) { + Slog.w(TAG, "triggerAugmentedAutofillLocked(): no view currently focused"); + return null; + } + + if (sVerbose) { + Slog.v(TAG, "calling IntelligenseService on view " + mCurrentViewId + + " using suggestion mode " + smartSuggestionFlagsToString(mode) + + " when server returned null for session " + this.id); + } + + // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize + // furgher AFM -> AFMS calls. + // TODO(b/119638958): add CTS tests + return intelligenceManagerInternal.requestAutofill(mService.getUserId(), mClient, + mActivityToken, this.id, mCurrentViewId); } @GuardedBy("mLock") @@ -2786,6 +2864,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println( mSaveOnAllViewsInvisible); pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds); + if (mAugmentedAutofillCallback != null) { + pw.print(prefix); pw.println("has AugmentedAutofillCallback"); + } mRemoteFillService.dump(prefix, pw); } @@ -2957,6 +3038,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.e(TAG, "Error notifying client to finish session", e); } } + destroyAugmentedAutofillWindowsLocked(); + } + + @GuardedBy("mLock") + void destroyAugmentedAutofillWindowsLocked() { + if (mAugmentedAutofillCallback != null) { + mAugmentedAutofillCallback.destroy(); + } } /** diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java index df46d260b961..ab639c3c9ce1 100644 --- a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java +++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java @@ -16,12 +16,15 @@ package com.android.server.backup; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; + import android.content.ContentResolver; import android.os.Handler; import android.provider.Settings; import android.util.KeyValueListParser; import android.util.KeyValueSettingObserver; import android.util.Slog; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -137,7 +140,7 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getKvBackupAgentTimeoutMillis() { synchronized (mLock) { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v(TAG, "getKvBackupAgentTimeoutMillis(): " + mKvBackupAgentTimeoutMillis); } return mKvBackupAgentTimeoutMillis; @@ -146,7 +149,7 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getFullBackupAgentTimeoutMillis() { synchronized (mLock) { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v(TAG, "getFullBackupAgentTimeoutMillis(): " + mFullBackupAgentTimeoutMillis); } return mFullBackupAgentTimeoutMillis; @@ -155,7 +158,7 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getSharedBackupAgentTimeoutMillis() { synchronized (mLock) { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getSharedBackupAgentTimeoutMillis(): " + mSharedBackupAgentTimeoutMillis); @@ -166,7 +169,7 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getRestoreAgentTimeoutMillis() { synchronized (mLock) { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v(TAG, "getRestoreAgentTimeoutMillis(): " + mRestoreAgentTimeoutMillis); } return mRestoreAgentTimeoutMillis; @@ -175,7 +178,7 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getRestoreAgentFinishedTimeoutMillis() { synchronized (mLock) { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getRestoreAgentFinishedTimeoutMillis(): " @@ -187,7 +190,7 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getQuotaExceededTimeoutMillis() { synchronized (mLock) { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getQuotaExceededTimeoutMillis(): " diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java index ec219615dfd4..e3fa0dc3c509 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java +++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java @@ -16,6 +16,8 @@ package com.android.server.backup; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; + import android.app.AlarmManager; import android.content.ContentResolver; import android.os.Handler; @@ -24,6 +26,7 @@ import android.text.TextUtils; import android.util.KeyValueListParser; import android.util.KeyValueSettingObserver; import android.util.Slog; + import com.android.internal.annotations.VisibleForTesting; /** @@ -151,7 +154,7 @@ public class BackupManagerConstants extends KeyValueSettingObserver { // group the calls of these methods in a block syncrhonized on // a reference of this object. public synchronized long getKeyValueBackupIntervalMilliseconds() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getKeyValueBackupIntervalMilliseconds(...) returns " @@ -161,7 +164,7 @@ public class BackupManagerConstants extends KeyValueSettingObserver { } public synchronized long getKeyValueBackupFuzzMilliseconds() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getKeyValueBackupFuzzMilliseconds(...) returns " @@ -171,7 +174,7 @@ public class BackupManagerConstants extends KeyValueSettingObserver { } public synchronized boolean getKeyValueBackupRequireCharging() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getKeyValueBackupRequireCharging(...) returns " @@ -181,7 +184,7 @@ public class BackupManagerConstants extends KeyValueSettingObserver { } public synchronized int getKeyValueBackupRequiredNetworkType() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getKeyValueBackupRequiredNetworkType(...) returns " @@ -191,7 +194,7 @@ public class BackupManagerConstants extends KeyValueSettingObserver { } public synchronized long getFullBackupIntervalMilliseconds() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getFullBackupIntervalMilliseconds(...) returns " @@ -201,14 +204,14 @@ public class BackupManagerConstants extends KeyValueSettingObserver { } public synchronized boolean getFullBackupRequireCharging() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v(TAG, "getFullBackupRequireCharging(...) returns " + mFullBackupRequireCharging); } return mFullBackupRequireCharging; } public synchronized int getFullBackupRequiredNetworkType() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getFullBackupRequiredNetworkType(...) returns " @@ -219,7 +222,7 @@ public class BackupManagerConstants extends KeyValueSettingObserver { /** Returns an array of package names that should be notified whenever a backup finishes. */ public synchronized String[] getBackupFinishedNotificationReceivers() { - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v( TAG, "getBackupFinishedNotificationReceivers(...) returns " diff --git a/services/backup/java/com/android/server/backup/FileMetadata.java b/services/backup/java/com/android/server/backup/FileMetadata.java index fe75041eeaca..84d987de3b22 100644 --- a/services/backup/java/com/android/server/backup/FileMetadata.java +++ b/services/backup/java/com/android/server/backup/FileMetadata.java @@ -16,7 +16,7 @@ package com.android.server.backup; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.app.backup.BackupAgent; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java index 82638b4ecee4..ce024765b4db 100644 --- a/services/backup/java/com/android/server/backup/FullBackupJob.java +++ b/services/backup/java/com/android/server/backup/FullBackupJob.java @@ -61,7 +61,7 @@ public class FullBackupJob extends JobService { @Override public boolean onStartJob(JobParameters params) { mParams = params; - Trampoline service = BackupManagerService.getInstance(); + Trampoline service = GlobalBackupManagerService.getInstance(); return service.beginFullBackup(this); } @@ -69,7 +69,7 @@ public class FullBackupJob extends JobService { public boolean onStopJob(JobParameters params) { if (mParams != null) { mParams = null; - Trampoline service = BackupManagerService.getInstance(); + Trampoline service = GlobalBackupManagerService.getInstance(); service.endFullBackup(); } return false; diff --git a/services/backup/java/com/android/server/backup/GlobalBackupManagerService.java b/services/backup/java/com/android/server/backup/GlobalBackupManagerService.java new file mode 100644 index 000000000000..9a1662e702ae --- /dev/null +++ b/services/backup/java/com/android/server/backup/GlobalBackupManagerService.java @@ -0,0 +1,633 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.backup; + +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.backup.IBackupManagerMonitor; +import android.app.backup.IBackupObserver; +import android.app.backup.IFullBackupRestoreObserver; +import android.app.backup.IRestoreSession; +import android.app.backup.ISelectBackupTransportCallback; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Environment; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.Trace; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemConfig; +import com.android.server.SystemService; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collections; +import java.util.Set; + +/** + * Definition of the system service that performs backup/restore operations. + * + * <p>This class is responsible for handling user-aware operations and acts as a delegator, routing + * incoming calls to the appropriate per-user {@link UserBackupManagerService} to handle the + * corresponding backup/restore operation. + */ +public class GlobalBackupManagerService { + public static final String TAG = "BackupManagerService"; + public static final boolean DEBUG = true; + public static final boolean MORE_DEBUG = false; + public static final boolean DEBUG_SCHEDULING = true; + + // File containing backup-enabled state. Contains a single byte to denote enabled status. + // Nonzero is enabled; file missing or a zero byte is disabled. + private static final String BACKUP_ENABLE_FILE = "backup_enabled"; + + // The published binder is a singleton Trampoline object that calls through to the proper code. + // This indirection lets us turn down the heavy implementation object on the fly without + // disturbing binders that have been cached elsewhere in the system. + private static Trampoline sInstance; + + static Trampoline getInstance() { + // Always constructed during system bring up, so no need to lazy-init. + return sInstance; + } + + /** Helper to create the {@link GlobalBackupManagerService} instance. */ + public static GlobalBackupManagerService create( + Context context, + Trampoline parent, + HandlerThread backupThread) { + // Set up our transport options and initialize the default transport + SystemConfig systemConfig = SystemConfig.getInstance(); + Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist(); + if (transportWhitelist == null) { + transportWhitelist = Collections.emptySet(); + } + + String transport = + Settings.Secure.getString( + context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT); + if (TextUtils.isEmpty(transport)) { + transport = null; + } + if (DEBUG) { + Slog.v(TAG, "Starting with transport " + transport); + } + TransportManager transportManager = + new TransportManager( + context, + transportWhitelist, + transport); + + // If encrypted file systems is enabled or disabled, this call will return the + // correct directory. + File baseStateDir = new File(Environment.getDataDirectory(), "backup"); + + // This dir on /cache is managed directly in init.rc + File dataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage"); + + return new GlobalBackupManagerService( + context, + parent, + backupThread, + baseStateDir, + dataDir, + transportManager); + } + + private UserBackupManagerService mUserBackupManagerService; + + /** Instantiate a new instance of {@link GlobalBackupManagerService}. */ + public GlobalBackupManagerService( + Context context, + Trampoline trampoline, + HandlerThread backupThread, + File baseStateDir, + File dataDir, + TransportManager transportManager) { + mUserBackupManagerService = + new UserBackupManagerService( + context, trampoline, backupThread, baseStateDir, dataDir, transportManager); + } + + // TODO(b/118520567): Remove when tests are modified to use per-user instance. + @VisibleForTesting + void setUserBackupManagerService(UserBackupManagerService userBackupManagerService) { + mUserBackupManagerService = userBackupManagerService; + } + + /** + * Called through Trampoline from {@link Lifecycle#onUnlockUser(int)}. We run the heavy work on + * a background thread to keep the unlock time down. + */ + public void unlockSystemUser() { + // Migrate legacy setting + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate"); + if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) { + if (DEBUG) { + Slog.i(TAG, "Backup enable apparently not migrated"); + } + ContentResolver resolver = sInstance.getContext().getContentResolver(); + int enableState = Settings.Secure.getIntForUser(resolver, + Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM); + if (enableState >= 0) { + if (DEBUG) { + Slog.i(TAG, "Migrating enable state " + (enableState != 0)); + } + writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM); + Settings.Secure.putStringForUser(resolver, + Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM); + } else { + if (DEBUG) { + Slog.i(TAG, "Backup not yet configured; retaining null enable state"); + } + } + } + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); + try { + sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM)); + } catch (RemoteException e) { + // can't happen; it's a local object + } + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + + /* + * The following methods are implementations of IBackupManager methods called from Trampoline. + * They delegate to the appropriate per-user instance of UserBackupManagerService to perform the + * action on the passed in user. Currently this is a straight redirection (see TODO). + */ + // TODO (b/118520567): Take in user id and call per-user instance of UserBackupManagerService. + + // --------------------------------------------- + // BACKUP AGENT OPERATIONS + // --------------------------------------------- + + /** + * An app's backup agent calls this method to let the service know that there's new data to + * backup for their app {@code packageName}. Only used for apps participating in key-value + * backup. + */ + public void dataChanged(String packageName) { + mUserBackupManagerService.dataChanged(packageName); + } + + /** + * Callback: a requested backup agent has been instantiated. This should only be called from the + * {@link ActivityManager}. + */ + public void agentConnected(String packageName, IBinder agentBinder) { + mUserBackupManagerService.agentConnected(packageName, agentBinder); + } + + /** + * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be + * called from the {@link ActivityManager}. + */ + public void agentDisconnected(String packageName) { + mUserBackupManagerService.agentDisconnected(packageName); + } + + /** + * Used by a currently-active backup agent to notify the service that it has completed its given + * outstanding asynchronous backup/restore operation. + */ + public void opComplete(int token, long result) { + mUserBackupManagerService.opComplete(token, result); + } + + // --------------------------------------------- + // TRANSPORT OPERATIONS + // --------------------------------------------- + + /** Run an initialize operation for the given transports {@code transportNames}. */ + public void initializeTransports(String[] transportNames, IBackupObserver observer) { + mUserBackupManagerService.initializeTransports(transportNames, observer); + } + + /** + * Clear the given package {@code packageName}'s backup data from the transport {@code + * transportName}. + */ + public void clearBackupData(String transportName, String packageName) { + mUserBackupManagerService.clearBackupData(transportName, packageName); + } + + /** Return the name of the currently active transport. */ + public String getCurrentTransport() { + return mUserBackupManagerService.getCurrentTransport(); + } + + /** + * Returns the {@link ComponentName} of the host service of the selected transport or {@code + * null} if no transport selected or if the transport selected is not registered. + */ + public ComponentName getCurrentTransportComponent() { + return mUserBackupManagerService.getCurrentTransportComponent(); + } + + /** Report all known, available backup transports by name. */ + public String[] listAllTransports() { + return mUserBackupManagerService.listAllTransports(); + } + + /** Report all known, available backup transports by {@link ComponentName}. */ + public ComponentName[] listAllTransportComponents() { + return mUserBackupManagerService.listAllTransportComponents(); + } + + /** Report all system whitelisted transports. */ + public String[] getTransportWhitelist() { + return mUserBackupManagerService.getTransportWhitelist(); + } + + /** + * Update the attributes of the transport identified by {@code transportComponent}. If the + * specified transport has not been bound at least once (for registration), this call will be + * ignored. Only the host process of the transport can change its description, otherwise a + * {@link SecurityException} will be thrown. + * + * @param transportComponent The identity of the transport being described. + * @param name A {@link String} with the new name for the transport. This is NOT for + * identification. MUST NOT be {@code null}. + * @param configurationIntent An {@link Intent} that can be passed to {@link + * Context#startActivity} in order to launch the transport's configuration UI. It may be + * {@code null} if the transport does not offer any user-facing configuration UI. + * @param currentDestinationString A {@link String} describing the destination to which the + * transport is currently sending data. MUST NOT be {@code null}. + * @param dataManagementIntent An {@link Intent} that can be passed to {@link + * Context#startActivity} in order to launch the transport's data-management UI. It may be + * {@code null} if the transport does not offer any user-facing data management UI. + * @param dataManagementLabel A {@link String} to be used as the label for the transport's data + * management affordance. This MUST be {@code null} when dataManagementIntent is {@code + * null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}. + * @throws SecurityException If the UID of the calling process differs from the package UID of + * {@code transportComponent} or if the caller does NOT have BACKUP permission. + */ + public void updateTransportAttributes( + ComponentName transportComponent, + String name, + @Nullable Intent configurationIntent, + String currentDestinationString, + @Nullable Intent dataManagementIntent, + String dataManagementLabel) { + mUserBackupManagerService.updateTransportAttributes( + transportComponent, + name, + configurationIntent, + currentDestinationString, + dataManagementIntent, + dataManagementLabel); + } + + /** + * Selects transport {@code transportName} and returns the previously selected transport. + * + * @deprecated Use {@link #selectBackupTransportAsync(ComponentName, + * ISelectBackupTransportCallback)} instead. + */ + @Deprecated + @Nullable + public String selectBackupTransport(String transportName) { + return mUserBackupManagerService.selectBackupTransport(transportName); + } + + /** + * Selects transport {@code transportComponent} asynchronously and notifies {@code listener} + * with the result upon completion. + */ + public void selectBackupTransportAsync( + ComponentName transportComponent, ISelectBackupTransportCallback listener) { + mUserBackupManagerService.selectBackupTransportAsync(transportComponent, listener); + } + + /** + * Supply the configuration intent for the given transport. If the name is not one of the + * available transports, or if the transport does not supply any configuration UI, the method + * returns {@code null}. + */ + public Intent getConfigurationIntent(String transportName) { + return mUserBackupManagerService.getConfigurationIntent(transportName); + } + + /** + * Supply the current destination string for the given transport. If the name is not one of the + * registered transports the method will return null. + * + * <p>This string is used VERBATIM as the summary text of the relevant Settings item. + * + * @param transportName The name of the registered transport. + * @return The current destination string or null if the transport is not registered. + */ + public String getDestinationString(String transportName) { + return mUserBackupManagerService.getDestinationString(transportName); + } + + /** Supply the manage-data intent for the given transport. */ + public Intent getDataManagementIntent(String transportName) { + return mUserBackupManagerService.getDataManagementIntent(transportName); + } + + /** + * Supply the menu label for affordances that fire the manage-data intent for the given + * transport. + */ + public String getDataManagementLabel(String transportName) { + return mUserBackupManagerService.getDataManagementLabel(transportName); + } + + // --------------------------------------------- + // SETTINGS OPERATIONS + // --------------------------------------------- + + /** Enable/disable the backup service. This is user-configurable via backup settings. */ + public void setBackupEnabled(boolean enable) { + mUserBackupManagerService.setBackupEnabled(enable); + } + + /** Enable/disable automatic restore of app data at install time. */ + public void setAutoRestore(boolean autoRestore) { + mUserBackupManagerService.setAutoRestore(autoRestore); + } + + /** Mark the backup service as having been provisioned (device has gone through SUW). */ + public void setBackupProvisioned(boolean provisioned) { + mUserBackupManagerService.setBackupProvisioned(provisioned); + } + + /** + * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}. + */ + public boolean isBackupEnabled() { + return mUserBackupManagerService.isBackupEnabled(); + } + + // --------------------------------------------- + // BACKUP OPERATIONS + // --------------------------------------------- + + /** Checks if the given package {@code packageName} is eligible for backup. */ + public boolean isAppEligibleForBackup(String packageName) { + return mUserBackupManagerService.isAppEligibleForBackup(packageName); + } + + /** + * Returns from the inputted packages {@code packages}, the ones that are eligible for backup. + */ + public String[] filterAppsEligibleForBackup(String[] packages) { + return mUserBackupManagerService.filterAppsEligibleForBackup(packages); + } + + /** + * Run a backup pass immediately for any key-value backup applications that have declared that + * they have pending updates. + */ + public void backupNow() { + mUserBackupManagerService.backupNow(); + } + + /** + * Requests a backup for the inputted {@code packages} with a specified callback {@link + * IBackupManagerMonitor} for receiving events during the operation. + */ + public int requestBackup( + String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor, int flags) { + return mUserBackupManagerService.requestBackup(packages, observer, monitor, flags); + } + + /** Cancel all running backup operations. */ + public void cancelBackups() { + mUserBackupManagerService.cancelBackups(); + } + + /** + * Used by the {@link JobScheduler} to run a full backup when conditions are right. The model we + * use is to perform one app backup per scheduled job execution, and to reschedule the job with + * zero latency as long as conditions remain right and we still have work to do. + * + * @return Whether ongoing work will continue. The return value here will be passed along as the + * return value to the callback {@link JobService#onStartJob(JobParameters)}. + */ + public boolean beginFullBackup(FullBackupJob scheduledJob) { + return mUserBackupManagerService.beginFullBackup(scheduledJob); + } + + /** + * Used by the {@link JobScheduler} to end the current full backup task when conditions are no + * longer met for running the full backup job. + */ + public void endFullBackup() { + mUserBackupManagerService.endFullBackup(); + } + + /** + * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'. + */ + public void fullTransportBackup(String[] packageNames) { + mUserBackupManagerService.fullTransportBackup(packageNames); + } + + // --------------------------------------------- + // RESTORE OPERATIONS + // --------------------------------------------- + + /** + * Used to run a restore pass for an application that is being installed. This should only be + * called from the {@link PackageManager}. + */ + public void restoreAtInstall(String packageName, int token) { + mUserBackupManagerService.restoreAtInstall(packageName, token); + } + + /** + * Begin a restore for the specified package {@code packageName} using the specified transport + * {@code transportName}. + */ + public IRestoreSession beginRestoreSession(String packageName, String transportName) { + return mUserBackupManagerService.beginRestoreSession(packageName, transportName); + } + + /** + * Get the restore-set token for the best-available restore set for this {@code packageName}: + * the active set if possible, else the ancestral one. Returns zero if none available. + */ + public long getAvailableRestoreToken(String packageName) { + return mUserBackupManagerService.getAvailableRestoreToken(packageName); + } + + // --------------------------------------------- + // ADB BACKUP/RESTORE OPERATIONS + // --------------------------------------------- + + /** Sets the backup password used when running adb backup. */ + public boolean setBackupPassword(String currentPassword, String newPassword) { + return mUserBackupManagerService.setBackupPassword(currentPassword, newPassword); + } + + /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */ + public boolean hasBackupPassword() { + return mUserBackupManagerService.hasBackupPassword(); + } + + /** + * Used by 'adb backup' to run a backup pass for packages {@code packageNames} supplied via the + * command line, writing the resulting data stream to the supplied {@code fd}. This method is + * synchronous and does not return to the caller until the backup has been completed. It + * requires on-screen confirmation by the user. + */ + public void adbBackup( + ParcelFileDescriptor fd, + boolean includeApks, + boolean includeObbs, + boolean includeShared, + boolean doWidgets, + boolean doAllApps, + boolean includeSystem, + boolean doCompress, + boolean doKeyValue, + String[] packageNames) { + mUserBackupManagerService.adbBackup( + fd, + includeApks, + includeObbs, + includeShared, + doWidgets, + doAllApps, + includeSystem, + doCompress, + doKeyValue, + packageNames); + } + + /** + * Used by 'adb restore' to run a restore pass reading from the supplied {@code fd}. This method + * is synchronous and does not return to the caller until the restore has been completed. It + * requires on-screen confirmation by the user. + */ + public void adbRestore(ParcelFileDescriptor fd) { + mUserBackupManagerService.adbRestore(fd); + } + + /** + * Confirm that the previously requested adb backup/restore operation can proceed. This is used + * to require a user-facing disclosure about the operation. + */ + public void acknowledgeAdbBackupOrRestore( + int token, + boolean allow, + String currentPassword, + String encryptionPassword, + IFullBackupRestoreObserver observer) { + mUserBackupManagerService.acknowledgeAdbBackupOrRestore( + token, allow, currentPassword, encryptionPassword, observer); + } + + // --------------------------------------------- + // SERVICE OPERATIONS + // --------------------------------------------- + + /** Prints service state for 'dumpsys backup'. */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mUserBackupManagerService.dump(fd, pw, args); + } + + private static boolean backupSettingMigrated(int userId) { + File base = new File(Environment.getDataDirectory(), "backup"); + File enableFile = new File(base, BACKUP_ENABLE_FILE); + return enableFile.exists(); + } + + private static boolean readBackupEnableState(int userId) { + File base = new File(Environment.getDataDirectory(), "backup"); + File enableFile = new File(base, BACKUP_ENABLE_FILE); + if (enableFile.exists()) { + try (FileInputStream fin = new FileInputStream(enableFile)) { + int state = fin.read(); + return state != 0; + } catch (IOException e) { + // can't read the file; fall through to assume disabled + Slog.e(TAG, "Cannot read enable state; assuming disabled"); + } + } else { + if (DEBUG) { + Slog.i(TAG, "isBackupEnabled() => false due to absent settings file"); + } + } + return false; + } + + static void writeBackupEnableState(boolean enable, int userId) { + File base = new File(Environment.getDataDirectory(), "backup"); + File enableFile = new File(base, BACKUP_ENABLE_FILE); + File stage = new File(base, BACKUP_ENABLE_FILE + "-stage"); + try (FileOutputStream fout = new FileOutputStream(stage)) { + fout.write(enable ? 1 : 0); + fout.close(); + stage.renameTo(enableFile); + // will be synced immediately by the try-with-resources call to close() + } catch (IOException | RuntimeException e) { + // Whoops; looks like we're doomed. Roll everything out, disabled, + // including the legacy state. + Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: " + + e.getMessage()); + + ContentResolver resolver = sInstance.getContext().getContentResolver(); + Settings.Secure.putStringForUser(resolver, + Settings.Secure.BACKUP_ENABLED, null, userId); + enableFile.delete(); + stage.delete(); + } + } + + /** Implementation to receive lifecycle event callbacks for system services. */ + public static final class Lifecycle extends SystemService { + public Lifecycle(Context context) { + super(context); + sInstance = new Trampoline(context); + } + + @Override + public void onStart() { + publishBinderService(Context.BACKUP_SERVICE, sInstance); + } + + @Override + public void onUnlockUser(int userId) { + if (userId == UserHandle.USER_SYSTEM) { + sInstance.unlockSystemUser(); + } + } + } +} diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java index 125c2250d7d1..92c2ee4c4e71 100644 --- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java @@ -5,7 +5,8 @@ import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; -import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; @@ -50,7 +51,7 @@ public class KeyValueAdbBackupEngine { private static final String BACKUP_KEY_VALUE_BACKUP_DATA_FILENAME_SUFFIX = ".data"; private static final String BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX = ".new"; - private BackupManagerService mBackupManagerService; + private UserBackupManagerService mBackupManagerService; private final PackageManager mPackageManager; private final OutputStream mOutput; private final PackageInfo mCurrentPackage; @@ -66,7 +67,7 @@ public class KeyValueAdbBackupEngine { private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public KeyValueAdbBackupEngine(OutputStream output, PackageInfo packageInfo, - BackupManagerService backupManagerService, PackageManager packageManager, + UserBackupManagerService backupManagerService, PackageManager packageManager, File baseStateDir, File dataDir) { mOutput = output; mCurrentPackage = packageInfo; @@ -85,7 +86,7 @@ public class KeyValueAdbBackupEngine { mNewStateName = new File(mStateDir, pkg + BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX); - mManifestFile = new File(mDataDir, BackupManagerService.BACKUP_MANIFEST_FILENAME); + mManifestFile = new File(mDataDir, BACKUP_MANIFEST_FILENAME); mAgentTimeoutParameters = Preconditions.checkNotNull( backupManagerService.getAgentTimeoutParameters(), "Timeout parameters cannot be null"); diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java index bb145769fc8c..bed520e9f068 100644 --- a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java @@ -39,7 +39,7 @@ public class KeyValueAdbRestoreEngine implements Runnable { private static final String TAG = "KeyValueAdbRestoreEngine"; private static final boolean DEBUG = false; - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; private final File mDataDir; FileMetadata mInfo; @@ -48,7 +48,7 @@ public class KeyValueAdbRestoreEngine implements Runnable { IBackupAgent mAgent; int mToken; - public KeyValueAdbRestoreEngine(BackupManagerService backupManagerService, + public KeyValueAdbRestoreEngine(UserBackupManagerService backupManagerService, File dataDir, FileMetadata info, ParcelFileDescriptor inFD, IBackupAgent agent, int token) { mBackupManagerService = backupManagerService; diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java index c805783103be..8156095cf576 100644 --- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java +++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java @@ -16,6 +16,8 @@ package com.android.server.backup; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; + import android.app.AlarmManager; import android.app.job.JobInfo; import android.app.job.JobParameters; @@ -71,7 +73,7 @@ public class KeyValueBackupJob extends JobService { if (delay <= 0) { delay = interval + new Random().nextInt((int) fuzz); } - if (BackupManagerService.DEBUG_SCHEDULING) { + if (DEBUG_SCHEDULING) { Slog.v(TAG, "Scheduling k/v pass in " + (delay / 1000 / 60) + " minutes"); } JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sKeyValueJobService) @@ -116,7 +118,7 @@ public class KeyValueBackupJob extends JobService { } // Time to run a key/value backup! - Trampoline service = BackupManagerService.getInstance(); + Trampoline service = GlobalBackupManagerService.getInstance(); try { service.backupNow(); } catch (RemoteException e) {} diff --git a/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java b/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java index b5db5e2c5850..dd91381779e4 100644 --- a/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java +++ b/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java @@ -23,8 +23,8 @@ import com.android.internal.annotations.GuardedBy; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.EOFException; -import java.io.FileInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.util.HashSet; @@ -46,7 +46,7 @@ import java.util.Set; final class ProcessedPackagesJournal { private static final String TAG = "ProcessedPackagesJournal"; private static final String JOURNAL_FILE_NAME = "processed"; - private static final boolean DEBUG = BackupManagerService.DEBUG || false; + private static final boolean DEBUG = GlobalBackupManagerService.DEBUG; // using HashSet instead of ArraySet since we expect 100-500 elements range @GuardedBy("mProcessedPackages") diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java index 32fd7e0f1607..22edebc982dd 100644 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -16,7 +16,7 @@ package com.android.server.backup; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.annotation.Nullable; import android.app.admin.DevicePolicyManager; @@ -42,20 +42,22 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.util.Slog; + import com.android.internal.annotations.GuardedBy; import com.android.internal.util.DumpUtils; + import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; /** - * A proxy to BackupManagerService implementation. + * A proxy to the {@link GlobalBackupManagerService} implementation. * - * <p>This is an external interface to the BackupManagerService which is being accessed via - * published binder (see BackupManagerService$Lifecycle). This lets us turn down the heavy - * implementation object on the fly without disturbing binders that have been cached somewhere in - * the system. + * <p>This is an external interface to the {@link GlobalBackupManagerService} which is being + * accessed via published binder {@link GlobalBackupManagerService.Lifecycle}. This lets us turn + * down the heavy implementation object on the fly without disturbing binders that have been cached + * somewhere in the system. * * <p>Trampoline determines whether the backup service is available. It can be disabled in the * following two ways: @@ -87,7 +89,7 @@ public class Trampoline extends IBackupManager.Stub { private final boolean mGlobalDisable; private final Object mStateLock = new Object(); - private volatile BackupManagerService mService; + private volatile GlobalBackupManagerService mService; private HandlerThread mHandlerThread; public Trampoline(Context context) { @@ -114,12 +116,12 @@ public class Trampoline extends IBackupManager.Stub { return mContext; } - protected BackupManagerService createBackupManagerService() { - return BackupManagerService.create(mContext, this, mHandlerThread); + protected GlobalBackupManagerService createBackupManagerService() { + return GlobalBackupManagerService.create(mContext, this, mHandlerThread); } /** - * Initialize {@link BackupManagerService} if the backup service is not disabled. Only the + * Initialize {@link GlobalBackupManagerService} if the backup service is not disabled. Only the * system user can initialize the service. */ /* package */ void initializeService(int userId) { @@ -143,10 +145,11 @@ public class Trampoline extends IBackupManager.Stub { } /** - * Called from {@link BackupManagerService$Lifecycle} when the system user is unlocked. Attempts - * to initialize {@link BackupManagerService} and set backup state for the system user. + * Called from {@link GlobalBackupManagerService.Lifecycle} when the system user is unlocked. + * Attempts to initialize {@link GlobalBackupManagerService} and set backup state for the system + * user. * - * @see BackupManagerService#unlockSystemUser() + * @see GlobalBackupManagerService#unlockSystemUser() */ void unlockSystemUser() { mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); @@ -159,7 +162,7 @@ public class Trampoline extends IBackupManager.Stub { initializeService(UserHandle.USER_SYSTEM); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - BackupManagerService service = mService; + GlobalBackupManagerService service = mService; if (service != null) { Slog.i(TAG, "Unlocking system user"); service.unlockSystemUser(); @@ -231,7 +234,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void dataChanged(String packageName) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.dataChanged(packageName); } @@ -240,7 +243,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void initializeTransports(String[] transportNames, IBackupObserver observer) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.initializeTransports(transportNames, observer); } @@ -249,7 +252,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void clearBackupData(String transportName, String packageName) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.clearBackupData(transportName, packageName); } @@ -257,7 +260,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void agentConnected(String packageName, IBinder agent) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.agentConnected(packageName, agent); } @@ -265,7 +268,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void agentDisconnected(String packageName) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.agentDisconnected(packageName); } @@ -273,7 +276,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void restoreAtInstall(String packageName, int token) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.restoreAtInstall(packageName, token); } @@ -281,7 +284,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void setBackupEnabled(boolean isEnabled) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.setBackupEnabled(isEnabled); } @@ -289,7 +292,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void setAutoRestore(boolean doAutoRestore) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.setAutoRestore(doAutoRestore); } @@ -297,7 +300,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void setBackupProvisioned(boolean isProvisioned) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.setBackupProvisioned(isProvisioned); } @@ -305,25 +308,25 @@ public class Trampoline extends IBackupManager.Stub { @Override public boolean isBackupEnabled() throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.isBackupEnabled() : false; } @Override public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.setBackupPassword(currentPw, newPw) : false; } @Override public boolean hasBackupPassword() throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.hasBackupPassword() : false; } @Override public void backupNow() throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.backupNow(); } @@ -334,7 +337,7 @@ public class Trampoline extends IBackupManager.Stub { boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem, boolean doCompress, boolean doKeyValue, String[] packageNames) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.adbBackup(fd, includeApks, includeObbs, includeShared, doWidgets, allApps, allIncludesSystem, doCompress, doKeyValue, packageNames); @@ -343,7 +346,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void fullTransportBackup(String[] packageNames) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.fullTransportBackup(packageNames); } @@ -351,7 +354,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void adbRestore(ParcelFileDescriptor fd) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.adbRestore(fd); } @@ -361,7 +364,7 @@ public class Trampoline extends IBackupManager.Stub { public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword, String encryptionPassword, IFullBackupRestoreObserver observer) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.acknowledgeAdbBackupOrRestore(token, allow, curPassword, encryptionPassword, observer); @@ -370,7 +373,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public String getCurrentTransport() throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getCurrentTransport() : null; } @@ -381,25 +384,25 @@ public class Trampoline extends IBackupManager.Stub { @Override @Nullable public ComponentName getCurrentTransportComponent() { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getCurrentTransportComponent() : null; } @Override public String[] listAllTransports() throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.listAllTransports() : null; } @Override public ComponentName[] listAllTransportComponents() throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.listAllTransportComponents() : null; } @Override public String[] getTransportWhitelist() { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getTransportWhitelist() : null; } @@ -411,7 +414,7 @@ public class Trampoline extends IBackupManager.Stub { String currentDestinationString, @Nullable Intent dataManagementIntent, String dataManagementLabel) { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.updateTransportAttributes( transportComponent, @@ -425,14 +428,14 @@ public class Trampoline extends IBackupManager.Stub { @Override public String selectBackupTransport(String transport) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.selectBackupTransport(transport) : null; } @Override public void selectBackupTransportAsync(ComponentName transport, ISelectBackupTransportCallback listener) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.selectBackupTransportAsync(transport, listener); } else { @@ -448,38 +451,38 @@ public class Trampoline extends IBackupManager.Stub { @Override public Intent getConfigurationIntent(String transport) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getConfigurationIntent(transport) : null; } @Override public String getDestinationString(String transport) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getDestinationString(transport) : null; } @Override public Intent getDataManagementIntent(String transport) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getDataManagementIntent(transport) : null; } @Override public String getDataManagementLabel(String transport) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getDataManagementLabel(transport) : null; } @Override public IRestoreSession beginRestoreSession(String packageName, String transportID) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.beginRestoreSession(packageName, transportID) : null; } @Override public void opComplete(int token, long result) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.opComplete(token, result); } @@ -487,26 +490,26 @@ public class Trampoline extends IBackupManager.Stub { @Override public long getAvailableRestoreToken(String packageName) { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.getAvailableRestoreToken(packageName) : 0; } @Override public boolean isAppEligibleForBackup(String packageName) { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false; } @Override public String[] filterAppsEligibleForBackup(String[] packages) { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.filterAppsEligibleForBackup(packages) : null; } @Override public int requestBackup(String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor, int flags) throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc == null) { return BackupManager.ERROR_BACKUP_NOT_ALLOWED; } @@ -515,7 +518,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void cancelBackups() throws RemoteException { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.cancelBackups(); } @@ -525,7 +528,7 @@ public class Trampoline extends IBackupManager.Stub { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.dump(fd, pw, args); } else { @@ -536,12 +539,12 @@ public class Trampoline extends IBackupManager.Stub { // Full backup/restore entry points - non-Binder; called directly // by the full-backup scheduled job /* package */ boolean beginFullBackup(FullBackupJob scheduledJob) { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; return (svc != null) ? svc.beginFullBackup(scheduledJob) : false; } /* package */ void endFullBackup() { - BackupManagerService svc = mService; + GlobalBackupManagerService svc = mService; if (svc != null) { svc.endFullBackup(); } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index e4b4bc525514..4855ae0358bc 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -18,6 +18,10 @@ package com.android.server.backup; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_FULL_CONFIRMATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_OP_COMPLETE; @@ -64,7 +68,6 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -78,13 +81,11 @@ import android.os.RemoteException; import android.os.SELinux; import android.os.ServiceManager; import android.os.SystemClock; -import android.os.Trace; import android.os.UserHandle; import android.os.WorkSource; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.Settings; -import android.text.TextUtils; import android.util.ArraySet; import android.util.AtomicFile; import android.util.EventLog; @@ -99,8 +100,6 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; -import com.android.server.SystemConfig; -import com.android.server.SystemService; import com.android.server.backup.fullbackup.FullBackupEntry; import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.internal.BackupHandler; @@ -160,12 +159,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; /** System service that performs backup/restore operations. */ -public class BackupManagerService { - public static final String TAG = "BackupManagerService"; - public static final boolean DEBUG = true; - public static final boolean MORE_DEBUG = false; - public static final boolean DEBUG_SCHEDULING = true; - +public class UserBackupManagerService { // File containing backup-enabled state. Contains a single byte; // nonzero == enabled. File missing or contains a zero byte == disabled. private static final String BACKUP_ENABLE_FILE = "backup_enabled"; @@ -249,59 +243,6 @@ public class BackupManagerService { private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours - // The published binder is a singleton Trampoline object that calls through to the proper code. - // This indirection lets us turn down the heavy implementation object on the fly without - // disturbing binders that have been cached elsewhere in the system. - private static Trampoline sInstance; - - static Trampoline getInstance() { - // Always constructed during system bring up, so no need to lazy-init. - return sInstance; - } - - /** Helper to create the {@link BackupManagerService} instance. */ - public static BackupManagerService create( - Context context, - Trampoline parent, - HandlerThread backupThread) { - // Set up our transport options and initialize the default transport - SystemConfig systemConfig = SystemConfig.getInstance(); - Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist(); - if (transportWhitelist == null) { - transportWhitelist = Collections.emptySet(); - } - - String transport = - Settings.Secure.getString( - context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT); - if (TextUtils.isEmpty(transport)) { - transport = null; - } - if (DEBUG) { - Slog.v(TAG, "Starting with transport " + transport); - } - TransportManager transportManager = - new TransportManager( - context, - transportWhitelist, - transport); - - // If encrypted file systems is enabled or disabled, this call will return the - // correct directory. - File baseStateDir = new File(Environment.getDataDirectory(), "backup"); - - // This dir on /cache is managed directly in init.rc - File dataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage"); - - return new BackupManagerService( - context, - parent, - backupThread, - baseStateDir, - dataDir, - transportManager); - } - private final BackupAgentTimeoutParameters mAgentTimeoutParameters; private final TransportManager mTransportManager; @@ -386,7 +327,7 @@ public class BackupManagerService { * A BackupRestore task gets notified of ack/timeout for the operation via * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called * on the mCurrentOpLock. - * {@link BackupManagerService#waitUntilOperationComplete(int)} is + * {@link UserBackupManagerService#waitUntilOperationComplete(int)} is * used in various places to 'wait' for notifyAll and detect change of pending state of an * operation. So typically, an operation will be removed from this array by: * - BackupRestoreTask#handleCancel and @@ -420,7 +361,7 @@ public class BackupManagerService { private long mCurrentToken = 0; @VisibleForTesting - public BackupManagerService( + public UserBackupManagerService( Context context, Trampoline parent, HandlerThread backupThread, @@ -782,44 +723,6 @@ public class BackupManagerService { } /** - * Called through Trampoline from {@link Lifecycle#onUnlockUser(int)}. We run the heavy work on - * a background thread to keep the unlock time down. - */ - public void unlockSystemUser() { - // Migrate legacy setting - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate"); - if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) { - if (DEBUG) { - Slog.i(TAG, "Backup enable apparently not migrated"); - } - ContentResolver resolver = sInstance.getContext().getContentResolver(); - int enableState = Settings.Secure.getIntForUser(resolver, - Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM); - if (enableState >= 0) { - if (DEBUG) { - Slog.i(TAG, "Migrating enable state " + (enableState != 0)); - } - writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM); - Settings.Secure.putStringForUser(resolver, - Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM); - } else { - if (DEBUG) { - Slog.i(TAG, "Backup not yet configured; retaining null enable state"); - } - } - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); - try { - sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM)); - } catch (RemoteException e) { - // can't happen; it's a local object - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } - - /** * Utility: build a new random integer token. The low bits are the ordinal of the operation for * near-time uniqueness, and the upper bits are random for app-side unpredictability. */ @@ -2761,7 +2664,8 @@ public class BackupManagerService { try { boolean wasEnabled = mEnabled; synchronized (this) { - writeBackupEnableState(enable, UserHandle.USER_SYSTEM); + // TODO(b/118520567): Clean up writing backup enabled logic. + GlobalBackupManagerService.writeBackupEnableState(enable, UserHandle.USER_SYSTEM); mEnabled = enable; } @@ -3594,72 +3498,4 @@ public class BackupManagerService { public IBackupManager getBackupManagerBinder() { return mBackupManagerBinder; } - - private static boolean backupSettingMigrated(int userId) { - File base = new File(Environment.getDataDirectory(), "backup"); - File enableFile = new File(base, BACKUP_ENABLE_FILE); - return enableFile.exists(); - } - - private static boolean readBackupEnableState(int userId) { - File base = new File(Environment.getDataDirectory(), "backup"); - File enableFile = new File(base, BACKUP_ENABLE_FILE); - if (enableFile.exists()) { - try (FileInputStream fin = new FileInputStream(enableFile)) { - int state = fin.read(); - return state != 0; - } catch (IOException e) { - // can't read the file; fall through to assume disabled - Slog.e(TAG, "Cannot read enable state; assuming disabled"); - } - } else { - if (DEBUG) { - Slog.i(TAG, "isBackupEnabled() => false due to absent settings file"); - } - } - return false; - } - - private static void writeBackupEnableState(boolean enable, int userId) { - File base = new File(Environment.getDataDirectory(), "backup"); - File enableFile = new File(base, BACKUP_ENABLE_FILE); - File stage = new File(base, BACKUP_ENABLE_FILE + "-stage"); - try (FileOutputStream fout = new FileOutputStream(stage)) { - fout.write(enable ? 1 : 0); - fout.close(); - stage.renameTo(enableFile); - // will be synced immediately by the try-with-resources call to close() - } catch (IOException | RuntimeException e) { - // Whoops; looks like we're doomed. Roll everything out, disabled, - // including the legacy state. - Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: " - + e.getMessage()); - - ContentResolver resolver = sInstance.getContext().getContentResolver(); - Settings.Secure.putStringForUser(resolver, - Settings.Secure.BACKUP_ENABLED, null, userId); - enableFile.delete(); - stage.delete(); - } - } - - /** Implementation to receive lifecycle event callbacks for system services. */ - public static final class Lifecycle extends SystemService { - public Lifecycle(Context context) { - super(context); - sInstance = new Trampoline(context); - } - - @Override - public void onStart() { - publishBinderService(Context.BACKUP_SERVICE, sInstance); - } - - @Override - public void onUnlockUser(int userId) { - if (userId == UserHandle.USER_SYSTEM) { - sInstance.unlockSystemUser(); - } - } - } } diff --git a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java index 94365d7dc02d..725bc74a66c6 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java +++ b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java @@ -1,10 +1,10 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_VERSION; -import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_VERSION; -import static com.android.server.backup.BackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_VERSION; +import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_VERSION; +import static com.android.server.backup.UserBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; import android.annotation.Nullable; import android.app.backup.FullBackup; diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java index c9f72181bcaf..9b484bc3ca29 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java @@ -16,13 +16,13 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME; -import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_FILENAME; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; -import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; +import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; +import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; @@ -39,8 +39,8 @@ import android.util.Slog; import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.remote.RemoteCall; import com.android.server.backup.utils.FullBackupUtils; @@ -53,7 +53,7 @@ import java.io.OutputStream; * and emitting it to the designated OutputStream. */ public class FullBackupEngine { - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; OutputStream mOutput; FullBackupPreflight mPreflightHook; BackupRestoreTask mTimeoutMonitor; @@ -164,24 +164,21 @@ public class FullBackupEngine { } /** - * Don't write apks for forward-locked apps or system-bundled apps that are not upgraded. + * Don't write apks for system-bundled apps that are not upgraded. */ private boolean shouldWriteApk( ApplicationInfo applicationInfo, boolean includeApks, boolean isSharedStorage) { - boolean isForwardLocked = - (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; boolean isSystemApp = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; boolean isUpdatedSystemApp = (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; return includeApks && !isSharedStorage - && !isForwardLocked && (!isSystemApp || isUpdatedSystemApp); } } public FullBackupEngine( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, OutputStream output, FullBackupPreflight preflightHook, PackageInfo pkg, diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java index bc7d9fc691dd..24784ea92c73 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java @@ -16,9 +16,9 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.app.backup.IBackupManager; import android.content.ComponentName; @@ -34,7 +34,7 @@ import android.util.Slog; import com.android.internal.backup.IObbBackupService; import com.android.internal.util.Preconditions; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.utils.FullBackupUtils; import java.io.IOException; @@ -45,11 +45,11 @@ import java.io.OutputStream; */ public class FullBackupObbConnection implements ServiceConnection { - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; volatile IObbBackupService mService; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; - public FullBackupObbConnection(BackupManagerService backupManagerService) { + public FullBackupObbConnection(UserBackupManagerService backupManagerService) { this.backupManagerService = backupManagerService; mService = null; mAgentTimeoutParameters = Preconditions.checkNotNull( diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java index 8f6923b6c05b..0ed75bb4a1b4 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java @@ -16,7 +16,7 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.app.backup.IFullBackupRestoreObserver; import android.os.RemoteException; diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java index 44edabce72b6..2f7687fc7009 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java @@ -17,12 +17,12 @@ package com.android.server.backup.fullbackup; import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; -import static com.android.server.backup.BackupManagerService.BACKUP_FILE_HEADER_MAGIC; -import static com.android.server.backup.BackupManagerService.BACKUP_FILE_VERSION; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC; +import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION; +import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.app.backup.IFullBackupRestoreObserver; import android.content.pm.ApplicationInfo; @@ -37,7 +37,7 @@ import android.util.Slog; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.KeyValueAdbBackupEngine; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.utils.AppBackupUtils; import com.android.server.backup.utils.PasswordUtils; @@ -66,7 +66,7 @@ import javax.crypto.spec.SecretKeySpec; */ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask { - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; FullBackupEngine mBackupEngine; final AtomicBoolean mLatch; @@ -86,7 +86,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor String mEncryptPassword; private final int mCurrentOpToken; - public PerformAdbBackupTask(BackupManagerService backupManagerService, + public PerformAdbBackupTask(UserBackupManagerService backupManagerService, ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem, diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 755095ec1b18..0d14e7ef3e55 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -16,12 +16,12 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.OP_PENDING; -import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; -import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.UserBackupManagerService.OP_PENDING; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.annotation.Nullable; import android.app.IBackupAgent; @@ -45,10 +45,10 @@ import com.android.internal.backup.IBackupTransport; import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FullBackupJob; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.internal.Operation; import com.android.server.backup.remote.RemoteCall; @@ -97,7 +97,7 @@ import java.util.concurrent.atomic.AtomicLong; */ public class PerformFullTransportBackupTask extends FullBackupTask implements BackupRestoreTask { public static PerformFullTransportBackupTask newWithCurrentTransport( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, @@ -128,7 +128,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba private static final String TAG = "PFTBT"; - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; private final Object mCancelLock = new Object(); ArrayList<PackageInfo> mPackages; @@ -150,7 +150,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba private final int mCurrentOpToken; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; - public PerformFullTransportBackupTask(BackupManagerService backupManagerService, + public PerformFullTransportBackupTask(UserBackupManagerService backupManagerService, TransportClient transportClient, IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index f66d8cc8a9a5..fd0946679655 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -16,9 +16,9 @@ package com.android.server.backup.internal; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.app.backup.RestoreSet; import android.content.Intent; @@ -35,10 +35,10 @@ import com.android.internal.backup.IBackupTransport; import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.fullbackup.PerformAdbBackupTask; import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.keyvalue.BackupRequest; @@ -84,10 +84,10 @@ public class BackupHandler extends Handler { public static final int MSG_BACKUP_RESTORE_STEP = 20; public static final int MSG_OP_COMPLETE = 21; - private final BackupManagerService backupManagerService; + private final UserBackupManagerService backupManagerService; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; - public BackupHandler(BackupManagerService backupManagerService, Looper looper) { + public BackupHandler(UserBackupManagerService backupManagerService, Looper looper) { super(looper); this.backupManagerService = backupManagerService; mAgentTimeoutParameters = Preconditions.checkNotNull( diff --git a/services/backup/java/com/android/server/backup/internal/ClearDataObserver.java b/services/backup/java/com/android/server/backup/internal/ClearDataObserver.java index b0b8037dbc64..396f36951a52 100644 --- a/services/backup/java/com/android/server/backup/internal/ClearDataObserver.java +++ b/services/backup/java/com/android/server/backup/internal/ClearDataObserver.java @@ -18,13 +18,13 @@ package com.android.server.backup.internal; import android.content.pm.IPackageDataObserver; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; public class ClearDataObserver extends IPackageDataObserver.Stub { - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; - public ClearDataObserver(BackupManagerService backupManagerService) { + public ClearDataObserver(UserBackupManagerService backupManagerService) { this.backupManagerService = backupManagerService; } diff --git a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java index d0281040452e..2bad5fe7ae1e 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java @@ -16,26 +16,26 @@ package com.android.server.backup.internal; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.content.pm.PackageInfo; import android.util.Slog; import com.android.internal.backup.IBackupTransport; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.transport.TransportClient; import java.io.File; public class PerformClearTask implements Runnable { - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; private final TransportManager mTransportManager; private final TransportClient mTransportClient; private final PackageInfo mPackage; private final OnTaskFinishedListener mListener; - PerformClearTask(BackupManagerService backupManagerService, + PerformClearTask(UserBackupManagerService backupManagerService, TransportClient transportClient, PackageInfo packageInfo, OnTaskFinishedListener listener) { mBackupManagerService = backupManagerService; diff --git a/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java b/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java index 1ef740db614f..1637e559acb7 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java @@ -16,7 +16,7 @@ package com.android.server.backup.internal; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.annotation.Nullable; import android.app.AlarmManager; @@ -30,8 +30,8 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.backup.IBackupTransport; import com.android.server.EventLogTags; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.transport.TransportClient; import java.io.File; @@ -49,7 +49,7 @@ import java.util.List; * operation was successful then it's {@link BackupTransport#TRANSPORT_OK}. */ public class PerformInitializeTask implements Runnable { - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; private final TransportManager mTransportManager; private final String[] mQueue; private final File mBaseStateDir; @@ -57,7 +57,7 @@ public class PerformInitializeTask implements Runnable { @Nullable private IBackupObserver mObserver; public PerformInitializeTask( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, String[] transportNames, @Nullable IBackupObserver observer, OnTaskFinishedListener listener) { @@ -72,7 +72,7 @@ public class PerformInitializeTask implements Runnable { @VisibleForTesting PerformInitializeTask( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, TransportManager transportManager, String[] transportNames, @Nullable IBackupObserver observer, diff --git a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java b/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java index 69720d4ee07c..eab86629e75b 100644 --- a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java +++ b/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java @@ -16,22 +16,22 @@ package com.android.server.backup.internal; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.database.ContentObserver; import android.os.Handler; import android.util.Slog; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.KeyValueBackupJob; +import com.android.server.backup.UserBackupManagerService; public class ProvisionedObserver extends ContentObserver { - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; public ProvisionedObserver( - BackupManagerService backupManagerService, Handler handler) { + UserBackupManagerService backupManagerService, Handler handler) { super(handler); this.backupManagerService = backupManagerService; } diff --git a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java index 6f574caabc23..d869f044f5a4 100644 --- a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java +++ b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java @@ -16,10 +16,10 @@ package com.android.server.backup.internal; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.RUN_BACKUP_ACTION; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.RUN_BACKUP_ACTION; import static com.android.server.backup.internal.BackupHandler.MSG_RUN_BACKUP; import android.app.PendingIntent; @@ -29,13 +29,13 @@ import android.content.Intent; import android.os.Message; import android.util.Slog; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; public class RunBackupReceiver extends BroadcastReceiver { - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; - public RunBackupReceiver(BackupManagerService backupManagerService) { + public RunBackupReceiver(UserBackupManagerService backupManagerService) { this.backupManagerService = backupManagerService; } diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java index 548c580f78fb..880e608a2fdb 100644 --- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java +++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java @@ -16,9 +16,9 @@ package com.android.server.backup.internal; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.RUN_INITIALIZE_ACTION; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.RUN_INITIALIZE_ACTION; import android.content.BroadcastReceiver; import android.content.Context; @@ -27,12 +27,12 @@ import android.os.PowerManager; import android.util.ArraySet; import android.util.Slog; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; public class RunInitializeReceiver extends BroadcastReceiver { - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; - public RunInitializeReceiver(BackupManagerService backupManagerService) { + public RunInitializeReceiver(UserBackupManagerService backupManagerService) { mBackupManagerService = backupManagerService; } diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java index bb8a1d1339a7..437abd22d249 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java @@ -28,8 +28,9 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.EventLogTags; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.DataChangedJournal; +import com.android.server.backup.GlobalBackupManagerService; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.remote.RemoteResult; import com.android.server.backup.utils.BackupManagerMonitorUtils; import com.android.server.backup.utils.BackupObserverUtils; @@ -53,8 +54,8 @@ import java.util.List; @VisibleForTesting public class KeyValueBackupReporter { @VisibleForTesting static final String TAG = "KeyValueBackupTask"; - private static final boolean DEBUG = BackupManagerService.DEBUG; - @VisibleForTesting static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG || false; + private static final boolean DEBUG = GlobalBackupManagerService.DEBUG; + @VisibleForTesting static final boolean MORE_DEBUG = GlobalBackupManagerService.MORE_DEBUG; static void onNewThread(String threadName) { if (DEBUG) { @@ -62,12 +63,12 @@ public class KeyValueBackupReporter { } } - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; private final IBackupObserver mObserver; @Nullable private IBackupManagerMonitor mMonitor; KeyValueBackupReporter( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, IBackupObserver observer, @Nullable IBackupManagerMonitor monitor) { mBackupManagerService = backupManagerService; diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java index d6f2a8775518..f39d795735f3 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java @@ -22,9 +22,9 @@ import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; -import static com.android.server.backup.BackupManagerService.KEY_WIDGET_STATE; -import static com.android.server.backup.BackupManagerService.OP_PENDING; -import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; +import static com.android.server.backup.UserBackupManagerService.KEY_WIDGET_STATE; +import static com.android.server.backup.UserBackupManagerService.OP_PENDING; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP; import android.annotation.IntDef; import android.annotation.Nullable; @@ -35,7 +35,6 @@ import android.app.backup.BackupDataOutput; import android.app.backup.BackupManager; import android.app.backup.BackupTransport; import android.app.backup.IBackupCallback; -import android.app.backup.IBackupManager; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IBackupObserver; import android.content.pm.ApplicationInfo; @@ -55,11 +54,11 @@ import com.android.internal.backup.IBackupTransport; import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.KeyValueBackupJob; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.internal.Operation; @@ -95,12 +94,12 @@ import java.util.concurrent.atomic.AtomicInteger; * <p>A few definitions: * * <ul> - * <li>State directory: {@link BackupManagerService#getBaseStateDir()}/<transport> + * <li>State directory: {@link UserBackupManagerService#getBaseStateDir()}/<transport> * <li>State file: {@link - * BackupManagerService#getBaseStateDir()}/<transport>/<package><br> + * UserBackupManagerService#getBaseStateDir()}/<transport>/<package><br> * Represents the state of the backup data for a specific package in the current dataset. - * <li>Stage directory: {@link BackupManagerService#getDataDir()} - * <li>Stage file: {@link BackupManagerService#getDataDir()}/<package>.data<br> + * <li>Stage directory: {@link UserBackupManagerService#getDataDir()} + * <li>Stage file: {@link UserBackupManagerService#getDataDir()}/<package>.data<br> * Contains staged data that the agents wrote via {@link BackupDataOutput}, to be transmitted * to the transport. * </ul> @@ -112,7 +111,7 @@ import java.util.concurrent.atomic.AtomicInteger; * of incremental choice. If non-incremental, PM will only be backed-up if specified in the queue, * and if it's the case it will be re-positioned at the head of the queue. * - * <p>Before starting, this task will register itself in {@link BackupManagerService} current + * <p>Before starting, this task will register itself in {@link UserBackupManagerService} current * operations. * * <p>In summary, this task will for each package: @@ -121,7 +120,7 @@ import java.util.concurrent.atomic.AtomicInteger; * <li>Bind to its {@link IBackupAgent}. * <li>Request transport quota and flags. * <li>Call {@link IBackupAgent#doBackup(ParcelFileDescriptor, ParcelFileDescriptor, - * ParcelFileDescriptor, long, int, IBackupManager, int)} via {@link RemoteCall} passing the + * ParcelFileDescriptor, long, IBackupCallback, int)} via {@link RemoteCall} passing the * old state file descriptor (read), the backup data file descriptor (write), the new state * file descriptor (write), the quota and the transport flags. This will call {@link * BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)} with @@ -131,7 +130,7 @@ import java.util.concurrent.atomic.AtomicInteger; * <ul> * <li>Agent response. * <li>Agent time-out (specified via {@link - * BackupManagerService#getAgentTimeoutParameters()}. + * UserBackupManagerService#getAgentTimeoutParameters()}. * <li>External cancellation or thread interrupt. * </ul> * <li>Unbind the agent. @@ -149,11 +148,11 @@ import java.util.concurrent.atomic.AtomicInteger; * <li>Mark data-changed for the remaining packages in the queue (skipped packages). * <li>Delete the {@link DataChangedJournal} provided. Note that this should not be the current * journal. - * <li>Set {@link BackupManagerService} current token as {@link + * <li>Set {@link UserBackupManagerService} current token as {@link * IBackupTransport#getCurrentRestoreSet()}, if applicable. * <li>Add the transport to the list of transports pending initialization ({@link - * BackupManagerService#getPendingInits()}) and kick-off initialization if the transport ever - * returned {@link BackupTransport#TRANSPORT_NOT_INITIALIZED}. + * UserBackupManagerService#getPendingInits()}) and kick-off initialization if the transport + * ever returned {@link BackupTransport#TRANSPORT_NOT_INITIALIZED}. * <li>Unregister the task in current operations. * <li>Release the wakelock. * <li>Kick-off {@link PerformFullTransportBackupTask} if a list of full-backup packages was @@ -174,7 +173,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { private static final int THREAD_PRIORITY = Process.THREAD_PRIORITY_BACKGROUND; private static final AtomicInteger THREAD_COUNT = new AtomicInteger(); private static final String BLANK_STATE_FILE_NAME = "blank_state"; - private static final String PM_PACKAGE = BackupManagerService.PACKAGE_MANAGER_SENTINEL; + private static final String PM_PACKAGE = UserBackupManagerService.PACKAGE_MANAGER_SENTINEL; @VisibleForTesting public static final String STAGING_FILE_SUFFIX = ".data"; @VisibleForTesting public static final String NEW_STATE_FILE_SUFFIX = ".new"; @@ -182,7 +181,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { * Creates a new {@link KeyValueBackupTask} for key-value backup operation, spins up a new * dedicated thread and kicks off the operation in it. * - * @param backupManagerService The {@link BackupManagerService} system service. + * @param backupManagerService The {@link UserBackupManagerService} instance. * @param transportClient The {@link TransportClient} that contains the transport used for the * operation. * @param transportDirName The value of {@link IBackupTransport#transportDirName()} for the @@ -201,7 +200,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { * @return The {@link KeyValueBackupTask} that was started. */ public static KeyValueBackupTask start( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, TransportClient transportClient, String transportDirName, List<String> queue, @@ -232,7 +231,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { return task; } - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; private final PackageManager mPackageManager; private final TransportManager mTransportManager; private final TransportClient mTransportClient; @@ -289,7 +288,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { @VisibleForTesting public KeyValueBackupTask( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, TransportClient transportClient, String transportDirName, List<String> queue, diff --git a/services/backup/java/com/android/server/backup/remote/ServiceBackupCallback.java b/services/backup/java/com/android/server/backup/remote/ServiceBackupCallback.java index 28d85a694d4b..bfc97ae81f97 100644 --- a/services/backup/java/com/android/server/backup/remote/ServiceBackupCallback.java +++ b/services/backup/java/com/android/server/backup/remote/ServiceBackupCallback.java @@ -20,12 +20,12 @@ import android.app.backup.IBackupCallback; import android.app.backup.IBackupManager; import android.os.RemoteException; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; /** * An implementation of {@link IBackupCallback} that routes the result to {@link - * BackupManagerService} via {@link IBackupManager#opComplete(int, long)} passing the token provided - * in the constructor. + * UserBackupManagerService} via {@link IBackupManager#opComplete(int, long)} passing the token + * provided in the constructor. */ public class ServiceBackupCallback extends IBackupCallback.Stub { private final IBackupManager mBackupManager; diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java index 140dded1cb74..5c05371aedda 100644 --- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java +++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java @@ -16,8 +16,8 @@ package com.android.server.backup.restore; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_RUN_GET_RESTORE_SETS; import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE; @@ -36,8 +36,8 @@ import android.os.Message; import android.os.PowerManager; import android.util.Slog; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.params.RestoreGetSetsParams; import com.android.server.backup.params.RestoreParams; @@ -53,14 +53,14 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { private final TransportManager mTransportManager; private final String mTransportName; - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; @Nullable private final String mPackageName; public RestoreSet[] mRestoreSets = null; boolean mEnded = false; boolean mTimedOut = false; public ActiveRestoreSession( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, @Nullable String packageName, String transportName) { mBackupManagerService = backupManagerService; @@ -405,10 +405,10 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { // Posted to the handler to tear down a restore session in a cleanly synchronized way public class EndRestoreRunnable implements Runnable { - BackupManagerService mBackupManager; + UserBackupManagerService mBackupManager; ActiveRestoreSession mSession; - public EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) { + public EndRestoreRunnable(UserBackupManagerService manager, ActiveRestoreSession session) { mBackupManager = manager; mSession = session; } diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java index a8c7ce6ad832..8196e709f2ee 100644 --- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java +++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java @@ -16,15 +16,15 @@ package com.android.server.backup.restore; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; import android.util.Slog; import com.android.internal.util.Preconditions; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; +import com.android.server.backup.UserBackupManagerService; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -35,12 +35,12 @@ import java.util.concurrent.TimeUnit; public class AdbRestoreFinishedLatch implements BackupRestoreTask { private static final String TAG = "AdbRestoreFinishedLatch"; - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; final CountDownLatch mLatch; private final int mCurrentOpToken; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; - public AdbRestoreFinishedLatch(BackupManagerService backupManagerService, + public AdbRestoreFinishedLatch(UserBackupManagerService backupManagerService, int currentOpToken) { this.backupManagerService = backupManagerService; mLatch = new CountDownLatch(1); diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedRunnable.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedRunnable.java index dc7044e450b7..184a6d03428f 100644 --- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedRunnable.java +++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedRunnable.java @@ -3,7 +3,7 @@ package com.android.server.backup.restore; import android.app.IBackupAgent; import android.os.RemoteException; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; /** * Runner that can be placed on a separate thread to do in-process invocation of the "restore @@ -13,10 +13,10 @@ public class AdbRestoreFinishedRunnable implements Runnable { private final IBackupAgent mAgent; private final int mToken; - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; AdbRestoreFinishedRunnable(IBackupAgent agent, int token, - BackupManagerService backupManagerService) { + UserBackupManagerService backupManagerService) { mAgent = agent; mToken = token; mBackupManagerService = backupManagerService; diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 1084f52ed36d..ee08902aca05 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -16,13 +16,13 @@ package com.android.server.backup.restore; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME; -import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_FILENAME; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT; -import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; +import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_RESTORE_WAIT; +import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import android.app.ApplicationThreadConstants; @@ -44,10 +44,10 @@ import android.util.Slog; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.fullbackup.FullBackupObbConnection; import com.android.server.backup.utils.BytesReadListener; import com.android.server.backup.utils.FullBackupRestoreObserverUtils; @@ -57,7 +57,6 @@ import com.android.server.backup.utils.TarBackupReader; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -68,7 +67,7 @@ import java.util.List; */ public class FullRestoreEngine extends RestoreEngine { - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; // Task in charge of monitoring timeouts private final BackupRestoreTask mMonitorTask; @@ -129,7 +128,7 @@ public class FullRestoreEngine extends RestoreEngine { private final BackupAgentTimeoutParameters mAgentTimeoutParameters; final boolean mIsAdbRestore; - public FullRestoreEngine(BackupManagerService backupManagerService, + public FullRestoreEngine(UserBackupManagerService backupManagerService, BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, boolean allowObbs, int ephemeralOpToken, boolean isAdbRestore) { diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index 32dbad9f92db..381252dafe07 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -16,18 +16,15 @@ package com.android.server.backup.restore; -import static com.android.server.backup.BackupManagerService.BACKUP_FILE_HEADER_MAGIC; -import static com.android.server.backup.BackupManagerService.BACKUP_FILE_VERSION; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT; -import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE; -import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; -import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK; -import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; - +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC; +import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION; +import static com.android.server.backup.UserBackupManagerService.SETTINGS_PACKAGE; +import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.app.IBackupAgent; import android.app.backup.BackupAgent; @@ -36,15 +33,12 @@ import android.content.pm.ApplicationInfo; import android.content.pm.Signature; import android.os.Environment; import android.os.ParcelFileDescriptor; -import android.os.RemoteException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; -import com.android.server.LocalServices; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; -import com.android.server.backup.PackageManagerBackupAgent; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.fullbackup.FullBackupObbConnection; import com.android.server.backup.utils.FullBackupRestoreObserverUtils; import com.android.server.backup.utils.PasswordUtils; @@ -72,7 +66,7 @@ import javax.crypto.spec.SecretKeySpec; public class PerformAdbRestoreTask implements Runnable { - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; private final ParcelFileDescriptor mInputFile; private final String mCurrentPassword; private final String mDecryptPassword; @@ -106,7 +100,7 @@ public class PerformAdbRestoreTask implements Runnable { // Packages we've already wiped data on when restoring their first file private final HashSet<String> mClearedPackages = new HashSet<>(); - public PerformAdbRestoreTask(BackupManagerService backupManagerService, + public PerformAdbRestoreTask(UserBackupManagerService backupManagerService, ParcelFileDescriptor fd, String curPassword, String decryptPassword, IFullBackupRestoreObserver observer, AtomicBoolean latch) { this.mBackupManagerService = backupManagerService; diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 580f70a046b5..7530356fff4d 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -16,13 +16,13 @@ package com.android.server.backup.restore; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.KEY_WIDGET_STATE; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT; -import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL; -import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.KEY_WIDGET_STATE; +import static com.android.server.backup.UserBackupManagerService.OP_TYPE_RESTORE_WAIT; +import static com.android.server.backup.UserBackupManagerService.PACKAGE_MANAGER_SENTINEL; +import static com.android.server.backup.UserBackupManagerService.SETTINGS_PACKAGE; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT; @@ -40,8 +40,8 @@ import android.app.backup.RestoreDescription; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.os.Bundle; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -62,8 +62,8 @@ import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.BackupUtils; import com.android.server.backup.PackageManagerBackupAgent; import com.android.server.backup.PackageManagerBackupAgent.Metadata; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.transport.TransportClient; import com.android.server.backup.utils.AppBackupUtils; @@ -80,7 +80,7 @@ import java.util.List; public class PerformUnifiedRestoreTask implements BackupRestoreTask { - private BackupManagerService backupManagerService; + private UserBackupManagerService backupManagerService; private final TransportManager mTransportManager; // Transport client we're working with to do the restore private final TransportClient mTransportClient; @@ -164,7 +164,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // This task can assume that the wakelock is properly held for it and doesn't have to worry // about releasing it. public PerformUnifiedRestoreTask( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, TransportClient transportClient, IRestoreObserver observer, IBackupManagerMonitor monitor, diff --git a/services/backup/java/com/android/server/backup/restore/RestoreFileRunnable.java b/services/backup/java/com/android/server/backup/restore/RestoreFileRunnable.java index 635b6d6bd431..c4aa2d745970 100644 --- a/services/backup/java/com/android/server/backup/restore/RestoreFileRunnable.java +++ b/services/backup/java/com/android/server/backup/restore/RestoreFileRunnable.java @@ -21,7 +21,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import com.android.server.backup.FileMetadata; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; import java.io.IOException; @@ -35,9 +35,9 @@ class RestoreFileRunnable implements Runnable { private final FileMetadata mInfo; private final ParcelFileDescriptor mSocket; private final int mToken; - private final BackupManagerService mBackupManagerService; + private final UserBackupManagerService mBackupManagerService; - RestoreFileRunnable(BackupManagerService backupManagerService, IBackupAgent agent, + RestoreFileRunnable(UserBackupManagerService backupManagerService, IBackupAgent agent, FileMetadata info, ParcelFileDescriptor socket, int token) throws IOException { mAgent = agent; mInfo = info; 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 c933833fa7a3..2452e4868c80 100644 --- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java @@ -16,9 +16,9 @@ package com.android.server.backup.utils; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.annotation.Nullable; import android.app.backup.BackupTransport; diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java index 6f083760980d..8b931d43dfe0 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java +++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java @@ -18,8 +18,8 @@ package com.android.server.backup.utils; import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.annotation.Nullable; import android.app.backup.BackupManagerMonitor; diff --git a/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java b/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java index c0cf2ef86920..9674c3db9c75 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java +++ b/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java @@ -16,8 +16,8 @@ package com.android.server.backup.utils; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.app.backup.BackupProgress; import android.app.backup.IBackupObserver; diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java index fa856ce2c6de..92cdf0de48c7 100644 --- a/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java +++ b/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java @@ -16,7 +16,7 @@ package com.android.server.backup.utils; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.app.backup.IFullBackupRestoreObserver; import android.os.RemoteException; diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java index dbe3cd9225b5..a6fdbf004726 100644 --- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java @@ -16,7 +16,7 @@ package com.android.server.backup.utils; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.os.ParcelFileDescriptor; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java index a7eb644713ba..65adf4ee267d 100644 --- a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java +++ b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java @@ -16,7 +16,7 @@ package com.android.server.backup.utils; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java index df7e6d45ba0f..91567d7aa0e5 100644 --- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java +++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java @@ -16,8 +16,8 @@ package com.android.server.backup.utils; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; import android.content.Context; import android.content.IIntentReceiver; diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index 6dd5284879f0..c295684d0732 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -34,14 +34,14 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_VERSION; -import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_FILENAME; -import static com.android.server.backup.BackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; -import static com.android.server.backup.BackupManagerService.DEBUG; -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; -import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.GlobalBackupManagerService.DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_VERSION; +import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; +import static com.android.server.backup.UserBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; +import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.app.backup.BackupAgent; import android.app.backup.BackupManagerMonitor; diff --git a/services/core/java/com/android/server/AbstractPerUserSystemService.java b/services/core/java/com/android/server/AbstractPerUserSystemService.java index b37888f8ef2e..71d261c7f5b5 100644 --- a/services/core/java/com/android/server/AbstractPerUserSystemService.java +++ b/services/core/java/com/android/server/AbstractPerUserSystemService.java @@ -163,6 +163,20 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst } /** + * Gets the user associated with this service. + */ + public final @UserIdInt int getUserId() { + return mUserId; + } + + /** + * Gets the master service. + */ + public final M getMaster() { + return mMaster; + } + + /** * Gets this UID of the remote service this service binds to, or {@code -1} if the service is * disabled. */ diff --git a/services/core/java/com/android/server/AbstractRemoteService.java b/services/core/java/com/android/server/AbstractRemoteService.java index 181d7fde1fb8..0d4cf6b01ba8 100644 --- a/services/core/java/com/android/server/AbstractRemoteService.java +++ b/services/core/java/com/android/server/AbstractRemoteService.java @@ -205,6 +205,9 @@ public abstract class AbstractRemoteService implements DeathRecipient { protected void scheduleUnbind() { cancelScheduledUnbind(); + // TODO(b/111276913): implement "permanent binding" + // TODO(b/117779333): make sure it's unbound if the service settings changing (right now + // it's not) mHandler.sendMessageDelayed(obtainMessage(AbstractRemoteService::handleUnbind, this) .setWhat(MSG_UNBIND), getTimeoutIdleBindMillis()); } @@ -250,7 +253,7 @@ public abstract class AbstractRemoteService implements DeathRecipient { } final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, - new UserHandle(mUserId)); + mHandler, new UserHandle(mUserId)); if (!willBind) { Slog.w(mTag, "could not bind to " + mIntent + " using flags " + flags); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 74c80237d721..60bbca833925 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -894,10 +894,18 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( - mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); + mIntentReceiver, UserHandle.ALL, intentFilter, null, null); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); + // Listen to package add and removal events for all users. + intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addDataScheme("package"); + mContext.registerReceiverAsUser( + mIntentReceiver, UserHandle.ALL, intentFilter, null, null); + try { mNMS.registerObserver(mTethering); mNMS.registerObserver(mDataActivityObserver); @@ -1659,6 +1667,24 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("Error parsing ip address in validation event"); } } + + @Override + public void onDnsEvent(int netId, int eventType, int returnCode, String hostname, + String[] ipAddresses, int ipAddressesCount, long timestamp, int uid) { + NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId); + // Netd event only allow registrants from system. Each NetworkMonitor thread is under + // the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd + // event callback for certain nai. e.g. cellular. Register here to pass to + // NetworkMonitor instead. + // TODO: Move the Dns Event to NetworkMonitor. Use Binder.clearCallingIdentity() in + // registerNetworkAgent to have NetworkMonitor created with system process as design + // expectation. Also, NetdEventListenerService only allow one callback from each + // caller type. Need to re-factor NetdEventListenerService to allow multiple + // NetworkMonitor registrants. + if (nai != null && nai.satisfies(mDefaultRequest)) { + nai.networkMonitor.sendMessage(NetworkMonitor.EVENT_DNS_NOTIFICATION, returnCode); + } + } }; @VisibleForTesting @@ -2073,12 +2099,14 @@ public class ConnectivityService extends IConnectivityManager.Stub return new MockableSystemProperties(); } - private void updateTcpBufferSizes(NetworkAgentInfo nai) { + // TODO: Replace nai and newLp with TcpBufferSizes and check default network before calling + // this method. + private void updateTcpBufferSizes(NetworkAgentInfo nai, LinkProperties newLp) { if (isDefaultNetwork(nai) == false) { return; } - String tcpBufferSizes = nai.linkProperties.getTcpBufferSizes(); + String tcpBufferSizes = newLp.getTcpBufferSizes(); String[] values = null; if (tcpBufferSizes != null) { values = tcpBufferSizes.split(","); @@ -4155,6 +4183,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserAdded(int userId) { + mPermissionMonitor.onUserAdded(userId); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { @@ -4165,6 +4194,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserRemoved(int userId) { + mPermissionMonitor.onUserRemoved(userId); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { @@ -4174,6 +4204,22 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void onPackageAdded(String packageName, int uid) { + if (TextUtils.isEmpty(packageName) || uid < 0) { + Slog.wtf(TAG, "Invalid package in onPackageAdded: " + packageName + " | " + uid); + return; + } + mPermissionMonitor.onPackageAdded(packageName, uid); + } + + private void onPackageRemoved(String packageName, int uid) { + if (TextUtils.isEmpty(packageName) || uid < 0) { + Slog.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid); + return; + } + mPermissionMonitor.onPackageRemoved(uid); + } + private void onUserUnlocked(int userId) { synchronized (mVpns) { // User present may be sent because of an unlock, which might mean an unlocked keystore. @@ -4185,11 +4231,15 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + final Uri packageData = intent.getData(); + final String packageName = + packageData != null ? packageData.getSchemeSpecificPart() : null; if (userId == UserHandle.USER_NULL) return; if (Intent.ACTION_USER_STARTED.equals(action)) { @@ -4202,6 +4252,10 @@ public class ConnectivityService extends IConnectivityManager.Stub onUserRemoved(userId); } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { onUserUnlocked(userId); + } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + onPackageAdded(packageName, uid); + } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + onPackageRemoved(packageName, uid); } } }; @@ -4728,8 +4782,8 @@ public class ConnectivityService extends IConnectivityManager.Stub updateUids(nai, null, nai.networkCapabilities); } - private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) { - LinkProperties newLp = new LinkProperties(networkAgent.linkProperties); + private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp, + LinkProperties oldLp) { int netId = networkAgent.network.netId; // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before @@ -4744,7 +4798,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // for (LinkProperties lp : newLp.getStackedLinks()) { // updateMtu(lp, null); // } - updateTcpBufferSizes(networkAgent); + updateTcpBufferSizes(networkAgent, newLp); updateRoutes(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); @@ -4754,8 +4808,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // updateDnses will fetch the private DNS configuration from DnsManager. mDnsManager.updatePrivateDnsStatus(netId, newLp); - // Start or stop clat accordingly to network state. - networkAgent.updateClat(mNMS); if (isDefaultNetwork(networkAgent)) { handleApplyDefaultProxy(newLp.getHttpProxy()); } else { @@ -4766,8 +4818,12 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (networkAgent) { networkAgent.linkProperties = newLp; } + // Start or stop clat accordingly to network state. + networkAgent.updateClat(mNMS); notifyIfacesChangedForNetworkStats(); - notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED); + if (networkAgent.everConnected) { + notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED); + } } mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent); @@ -5072,13 +5128,7 @@ public class ConnectivityService extends IConnectivityManager.Stub "; created=" + nai.created + "; everConnected=" + nai.everConnected); } - LinkProperties oldLp = nai.linkProperties; - synchronized (nai) { - nai.linkProperties = newLp; - } - if (nai.everConnected) { - updateLinkProperties(nai, oldLp); - } + updateLinkProperties(nai, newLp, new LinkProperties(nai.linkProperties)); } private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) { @@ -5239,7 +5289,7 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyLockdownVpn(newNetwork); handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy()); - updateTcpBufferSizes(newNetwork); + updateTcpBufferSizes(newNetwork, new LinkProperties(newNetwork.linkProperties)); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); } @@ -5654,7 +5704,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig()); - updateLinkProperties(networkAgent, null); + updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties), + null); networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); scheduleUnvalidatedPrompt(networkAgent); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 046442a0b3ad..e5275e50e484 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -17,6 +17,7 @@ package com.android.server; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS; import android.Manifest; import android.annotation.NonNull; @@ -2990,7 +2991,7 @@ public class LocationManagerService extends ILocationManager.Stub { ArrayList<Receiver> deadReceivers = null; ArrayList<UpdateRecord> deadUpdateRecords = null; - // Broadcast location or status to all listeners + // Broadcast location to all listeners for (UpdateRecord r : records) { Receiver receiver = r.mReceiver; boolean receiverDead = false; @@ -3049,14 +3050,19 @@ public class LocationManagerService extends ILocationManager.Stub { } } - long prevStatusUpdateTime = r.mLastStatusBroadcast; - if ((newStatusUpdateTime > prevStatusUpdateTime) && - (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { + // TODO: location provider status callbacks have been disabled and deprecated, and are + // guarded behind this setting now. should be removed completely post-Q + if (Settings.Global.getInt(mContext.getContentResolver(), + LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) { + long prevStatusUpdateTime = r.mLastStatusBroadcast; + if ((newStatusUpdateTime > prevStatusUpdateTime) + && (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { - r.mLastStatusBroadcast = newStatusUpdateTime; - if (!receiver.callStatusChangedLocked(provider, status, extras)) { - receiverDead = true; - Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); + r.mLastStatusBroadcast = newStatusUpdateTime; + if (!receiver.callStatusChangedLocked(provider, status, extras)) { + receiverDead = true; + Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); + } } } @@ -3276,7 +3282,6 @@ public class LocationManagerService extends ILocationManager.Stub { // we don't leave anything dangling. clearTestProviderEnabled(provider, opPackageName); clearTestProviderLocation(provider, opPackageName); - clearTestProviderStatus(provider, opPackageName); MockProvider mockProvider = mMockProviders.remove(provider); if (mockProvider == null) { @@ -3409,21 +3414,6 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public void clearTestProviderStatus(String provider, String opPackageName) { - if (!canCallerAccessMockLocation(opPackageName)) { - return; - } - - synchronized (mLock) { - MockProvider mockProvider = mMockProviders.get(provider); - if (mockProvider == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - mockProvider.clearStatus(); - } - } - - @Override public PendingIntent createManageLocationPermissionIntent(String packageName, String permission) { Preconditions.checkNotNull(packageName); diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index d1b56e9afa4e..e80e9e1b594e 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -105,6 +105,7 @@ public class Watchdog extends Thread { "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", diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7e9e83cf17d0..80e73132f542 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -497,6 +497,18 @@ public class ActivityManagerService extends IActivityManager.Stub private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB /** + * The number of binder proxies we need to have before we start warning and + * dumping debug info. + */ + private static final int BINDER_PROXY_HIGH_WATERMARK = 6000; + + /** + * Low watermark that needs to be met before we consider dumping info again, + * after already hitting the high watermark. + */ + private static final int BINDER_PROXY_LOW_WATERMARK = 5500; + + /** * State indicating that there is no need for any blocking for network. */ @VisibleForTesting @@ -4360,7 +4372,6 @@ public class ActivityManagerService extends IActivityManager.Stub EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName); - app.makeActive(thread, mProcessStats); app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ; app.setCurrentSchedulingGroup(app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT); app.forcingToImportant = null; @@ -4567,6 +4578,10 @@ public class ActivityManagerService extends IActivityManager.Stub profilerInfo.closeFd(); profilerInfo = null; } + + // Make app active after binding application or client may be running requests (e.g + // starting activities) before it is ready. + app.makeActive(thread, mProcessStats); checkTime(startTime, "attachApplicationLocked: immediately after bindApplication"); mProcessList.updateLruProcessLocked(app, false, null); checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked"); @@ -8477,7 +8492,8 @@ public class ActivityManagerService extends IActivityManager.Stub mAtmInternal.resumeTopActivities(false /* scheduleIdle */); mUserController.sendUserSwitchBroadcasts(-1, currentUserId); - BinderInternal.nSetBinderProxyCountWatermarks(6000,5500); + BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK, + BINDER_PROXY_LOW_WATERMARK); BinderInternal.nSetBinderProxyCountEnabled(true); BinderInternal.setBinderProxyCountCallback( new BinderInternal.BinderProxyLimitListener() { @@ -9217,11 +9233,6 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpBinderProxies(pw); - pw.println(); - if (dumpAll) { - pw.println("-------------------------------------------------------------------------------"); - } dumpLmkLocked(pw); } pw.println(); @@ -9235,6 +9246,19 @@ public class ActivityManagerService extends IActivityManager.Stub } dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId); } + if (dumpPackage == null) { + // Intentionally dropping the lock for this, because dumpBinderProxies() will make many + // outgoing binder calls to retrieve interface descriptors; while that is system code, + // there is nothing preventing an app from overriding this implementation by talking to + // the binder driver directly, and hang up system_server in the process. So, dump + // without locks held, and even then only when there is an unreasonably large number of + // proxies in the first place. + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + } + dumpBinderProxies(pw, BINDER_PROXY_HIGH_WATERMARK /* minToDump */); + } } /** @@ -9373,7 +9397,7 @@ public class ActivityManagerService extends IActivityManager.Stub cmd, fd, pw, args, opti, true /* dumpAll */, dumpClient, dumpPackage); } else if ("binder-proxies".equals(cmd)) { if (opti >= args.length) { - dumpBinderProxies(pw); + dumpBinderProxies(pw, 0 /* minToDump */); } else { String uid = args[opti]; opti++; @@ -9714,10 +9738,17 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } - void dumpBinderProxies(PrintWriter pw) { + void dumpBinderProxies(PrintWriter pw, int minCountToDumpInterfaces) { pw.println("ACTIVITY MANAGER BINDER PROXY STATE (dumpsys activity binder-proxies)"); - dumpBinderProxyInterfaceCounts(pw, - " Top proxy interface names held by SYSTEM"); + final int proxyCount = BinderProxy.getProxyCount(); + if (proxyCount >= minCountToDumpInterfaces) { + dumpBinderProxyInterfaceCounts(pw, + "Top proxy interface names held by SYSTEM"); + } else { + pw.print("Not dumping proxy interface counts because size (" + + Integer.toString(proxyCount) + ") looks reasonable"); + pw.println(); + } dumpBinderProxiesCounts(pw, " Counts of Binder Proxies held by SYSTEM"); } diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java index 4fe7d03c3362..09df7e20a3e9 100644 --- a/services/core/java/com/android/server/am/AssistDataRequester.java +++ b/services/core/java/com/android/server/am/AssistDataRequester.java @@ -222,11 +222,11 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i); receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities); boolean result = requestAutofillData - ? ActivityTaskManager.getService().requestAssistContextExtras( + ? ActivityTaskManager.getService().requestAutofillData(this, + receiverExtras, topActivity, 0 /* flags */) + : ActivityTaskManager.getService().requestAssistContextExtras( ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity, - /* focused= */ i == 0, /* newSessionId= */ i == 0) - : ActivityTaskManager.getService().requestAutofillData(this, - receiverExtras, topActivity, 0 /* flags */); + /* focused= */ i == 0, /* newSessionId= */ i == 0); if (result) { mPendingDataCount++; } else if (i == 0) { diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index a5848ca0235a..4c4a09060706 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -65,6 +65,7 @@ class SettingsToPropertiesMapper { // permission in the corresponding .te file your feature belongs to. @VisibleForTesting static final String[] sGlobalSettings = new String[] { + Settings.Global.NATIVE_FLAGS_HEALTH_CHECK_ENABLED, }; @VisibleForTesting diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 67d27c94f41b..6cde4adb9f11 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -649,6 +649,9 @@ public class AudioService extends IAudioService.Stub private String mEnabledSurroundFormats; private boolean mSurroundModeChanged; + @GuardedBy("mSettingsLock") + private int mAssistantUid; + // Intent "extra" data keys. public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName"; public static final String CONNECT_INTENT_KEY_STATE = "state"; @@ -1079,6 +1082,10 @@ public class AudioService extends IAudioService.Stub AudioSystem.setForceUse(AudioSystem.FOR_DOCK, forDock); sendEncodedSurroundMode(mContentResolver, "onAudioServerDied"); sendEnabledSurroundFormats(mContentResolver, true); + updateAssistantUId(true); + } + synchronized (mAccessibilityServiceUidsLock) { + AudioSystem.setA11yServicesUids(mAccessibilityServiceUids); } synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiTvClient != null) { @@ -1404,6 +1411,39 @@ public class AudioService extends IAudioService.Stub } } + @GuardedBy("mSettingsLock") + private void updateAssistantUId(boolean forceUpdate) { + int assistantUid = 0; + + // Consider assistants in the following order of priority: + // 1) voice interaction service + // 2) assistant + String assistantName = Settings.Secure.getStringForUser( + mContentResolver, + Settings.Secure.VOICE_INTERACTION_SERVICE, UserHandle.USER_CURRENT); + if (TextUtils.isEmpty(assistantName)) { + assistantName = Settings.Secure.getStringForUser( + mContentResolver, + Settings.Secure.ASSISTANT, UserHandle.USER_CURRENT); + } + if (!TextUtils.isEmpty(assistantName)) { + String packageName = ComponentName.unflattenFromString(assistantName).getPackageName(); + if (!TextUtils.isEmpty(packageName)) { + try { + assistantUid = mContext.getPackageManager().getPackageUid(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, + "updateAssistantUId() could not find UID for package: " + packageName); + } + } + } + + if (assistantUid != mAssistantUid || forceUpdate) { + AudioSystem.setAssistantUid(assistantUid); + mAssistantUid = assistantUid; + } + } + private void readPersistedSettings() { final ContentResolver cr = mContentResolver; @@ -1447,6 +1487,7 @@ public class AudioService extends IAudioService.Stub readDockAudioSettings(cr); sendEncodedSurroundMode(cr, "readPersistedSettings"); sendEnabledSurroundFormats(cr, true); + updateAssistantUId(true); } mMuteAffectedStreams = System.getIntForUser(cr, @@ -5811,6 +5852,9 @@ public class AudioService extends IAudioService.Stub mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS); mContentResolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS), false, this); + + mContentResolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.VOICE_INTERACTION_SERVICE), false, this); } @Override @@ -5832,6 +5876,7 @@ public class AudioService extends IAudioService.Stub updateMasterMono(mContentResolver); updateEncodedSurroundOutput(); sendEnabledSurroundFormats(mContentResolver, mSurroundModeChanged); + updateAssistantUId(false); } } @@ -7658,6 +7703,7 @@ public class AudioService extends IAudioService.Stub mAccessibilityServiceUids = uids.toArray(); } } + AudioSystem.setA11yServicesUids(mAccessibilityServiceUids); } } } diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index c3e38424e90b..c2f4406c615d 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -72,6 +72,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Protocol; +import com.android.internal.util.RingBufferIndices; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.connectivity.DnsManager.PrivateDnsConfig; @@ -99,7 +100,7 @@ public class NetworkMonitor extends StateMachine { private static final String TAG = NetworkMonitor.class.getSimpleName(); private static final boolean DBG = true; private static final boolean VDBG = false; - + private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG); // Default configuration values for captive portal detection probes. // TODO: append a random length parameter to the default HTTPS url. // TODO: randomize browser version ids in the default User-Agent String. @@ -116,6 +117,15 @@ public class NetworkMonitor extends StateMachine { private static final int SOCKET_TIMEOUT_MS = 10000; private static final int PROBE_TIMEOUT_MS = 3000; + // Default configuration values for data stall detection. + private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5; + private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000; + private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000; + + private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; + private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = + (1 << DATA_STALL_EVALUATION_TYPE_DNS); + static enum EvaluationResult { VALIDATED(true), CAPTIVE_PORTAL(false); @@ -233,6 +243,12 @@ public class NetworkMonitor extends StateMachine { */ public static final int CMD_PROBE_COMPLETE = BASE + 16; + /** + * ConnectivityService notifies NetworkMonitor of DNS query responses event. + * arg1 = returncode in OnDnsEvent which indicates the response code for the DNS query. + */ + public static final int EVENT_DNS_NOTIFICATION = BASE + 17; + // Start mReevaluateDelayMs at this value and double. private static final int INITIAL_REEVALUATE_DELAY_MS = 1000; private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000; @@ -314,6 +330,12 @@ public class NetworkMonitor extends StateMachine { private int mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS; private int mEvaluateAttempts = 0; private volatile int mProbeToken = 0; + private final int mConsecutiveDnsTimeoutThreshold; + private final int mDataStallMinEvaluateTime; + private final int mDataStallValidDnsTimeThreshold; + private final int mDataStallEvaluationType; + private final DnsStallDetector mDnsStallDetector; + private long mLastProbeTime; public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) { @@ -359,6 +381,12 @@ public class NetworkMonitor extends StateMachine { mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls(); mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs(); mRandom = deps.getRandom(); + // TODO: Evaluate to move data stall configuration to a specific class. + mConsecutiveDnsTimeoutThreshold = getConsecutiveDnsTimeoutThreshold(); + mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold); + mDataStallMinEvaluateTime = getDataStallMinEvaluateTime(); + mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold(); + mDataStallEvaluationType = getDataStallEvalutionType(); start(); } @@ -507,6 +535,9 @@ public class NetworkMonitor extends StateMachine { sendMessage(CMD_EVALUATE_PRIVATE_DNS); break; } + case EVENT_DNS_NOTIFICATION: + mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1); + break; default: break; } @@ -537,6 +568,13 @@ public class NetworkMonitor extends StateMachine { case CMD_EVALUATE_PRIVATE_DNS: transitionTo(mEvaluatingPrivateDnsState); break; + case EVENT_DNS_NOTIFICATION: + mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1); + if (isDataStall()) { + validationLog("Suspecting data stall, reevaluate"); + transitionTo(mEvaluatingState); + } + break; default: return NOT_HANDLED; } @@ -856,6 +894,7 @@ public class NetworkMonitor extends StateMachine { final CaptivePortalProbeResult probeResult = (CaptivePortalProbeResult) message.obj; + mLastProbeTime = SystemClock.elapsedRealtime(); if (probeResult.isSuccessful()) { // Transit EvaluatingPrivateDnsState to get to Validated // state (even if no Private DNS validation required). @@ -883,6 +922,7 @@ public class NetworkMonitor extends StateMachine { // Leave the event to EvaluatingState. Defer this message will result in reset // of mReevaluateDelayMs and mEvaluateAttempts. case CMD_NETWORK_DISCONNECTED: + case EVENT_DNS_NOTIFICATION: return NOT_HANDLED; default: // TODO: Some events may able to handle in this state, instead of deferring to @@ -947,6 +987,29 @@ public class NetworkMonitor extends StateMachine { Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL); } + private int getConsecutiveDnsTimeoutThreshold() { + return mDependencies.getSetting(mContext, + Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD, + DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD); + } + + private int getDataStallMinEvaluateTime() { + return mDependencies.getSetting(mContext, + Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL, + DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS); + } + + private int getDataStallValidDnsTimeThreshold() { + return mDependencies.getSetting(mContext, + Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD, + DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS); + } + + private int getDataStallEvalutionType() { + return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE, + DEFAULT_DATA_STALL_EVALUATION_TYPES); + } + // Static for direct access by ConnectivityService public static String getCaptivePortalServerHttpUrl(Context context) { return getCaptivePortalServerHttpUrl(Dependencies.DEFAULT, context); @@ -1462,4 +1525,127 @@ public class NetworkMonitor extends StateMachine { public static final Dependencies DEFAULT = new Dependencies(); } + + /** + * Methods in this class perform no locking because all accesses are performed on the state + * machine's thread. Need to consider the thread safety if it ever could be accessed outside the + * state machine. + */ + @VisibleForTesting + protected class DnsStallDetector { + private static final int DEFAULT_DNS_LOG_SIZE = 50; + private int mConsecutiveTimeoutCount = 0; + private int mSize; + final DnsResult[] mDnsEvents; + final RingBufferIndices mResultIndices; + + DnsStallDetector(int size) { + mSize = Math.max(DEFAULT_DNS_LOG_SIZE, size); + mDnsEvents = new DnsResult[mSize]; + mResultIndices = new RingBufferIndices(mSize); + } + + @VisibleForTesting + protected void accumulateConsecutiveDnsTimeoutCount(int code) { + final DnsResult result = new DnsResult(code); + mDnsEvents[mResultIndices.add()] = result; + if (result.isTimeout()) { + mConsecutiveTimeoutCount++; + } else { + // Keep the event in mDnsEvents without clearing it so that there are logs to do the + // simulation and analysis. + mConsecutiveTimeoutCount = 0; + } + } + + private boolean isDataStallSuspected(int timeoutCountThreshold, int validTime) { + if (timeoutCountThreshold <= 0) { + Log.wtf(TAG, "Timeout count threshold should be larger than 0."); + return false; + } + + // Check if the consecutive timeout count reach the threshold or not. + if (mConsecutiveTimeoutCount < timeoutCountThreshold) { + return false; + } + + // Check if the target dns event index is valid or not. + final int firstConsecutiveTimeoutIndex = + mResultIndices.indexOf(mResultIndices.size() - timeoutCountThreshold); + + // If the dns timeout events happened long time ago, the events are meaningless for + // data stall evaluation. Thus, check if the first consecutive timeout dns event + // considered in the evaluation happened in defined threshold time. + final long now = SystemClock.elapsedRealtime(); + final long firstTimeoutTime = now - mDnsEvents[firstConsecutiveTimeoutIndex].mTimeStamp; + return (firstTimeoutTime < validTime); + } + + int getConsecutiveTimeoutCount() { + return mConsecutiveTimeoutCount; + } + } + + private static class DnsResult { + // TODO: Need to move the DNS return code definition to a specific class once unify DNS + // response code is done. + private static final int RETURN_CODE_DNS_TIMEOUT = 255; + + private final long mTimeStamp; + private final int mReturnCode; + + DnsResult(int code) { + mTimeStamp = SystemClock.elapsedRealtime(); + mReturnCode = code; + } + + private boolean isTimeout() { + return mReturnCode == RETURN_CODE_DNS_TIMEOUT; + } + } + + + @VisibleForTesting + protected DnsStallDetector getDnsStallDetector() { + return mDnsStallDetector; + } + + private boolean dataStallEvaluateTypeEnabled(int type) { + return (mDataStallEvaluationType & (1 << type)) != 0; + } + + @VisibleForTesting + protected long getLastProbeTime() { + return mLastProbeTime; + } + + @VisibleForTesting + protected boolean isDataStall() { + boolean result = false; + // Reevaluation will generate traffic. Thus, set a minimal reevaluation timer to limit the + // possible traffic cost in metered network. + if (mNetworkAgentInfo.networkCapabilities.isMetered() + && (SystemClock.elapsedRealtime() - getLastProbeTime() + < mDataStallMinEvaluateTime)) { + return false; + } + + // Check dns signal. Suspect it may be a data stall if both : + // 1. The number of consecutive DNS query timeouts > mConsecutiveDnsTimeoutThreshold. + // 2. Those consecutive DNS queries happened in the last mValidDataStallDnsTimeThreshold ms. + if (dataStallEvaluateTypeEnabled(DATA_STALL_EVALUATION_TYPE_DNS)) { + if (mDnsStallDetector.isDataStallSuspected(mConsecutiveDnsTimeoutThreshold, + mDataStallValidDnsTimeThreshold)) { + result = true; + logNetworkEvent(NetworkEvent.NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND); + } + } + + if (VDBG_STALL) { + log("isDataStall: result=" + result + ", consecutive dns timeout count=" + + mDnsStallDetector.getConsecutiveTimeoutCount()); + } + + return result; + } } diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 94c94a514dec..420b23e6a39f 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -27,10 +27,7 @@ import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; import android.annotation.NonNull; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -42,7 +39,6 @@ import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; -import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -64,15 +60,14 @@ import java.util.Set; public class PermissionMonitor { private static final String TAG = "PermissionMonitor"; private static final boolean DBG = true; - private static final Boolean SYSTEM = Boolean.TRUE; - private static final Boolean NETWORK = Boolean.FALSE; + protected static final Boolean SYSTEM = Boolean.TRUE; + protected static final Boolean NETWORK = Boolean.FALSE; private static final int VERSION_Q = Build.VERSION_CODES.Q; private final Context mContext; private final PackageManager mPackageManager; private final UserManager mUserManager; private final INetworkManagementService mNetd; - private final BroadcastReceiver mIntentReceiver; // Values are User IDs. private final Set<Integer> mUsers = new HashSet<>(); @@ -85,26 +80,6 @@ public class PermissionMonitor { mPackageManager = context.getPackageManager(); mUserManager = UserManager.get(context); mNetd = netd; - mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); - int appUid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID); - Uri appData = intent.getData(); - String appName = appData != null ? appData.getSchemeSpecificPart() : null; - - if (Intent.ACTION_USER_ADDED.equals(action)) { - onUserAdded(user); - } else if (Intent.ACTION_USER_REMOVED.equals(action)) { - onUserRemoved(user); - } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { - onAppAdded(appName, appUid); - } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - onAppRemoved(appUid); - } - } - }; } // Intended to be called only once at startup, after the system is ready. Installs a broadcast @@ -112,17 +87,6 @@ public class PermissionMonitor { public synchronized void startMonitoring() { log("Monitoring"); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_USER_ADDED); - intentFilter.addAction(Intent.ACTION_USER_REMOVED); - mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null); - - intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); - intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); - intentFilter.addDataScheme("package"); - mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null); - List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS); if (apps == null) { loge("No apps"); @@ -260,7 +224,14 @@ public class PermissionMonitor { } } - private synchronized void onUserAdded(int user) { + /** + * Called when a user is added. See {link #ACTION_USER_ADDED}. + * + * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}. + * + * @hide + */ + public synchronized void onUserAdded(int user) { if (user < 0) { loge("Invalid user in onUserAdded: " + user); return; @@ -272,7 +243,14 @@ public class PermissionMonitor { update(users, mApps, true); } - private synchronized void onUserRemoved(int user) { + /** + * Called when an user is removed. See {link #ACTION_USER_REMOVED}. + * + * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}. + * + * @hide + */ + public synchronized void onUserRemoved(int user) { if (user < 0) { loge("Invalid user in onUserRemoved: " + user); return; @@ -284,8 +262,8 @@ public class PermissionMonitor { update(users, mApps, false); } - - private Boolean highestPermissionForUid(Boolean currentPermission, String name) { + @VisibleForTesting + protected Boolean highestPermissionForUid(Boolean currentPermission, String name) { if (currentPermission == SYSTEM) { return currentPermission; } @@ -303,33 +281,39 @@ public class PermissionMonitor { return currentPermission; } - private synchronized void onAppAdded(String appName, int appUid) { - if (TextUtils.isEmpty(appName) || appUid < 0) { - loge("Invalid app in onAppAdded: " + appName + " | " + appUid); - return; - } - + /** + * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}. + * + * @param packageName The name of the new package. + * @param uid The uid of the new package. + * + * @hide + */ + public synchronized void onPackageAdded(String packageName, int uid) { // If multiple packages share a UID (cf: android:sharedUserId) and ask for different // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is). - final Boolean permission = highestPermissionForUid(mApps.get(appUid), appName); - if (permission != mApps.get(appUid)) { - mApps.put(appUid, permission); + final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName); + if (permission != mApps.get(uid)) { + mApps.put(uid, permission); Map<Integer, Boolean> apps = new HashMap<>(); - apps.put(appUid, permission); + apps.put(uid, permission); update(mUsers, apps, true); } } - private synchronized void onAppRemoved(int appUid) { - if (appUid < 0) { - loge("Invalid app in onAppRemoved: " + appUid); - return; - } + /** + * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}. + * + * @param uid containing the integer uid previously assigned to the package. + * + * @hide + */ + public synchronized void onPackageRemoved(int uid) { Map<Integer, Boolean> apps = new HashMap<>(); Boolean permission = null; - String[] packages = mPackageManager.getPackagesForUid(appUid); + String[] packages = mPackageManager.getPackagesForUid(uid); if (packages != null && packages.length > 0) { for (String name : packages) { permission = highestPermissionForUid(permission, name); @@ -341,16 +325,16 @@ public class PermissionMonitor { } } } - if (permission == mApps.get(appUid)) { + if (permission == mApps.get(uid)) { // The permissions of this UID have not changed. Nothing to do. return; } else if (permission != null) { - mApps.put(appUid, permission); - apps.put(appUid, permission); + mApps.put(uid, permission); + apps.put(uid, permission); update(mUsers, apps, true); } else { - mApps.remove(appUid); - apps.put(appUid, NETWORK); // doesn't matter which permission we pick here + mApps.remove(uid); + apps.put(uid, NETWORK); // doesn't matter which permission we pick here update(mUsers, apps, false); } } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 3a31c9c5e05f..3339a49c5ed0 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -1443,25 +1443,10 @@ public class InputManagerService extends IInputManager.Stub } } - public void setInputWindows(InputWindowHandle[] windowHandles, int displayId) { - nativeSetInputWindows(mPtr, windowHandles, displayId); - } - public void setFocusedApplication(int displayId, InputApplicationHandle application) { nativeSetFocusedApplication(mPtr, displayId, application); } - public void setFocusedWindow(InputWindowHandle focusedWindowHandle) { - final IWindow newFocusedWindow = - focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null; - if (mFocusedWindow != newFocusedWindow) { - if (mFocusedWindowHasCapture) { - setPointerCapture(false); - } - mFocusedWindow = newFocusedWindow; - } - } - public void setFocusedDisplay(int displayId) { nativeSetFocusedDisplay(mPtr, displayId); } @@ -1799,11 +1784,22 @@ public class InputManagerService extends IInputManager.Stub mWindowManagerCallbacks.notifyInputChannelBroken(token); } + // Native callback + private void notifyFocusChanged(IBinder token) { + if (mFocusedWindow != token) { + if (mFocusedWindowHasCapture) { + setPointerCapture(false); + } + if (token instanceof IWindow) { + mFocusedWindow = (IWindow) token; + } + } + } + // Native callback. - private long notifyANR(InputApplicationHandle inputApplicationHandle, - IBinder token, String reason) { + private long notifyANR(IBinder token, String reason) { return mWindowManagerCallbacks.notifyANR( - inputApplicationHandle, token, reason); + token, reason); } // Native callback. @@ -1834,14 +1830,12 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private long interceptKeyBeforeDispatching(IBinder focus, - KeyEvent event, int policyFlags) { + private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) { return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); } // Native callback. - private KeyEvent dispatchUnhandledKey(IBinder focus, - KeyEvent event, int policyFlags) { + private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) { return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); } @@ -1993,8 +1987,7 @@ public class InputManagerService extends IInputManager.Stub public void notifyInputChannelBroken(IBinder token); - public long notifyANR(InputApplicationHandle inputApplicationHandle, - IBinder token, String reason); + public long notifyANR(IBinder token, String reason); public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1dfb86a1eff1..a8da9680c4f5 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2420,8 +2420,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub .setContentText(summary) .setContentIntent(mImeSwitchPendingIntent); try { + // TODO(b/120076400): Figure out what is the best behavior if ((mNotificationManager != null) - && !mIWindowManager.hasNavigationBar()) { + && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) { if (DEBUG) { Slog.d(TAG, "--- show notification: label = " + summary); } diff --git a/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java index aac83b62b0a5..6fe632459eaa 100644 --- a/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java +++ b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java @@ -19,6 +19,8 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.os.Bundle; import android.os.IBinder; +import android.view.autofill.AutofillId; +import android.view.autofill.IAutoFillManagerClient; /** * Intelligence Manager local system service interface. @@ -41,4 +43,37 @@ public abstract class IntelligenceManagerInternal { */ public abstract boolean sendActivityAssistData(@UserIdInt int userId, @NonNull IBinder activityToken, @NonNull Bundle data); + + /** + * Asks the intelligence service to provide Augmented Autofill for a given activity. + * + * @param userId user handle + * @param client binder used to communicate with the activity that originated this request. + * @param activityToken activity that originated this request. + * @param autofillSessionId autofill session id (must be used on {@code client} calls. + * @param focusedId id of the the field that triggered this request. + * + * @return {@code false} if the service cannot handle this request, {@code true} otherwise. + * <b>NOTE: </b> it must return right away; typically it will return {@code false} if the + * service is disabled (or the activity blacklisted). + */ + public abstract AugmentedAutofillCallback requestAutofill(@UserIdInt int userId, + @NonNull IAutoFillManagerClient client, @NonNull IBinder activityToken, + int autofillSessionId, @NonNull AutofillId focusedId); + + /** + * Callback used by the Autofill Session to communicate with the Augmented Autofill service. + */ + public interface AugmentedAutofillCallback { + // TODO(b/111330312): this method is calling when the Autofill session is destroyed, the + // 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 + // new FillRequest, which in turn triggers the Augmented Autofill request again) + /** + * Destroys the Autofill UI. + */ + void destroy(); + } } diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 9e6e3812df6b..d5e4681a0d90 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -97,8 +97,8 @@ import java.util.Properties; * * {@hide} */ -public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback, - GnssSatelliteBlacklistCallback { +public class GnssLocationProvider extends LocationProviderInterface + implements InjectNtpTimeCallback, GnssSatelliteBlacklistCallback { private static final String TAG = "GnssLocationProvider"; diff --git a/services/core/java/com/android/server/location/LocationProviderInterface.java b/services/core/java/com/android/server/location/LocationProviderInterface.java index 6f0923233e19..678596445fe3 100644 --- a/services/core/java/com/android/server/location/LocationProviderInterface.java +++ b/services/core/java/com/android/server/location/LocationProviderInterface.java @@ -16,33 +16,63 @@ package com.android.server.location; -import java.io.FileDescriptor; -import java.io.PrintWriter; +import android.location.LocationProvider; +import android.os.Bundle; +import android.os.WorkSource; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; - -import android.os.Bundle; -import android.os.WorkSource; +import java.io.FileDescriptor; +import java.io.PrintWriter; /** * Location Manager's interface for location providers. * @hide */ -public interface LocationProviderInterface { - public String getName(); +public abstract class LocationProviderInterface { + + /** Get name. */ + public abstract String getName(); + + /** Enable. */ + public abstract void enable(); + + /** Disable. */ + public abstract void disable(); + + /** Is enabled. */ + public abstract boolean isEnabled(); + + /** Set request. */ + public abstract void setRequest(ProviderRequest request, WorkSource source); + + /** dump. */ + public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args); + + /** Get properties. */ + public abstract ProviderProperties getProperties(); - public void enable(); - public void disable(); - public boolean isEnabled(); - public void setRequest(ProviderRequest request, WorkSource source); + /** + * Get status. + * + * @deprecated Will be removed in a future release. + */ + @Deprecated + public int getStatus(Bundle extras) { + return LocationProvider.AVAILABLE; + } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args); + /** + * Get status update time. + * + * @deprecated Will be removed in a future release. + */ + @Deprecated + public long getStatusUpdateTime() { + return 0; + } - // --- deprecated (but still supported) --- - public ProviderProperties getProperties(); - public int getStatus(Bundle extras); - public long getStatusUpdateTime(); - public boolean sendExtraCommand(String command, Bundle extras); + /** Send extra command. */ + public abstract boolean sendExtraCommand(String command, Bundle extras); } diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index bb86b4852fd5..b40841467946 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -41,7 +41,7 @@ import java.io.PrintWriter; /** * Proxy for ILocationProvider implementations. */ -public class LocationProviderProxy implements LocationProviderInterface { +public class LocationProviderProxy extends LocationProviderInterface { private static final String TAG = "LocationProviderProxy"; private static final boolean D = LocationManagerService.D; diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index 857876189c55..145aee3a9e6a 100644 --- a/services/core/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java @@ -25,32 +25,32 @@ import android.os.WorkSource; import android.util.Log; import android.util.PrintWriterPrinter; +import com.android.internal.location.ProviderProperties; +import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; -import com.android.internal.location.ProviderProperties; -import com.android.internal.location.ProviderRequest; - /** * A mock location provider used by LocationManagerService to implement test providers. * * {@hide} */ -public class MockProvider implements LocationProviderInterface { +public class MockProvider extends LocationProviderInterface { private final String mName; private final ProviderProperties mProperties; private final ILocationManager mLocationManager; private final Location mLocation; - private final Bundle mExtras = new Bundle(); - private int mStatus; - private long mStatusUpdateTime; private boolean mHasLocation; - private boolean mHasStatus; private boolean mEnabled; + + private int mStatus; + private long mStatusUpdateTime; + private Bundle mExtras; + private static final String TAG = "MockProvider"; public MockProvider(String name, ILocationManager locationManager, @@ -61,6 +61,10 @@ public class MockProvider implements LocationProviderInterface { mLocationManager = locationManager; mProperties = properties; mLocation = new Location(name); + + mStatus = LocationProvider.AVAILABLE; + mStatusUpdateTime = 0L; + mExtras = null; } @Override @@ -90,13 +94,12 @@ public class MockProvider implements LocationProviderInterface { @Override public int getStatus(Bundle extras) { - if (mHasStatus) { + if (mExtras != null) { extras.clear(); extras.putAll(mExtras); - return mStatus; - } else { - return LocationProvider.AVAILABLE; } + + return mStatus; } @Override @@ -120,19 +123,14 @@ public class MockProvider implements LocationProviderInterface { mHasLocation = false; } + /** + * @deprecated Will be removed in a future release. + */ + @Deprecated public void setStatus(int status, Bundle extras, long updateTime) { mStatus = status; mStatusUpdateTime = updateTime; - mExtras.clear(); - if (extras != null) { - mExtras.putAll(extras); - } - mHasStatus = true; - } - - public void clearStatus() { - mHasStatus = false; - mStatusUpdateTime = 0; + mExtras = extras; } @Override @@ -145,9 +143,6 @@ public class MockProvider implements LocationProviderInterface { pw.println(prefix + "mHasLocation=" + mHasLocation); pw.println(prefix + "mLocation:"); mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); - pw.println(prefix + "mHasStatus=" + mHasStatus); - pw.println(prefix + "mStatus=" + mStatus); - pw.println(prefix + "mStatusUpdateTime=" + mStatusUpdateTime); pw.println(prefix + "mExtras=" + mExtras); } diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index 71bae07680a3..99c92149fa1b 100644 --- a/services/core/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java @@ -16,22 +16,20 @@ package com.android.server.location; -import java.io.FileDescriptor; -import java.io.PrintWriter; - -import com.android.internal.location.ProviderProperties; -import com.android.internal.location.ProviderRequest; - import android.location.Criteria; import android.location.ILocationManager; import android.location.Location; import android.location.LocationManager; -import android.location.LocationProvider; import android.os.Bundle; import android.os.RemoteException; import android.os.WorkSource; import android.util.Log; +import com.android.internal.location.ProviderProperties; +import com.android.internal.location.ProviderRequest; + +import java.io.FileDescriptor; +import java.io.PrintWriter; /** * A passive location provider reports locations received from other providers @@ -40,7 +38,7 @@ import android.util.Log; * * {@hide} */ -public class PassiveProvider implements LocationProviderInterface { +public class PassiveProvider extends LocationProviderInterface { private static final String TAG = "PassiveProvider"; private static final ProviderProperties PROPERTIES = new ProviderProperties( @@ -78,20 +76,6 @@ public class PassiveProvider implements LocationProviderInterface { } @Override - public int getStatus(Bundle extras) { - if (mReportLocation) { - return LocationProvider.AVAILABLE; - } else { - return LocationProvider.TEMPORARILY_UNAVAILABLE; - } - } - - @Override - public long getStatusUpdateTime() { - return -1; - } - - @Override public void setRequest(ProviderRequest request, WorkSource source) { mReportLocation = request.reportLocation; } diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index decdac6cbfce..9222740e0506 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -45,5 +45,15 @@ public interface NotificationDelegate { void onNotificationDirectReplied(String key); void onNotificationSettingsViewed(String key); void onNotificationSmartRepliesAdded(String key, int replyCount); - void onNotificationSmartReplySent(String key, int replyIndex); + + /** + * Notifies a smart reply is sent. + * + * @param key the notification key + * @param clickedIndex the index of clicked reply + * @param reply the reply that is sent + * @param generatedByAssistant specifies is the reply generated by NAS + */ + void onNotificationSmartReplySent(String key, int clickedIndex, CharSequence reply, + boolean generatedByAssistant); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 84577e22c41f..60058724e9a7 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -246,6 +246,7 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import java.util.function.Predicate; /** {@hide} */ @@ -887,6 +888,7 @@ public class NotificationManagerService extends SystemService { EventLogTags.writeNotificationExpansion(key, userAction ? 1 : 0, expanded ? 1 : 0, r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); + mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded); } } } @@ -902,6 +904,7 @@ public class NotificationManagerService extends SystemService { .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION) .setType(MetricsEvent.TYPE_ACTION)); reportUserInteraction(r); + mAssistants.notifyAssistantNotificationDirectReplyLocked(r.sbn); } } } @@ -917,7 +920,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationSmartReplySent(String key, int replyIndex) { + public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply, + boolean generatedByAssistant) { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { @@ -927,6 +931,8 @@ public class NotificationManagerService extends SystemService { mMetricsLogger.write(logMaker); // Treat clicking on a smart reply as a user interaction. reportUserInteraction(r); + mAssistants.notifyAssistantSuggestedReplySent( + r.sbn, reply, generatedByAssistant); } } } @@ -4730,7 +4736,7 @@ public class NotificationManagerService extends SystemService { mRankingHelper.extractSignals(r); // tell the assistant service about the notification if (mAssistants.isEnabled()) { - mAssistants.onNotificationEnqueued(r); + mAssistants.onNotificationEnqueuedLocked(r); mHandler.postDelayed(new PostNotificationRunnable(r.getKey()), DELAY_FOR_ASSISTANT_TIME); } else { @@ -6847,69 +6853,125 @@ public class NotificationManagerService extends SystemService { } } - public void onNotificationEnqueued(final NotificationRecord r) { + @GuardedBy("mNotificationLock") + private void onNotificationEnqueuedLocked(final NotificationRecord r) { final StatusBarNotification sbn = r.sbn; - TrimCache trimCache = new TrimCache(sbn); + notifyAssistantLocked( + sbn, + true /* sameUserOnly */, + (assistant, sbnHolder) -> { + try { + assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel()); + } catch (RemoteException ex) { + Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); + } + }); + } - // There should be only one, but it's a list, so while we enforce - // singularity elsewhere, we keep it general here, to avoid surprises. - for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { - boolean sbnVisible = isVisibleToListener(sbn, info) - && info.isSameUser(r.getUserId()); - if (!sbnVisible) { - continue; - } + @GuardedBy("mNotificationLock") + void notifyAssistantExpansionChangedLocked( + final StatusBarNotification sbn, + final boolean isUserAction, + final boolean isExpanded) { + final String key = sbn.getKey(); + notifyAssistantLocked( + sbn, + false /* sameUserOnly */, + (assistant, sbnHolder) -> { + try { + assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded); + } catch (RemoteException ex) { + Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); + } + }); + } - final StatusBarNotification sbnToPost = trimCache.ForListener(info); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyEnqueued(info, sbnToPost, r.getChannel()); - } - }); - } + @GuardedBy("mNotificationLock") + void notifyAssistantNotificationDirectReplyLocked( + final StatusBarNotification sbn) { + final String key = sbn.getKey(); + notifyAssistantLocked( + sbn, + false /* sameUserOnly */, + (assistant, sbnHolder) -> { + try { + assistant.onNotificationDirectReply(key); + } catch (RemoteException ex) { + Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex); + } + }); } - private void notifyEnqueued(final ManagedServiceInfo info, - final StatusBarNotification sbn, final NotificationChannel channel) { - final INotificationListener assistant = (INotificationListener) info.service; - StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); - try { - assistant.onNotificationEnqueuedWithChannel(sbnHolder, channel); - } catch (RemoteException ex) { - Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); - } + @GuardedBy("mNotificationLock") + void notifyAssistantSuggestedReplySent( + final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) { + final String key = sbn.getKey(); + notifyAssistantLocked( + sbn, + false /* sameUserOnly */, + (assistant, sbnHolder) -> { + try { + assistant.onSuggestedReplySent( + key, + reply, + generatedByAssistant + ? NotificationAssistantService.SOURCE_FROM_ASSISTANT + : NotificationAssistantService.SOURCE_FROM_APP); + } catch (RemoteException ex) { + Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); + } + }); } + /** * asynchronously notify the assistant that a notification has been snoozed until a * context */ @GuardedBy("mNotificationLock") - public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn, - final String snoozeCriterionId) { - TrimCache trimCache = new TrimCache(sbn); - for (final ManagedServiceInfo info : getServices()) { - boolean sbnVisible = isVisibleToListener(sbn, info); - if (!sbnVisible) { - continue; - } - final StatusBarNotification sbnToPost = trimCache.ForListener(info); - mHandler.post(new Runnable() { - @Override - public void run() { - final INotificationListener assistant = - (INotificationListener) info.service; - StatusBarNotificationHolder sbnHolder - = new StatusBarNotificationHolder(sbnToPost); + private void notifyAssistantSnoozedLocked( + final StatusBarNotification sbn, final String snoozeCriterionId) { + notifyAssistantLocked( + sbn, + false /* sameUserOnly */, + (assistant, sbnHolder) -> { try { assistant.onNotificationSnoozedUntilContext( sbnHolder, snoozeCriterionId); } catch (RemoteException ex) { Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); } - } - }); + }); + } + + /** + * Notifies the assistant something about the specified notification, only assistant + * that is visible to the notification will be notified. + * + * @param sbn the notification object that the update is about. + * @param sameUserOnly should the update be sent to the assistant in the same user only. + * @param callback the callback that provides the assistant to be notified, executed + * in WorkerHandler. + */ + @GuardedBy("mNotificationLock") + private void notifyAssistantLocked( + final StatusBarNotification sbn, + boolean sameUserOnly, + BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) { + TrimCache trimCache = new TrimCache(sbn); + // There should be only one, but it's a list, so while we enforce + // singularity elsewhere, we keep it general here, to avoid surprises. + for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { + boolean sbnVisible = isVisibleToListener(sbn, info) + && (!sameUserOnly || info.isSameUser(sbn.getUserId())); + if (!sbnVisible) { + continue; + } + final INotificationListener assistant = (INotificationListener) info.service; + final StatusBarNotification sbnToPost = trimCache.ForListener(info); + final StatusBarNotificationHolder sbnHolder = + new StatusBarNotificationHolder(sbnToPost); + mHandler.post(() -> callback.accept(assistant, sbnHolder)); } } diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 731e6bcfb074..6d5982708f4c 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -46,7 +46,7 @@ import java.io.File; * Note: this class is subclassed in the OMS unit tests, and hence not marked as final. */ class IdmapManager { - private static final boolean FEATURE_FLAG_IDMAP2 = false; + private static final boolean FEATURE_FLAG_IDMAP2 = true; private final Installer mInstaller; private IIdmap2 mIdmap2Service; diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index cc640f03edba..093b85e5ed4c 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -16,6 +16,28 @@ package com.android.server.pm; +import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; + +import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; +import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; +import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS; +import static com.android.server.pm.Installer.DEXOPT_FORCE; +import static com.android.server.pm.Installer.DEXOPT_GENERATE_APP_IMAGE; +import static com.android.server.pm.Installer.DEXOPT_GENERATE_COMPACT_DEX; +import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB; +import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; +import static com.android.server.pm.Installer.DEXOPT_PUBLIC; +import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX; +import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE; +import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE; +import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; +import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; +import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName; + +import static dalvik.system.DexFile.getSafeModeCompilerFilter; +import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; + import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -41,6 +63,8 @@ import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.DexoptUtils; import com.android.server.pm.dex.PackageDexUsage; +import dalvik.system.DexFile; + import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -48,32 +72,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import dalvik.system.DexFile; - -import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; - -import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; -import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; -import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; -import static com.android.server.pm.Installer.DEXOPT_PUBLIC; -import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX; -import static com.android.server.pm.Installer.DEXOPT_FORCE; -import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE; -import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE; -import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB; -import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS; -import static com.android.server.pm.Installer.DEXOPT_GENERATE_COMPACT_DEX; -import static com.android.server.pm.Installer.DEXOPT_GENERATE_APP_IMAGE; -import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; -import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; - -import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT; - -import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName; - -import static dalvik.system.DexFile.getSafeModeCompilerFilter; -import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; - /** * Helper class for running dexopt command on packages. */ @@ -544,8 +542,7 @@ public class PackageDexOptimizer { // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that // the user does not have an existing profile. boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter); - boolean isPublic = !info.isForwardLocked() && - (!isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()); + boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata(); int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; // Some apps are executed with restrictions on hidden API usage. If this app is one // of them, pass a flag to dexopt to enable the same restrictions during compilation. diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 1a5b86cfbce0..2e9a71a178fb 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -455,12 +455,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag"); } - if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0 - || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { - throw new IllegalArgumentException( - "New installs into ASEC containers no longer supported"); - } - // Defensively resize giant app icons if (params.appIcon != null) { final ActivityManager am = (ActivityManager) mContext.getSystemService( @@ -487,21 +481,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements if (!PackageHelper.fitsOnInternal(mContext, params)) { throw new IOException("No suitable internal storage available"); } - - } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { - if (!PackageHelper.fitsOnExternal(mContext, params)) { - throw new IOException("No suitable external storage available"); - } - - } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) { - // For now, installs to adopted media are treated as internal from - // an install flag point-of-view. - params.setInstallFlagsInternal(); - } else { // For now, installs to adopted media are treated as internal from // an install flag point-of-view. - params.setInstallFlagsInternal(); + params.installFlags |= PackageManager.INSTALL_INTERNAL; // Resolve best location for install, based on combination of // requested install flags, delta size, and manifest settings. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index acbd81dab5bc..14682f325940 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -43,7 +43,6 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRAD import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; -import static android.content.pm.PackageManager.INSTALL_EXTERNAL; import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION; @@ -646,9 +645,6 @@ public class PackageManagerService extends IPackageManager.Stub /** Directory where installed application's 32-bit native libraries are copied. */ private static final File sAppLib32InstallDir = new File(Environment.getDataDirectory(), "app-lib"); - /** Directory where code and non-resource assets of forward-locked applications are stored */ - private static final File sDrmAppPrivateInstallDir = - new File(Environment.getDataDirectory(), "app-private"); // ---------------------------------------------------------------- @@ -1811,12 +1807,10 @@ public class PackageManagerService extends IPackageManager.Stub firstUserIds, firstInstantUserIds); } - // Send broadcast package appeared if forward locked/external for all users - // treat asec-hosted packages like removable media on upgrade - if (res.pkg.isForwardLocked() || isExternal(res.pkg)) { + // Send broadcast package appeared if external for all users + if (isExternal(res.pkg)) { if (DEBUG_INSTALL) { - Slog.i(TAG, "upgrading pkg " + res.pkg - + " is ASEC-hosted -> AVAILABLE"); + Slog.i(TAG, "upgrading pkg " + res.pkg + " is external"); } final int[] uidArray = new int[]{res.pkg.applicationInfo.uid}; ArrayList<String> pkgList = new ArrayList<>(1); @@ -2629,10 +2623,6 @@ public class PackageManagerService extends IPackageManager.Stub SystemClock.uptimeMillis()); scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); - scanDirTracedLI(sDrmAppPrivateInstallDir, mDefParseFlags - | PackageParser.PARSE_FORWARD_LOCK, - scanFlags | SCAN_REQUIRE_KNOWN, 0); - // Remove disable package settings for updated system apps that were // removed via an OTA. If the update is no longer present, remove the // app completely. Otherwise, revoke their system privileges. @@ -5407,7 +5397,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mPackages) { Signature[] s1; Signature[] s2; - Object obj = mSettings.getUserIdLPr(uid1); + Object obj = mSettings.getSettingLPr(uid1); if (obj != null) { if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { @@ -5426,7 +5416,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - obj = mSettings.getUserIdLPr(uid2); + obj = mSettings.getSettingLPr(uid2); if (obj != null) { if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { @@ -5485,7 +5475,7 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mPackages) { final PackageParser.SigningDetails signingDetails; - final Object obj = mSettings.getUserIdLPr(uid); + final Object obj = mSettings.getSettingLPr(uid); if (obj != null) { if (obj instanceof SharedUserSetting) { final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; @@ -5598,7 +5588,7 @@ public class PackageManagerService extends IPackageManager.Stub uid = UserHandle.getAppId(uid); // reader synchronized (mPackages) { - Object obj = mSettings.getUserIdLPr(uid); + Object obj = mSettings.getSettingLPr(uid); if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { return null; @@ -5634,7 +5624,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } synchronized (mPackages) { - Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); + Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return sus.name + ":" + sus.userId; @@ -5662,7 +5652,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mPackages) { for (int i = uids.length - 1; i >= 0; i--) { final int uid = uids[i]; - Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); + Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; names[i] = "shared:" + sus.name; @@ -5711,7 +5701,7 @@ public class PackageManagerService extends IPackageManager.Stub return 0; } synchronized (mPackages) { - Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); + Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return sus.pkgFlags; @@ -5733,7 +5723,7 @@ public class PackageManagerService extends IPackageManager.Stub return 0; } synchronized (mPackages) { - Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); + Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return sus.pkgPrivateFlags; @@ -5756,7 +5746,7 @@ public class PackageManagerService extends IPackageManager.Stub uid = UserHandle.getAppId(uid); // reader synchronized (mPackages) { - Object obj = mSettings.getUserIdLPr(uid); + Object obj = mSettings.getSettingLPr(uid); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; final Iterator<PackageSetting> it = sus.packages.iterator(); @@ -6396,7 +6386,7 @@ public class PackageManagerService extends IPackageManager.Stub callingUid = mIsolatedOwners.get(callingUid); } final int appId = UserHandle.getAppId(callingUid); - final Object obj = mSettings.getUserIdLPr(appId); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid)); @@ -8631,7 +8621,7 @@ public class PackageManagerService extends IPackageManager.Stub + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); final InstallArgs args = createInstallArgsForExisting( - packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString, + pkgSetting.codePathString, pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting)); args.cleanUpResourcesLI(); synchronized (mPackages) { @@ -8704,7 +8694,7 @@ public class PackageManagerService extends IPackageManager.Stub + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); InstallArgs args = createInstallArgsForExisting( - packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString, + pkgSetting.codePathString, pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); @@ -8726,7 +8716,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_UPDATE_SIGNATURE, currentTime, user); if (scanResult.success) { synchronized (mPackages) { - commitScanResultLocked(scanResult); + try { + prepareScanResultLocked(scanResult); + commitScanResultLocked(scanResult); + } catch (PackageManagerException e) { + unprepareScanResultLocked(scanResult); + throw e; + } } } @@ -10125,7 +10121,37 @@ public class PackageManagerService extends IPackageManager.Stub } } for (ScanResult result : results) { - commitScanResultLocked(result); + try { + prepareScanResultLocked(result); + commitScanResultLocked(result); + } catch (PackageManagerException e) { + unprepareScanResultLocked(result); + throw e; + } + } + } + } + + /** Prepares the system to commit a {@link ScanResult} in a way that will not fail. */ + private void prepareScanResultLocked(@NonNull ScanResult result) + throws PackageManagerException { + if (!result.existingSettingCopied) { + // THROWS: when we can't allocate a user id. add call to check if there's + // enough space to ensure we won't throw; otherwise, don't modify state + mSettings.registerAppIdLPw(result.pkgSetting); + } + } + + /** + * Reverts any changes to the system that were made by + * {@link #prepareScanResultLocked(ScanResult)} + */ + private void unprepareScanResultLocked(@NonNull ScanResult result) { + if (!result.existingSettingCopied) { + // iff we've acquired an app ID for a new package setting, remove it so that it can be + // acquired by another request. + if (result.pkgSetting.appId > 0) { + mSettings.removeAppIdLPw(result.pkgSetting.appId); } } } @@ -10164,10 +10190,6 @@ public class PackageManagerService extends IPackageManager.Stub if (originalPkgSetting != null) { mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name); } - // THROWS: when we can't allocate a user id. add call to check if there's - // enough space to ensure we won't throw; otherwise, don't modify state - mSettings.addUserToSettingLPw(pkgSetting); - if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) { mTransferedPackages.add(originalPkgSetting.name); } @@ -11536,11 +11558,8 @@ public class PackageManagerService extends IPackageManager.Stub // pass once we've determined ABI below. setNativeLibraryPaths(pkg, sAppLib32InstallDir); - // We would never need to extract libs for forward-locked and external packages, - // since the container service will do it for us. We shouldn't attempt to - // extract libs from system app when it was not updated. - if (pkg.isForwardLocked() || pkg.applicationInfo.isExternalAsec() || - (isSystemApp(pkg) && !pkg.isUpdatedSystemApp())) { + // We shouldn't attempt to extract libs from system app when it was not updated. + if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { extractLibs = false; } @@ -11881,7 +11900,6 @@ public class PackageManagerService extends IPackageManager.Stub final String codePath = pkg.codePath; final File codeFile = new File(codePath); final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp(); - final boolean asecApp = info.isForwardLocked() || info.isExternalAsec(); info.nativeLibraryRootDir = null; info.nativeLibraryRootRequiresIsa = false; @@ -11910,9 +11928,6 @@ public class PackageManagerService extends IPackageManager.Stub info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot), secondaryLibDir, apkName).getAbsolutePath(); } - } else if (asecApp) { - info.nativeLibraryRootDir = new File(codeFile.getParentFile(), LIB_DIR_NAME) - .getAbsolutePath(); } else { final String apkName = deriveCodePathName(codePath); info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName) @@ -13496,7 +13511,7 @@ public class PackageManagerService extends IPackageManager.Stub } Signature[] callerSignature; - Object obj = mSettings.getUserIdLPr(callingUid); + Object obj = mSettings.getSettingLPr(callingUid); if (obj != null) { if (obj instanceof SharedUserSetting) { callerSignature = @@ -14021,7 +14036,6 @@ public class PackageManagerService extends IPackageManager.Stub private int installLocationPolicy(PackageInfoLite pkgLite) { String packageName = pkgLite.packageName; int installLocation = pkgLite.installLocation; - boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; // reader synchronized (mPackages) { // Currently installed package which the new package is attempting to replace or @@ -14074,16 +14088,8 @@ public class PackageManagerService extends IPackageManager.Stub if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { // Check for updated system application. if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - if (onSd) { - Slog.w(TAG, "Cannot install update to system app on sdcard"); - return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION; - } return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } else { - if (onSd) { - // Install flag overrides everything. - return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; - } // If current upgrade specifies particular preference if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { // Application explicitly specified internal. @@ -14104,11 +14110,6 @@ public class PackageManagerService extends IPackageManager.Stub } } } - // All the special cases have been taken care of. - // Return result based on recommended install location. - if (onSd) { - return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; - } return pkgLite.recommendedInstallLocation; } @@ -14125,70 +14126,59 @@ public class PackageManagerService extends IPackageManager.Stub if (origin.staged) { if (origin.file != null) { installFlags |= PackageManager.INSTALL_INTERNAL; - installFlags &= ~PackageManager.INSTALL_EXTERNAL; } else { throw new IllegalStateException("Invalid stage location"); } } - final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; PackageInfoLite pkgLite = null; - if (onInt && onSd) { - // Check if both bits are set. - Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); - ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; - } else if (onSd && ephemeral) { - Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external"); - ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; - } else { - pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, - origin.resolvedPath, installFlags, packageAbiOverride); - if (DEBUG_INSTANT && ephemeral) { - Slog.v(TAG, "pkgLite for install: " + pkgLite); + pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, + origin.resolvedPath, installFlags, packageAbiOverride); + + if (DEBUG_INSTANT && ephemeral) { + Slog.v(TAG, "pkgLite for install: " + pkgLite); + } + + /* + * If we have too little free space, try to free cache + * before giving up. + */ + if (!origin.staged && pkgLite.recommendedInstallLocation + == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { + // TODO: focus freeing disk space on the target device + final StorageManager storage = StorageManager.from(mContext); + final long lowThreshold = storage.getStorageLowBytes( + Environment.getDataDirectory()); + + final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize( + origin.resolvedPath, packageAbiOverride); + if (sizeBytes >= 0) { + try { + mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0); + pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, + origin.resolvedPath, installFlags, packageAbiOverride); + } catch (InstallerException e) { + Slog.w(TAG, "Failed to free cache", e); + } } /* - * If we have too little free space, try to free cache - * before giving up. + * The cache free must have deleted the file we downloaded to install. + * + * TODO: fix the "freeCache" call to not delete the file we care about. */ - if (!origin.staged && pkgLite.recommendedInstallLocation - == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { - // TODO: focus freeing disk space on the target device - final StorageManager storage = StorageManager.from(mContext); - final long lowThreshold = storage.getStorageLowBytes( - Environment.getDataDirectory()); - - final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize( - origin.resolvedPath, packageAbiOverride); - if (sizeBytes >= 0) { - try { - mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0); - pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, - origin.resolvedPath, installFlags, packageAbiOverride); - } catch (InstallerException e) { - Slog.w(TAG, "Failed to free cache", e); - } - } - - /* - * The cache free must have deleted the file we - * downloaded to install. - * - * TODO: fix the "freeCache" call to not delete - * the file we care about. - */ - if (pkgLite.recommendedInstallLocation - == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { - pkgLite.recommendedInstallLocation + if (pkgLite.recommendedInstallLocation + == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { + pkgLite.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; - } } } + if (ret == PackageManager.INSTALL_SUCCEEDED) { int loc = pkgLite.recommendedInstallLocation; if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { @@ -14208,24 +14198,21 @@ public class PackageManagerService extends IPackageManager.Stub loc = installLocationPolicy(pkgLite); if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) { ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE; - } else if (!onSd && !onInt) { + } else if (!onInt) { // Override install location with flags if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { // Set the flag to install on external media. - installFlags |= PackageManager.INSTALL_EXTERNAL; installFlags &= ~PackageManager.INSTALL_INTERNAL; } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) { if (DEBUG_INSTANT) { Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag"); } installFlags |= PackageManager.INSTALL_INSTANT_APP; - installFlags &= ~(PackageManager.INSTALL_EXTERNAL - |PackageManager.INSTALL_INTERNAL); + installFlags &= ~PackageManager.INSTALL_INTERNAL; } else { // Make sure the flag for installing on external // media is unset installFlags |= PackageManager.INSTALL_INTERNAL; - installFlags &= ~PackageManager.INSTALL_EXTERNAL; } } } @@ -14409,7 +14396,7 @@ public class PackageManagerService extends IPackageManager.Stub * Create args that describe an existing installed package. Typically used * when cleaning up old installs, or used as a move source. */ - private InstallArgs createInstallArgsForExisting(int installFlags, String codePath, + private InstallArgs createInstallArgsForExisting(String codePath, String resourcePath, String[] instructionSets) { return new FileInstallArgs(codePath, resourcePath, instructionSets); } @@ -14501,14 +14488,6 @@ public class PackageManagerService extends IPackageManager.Stub return PackageManager.INSTALL_SUCCEEDED; } - protected boolean isFwdLocked() { - return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0; - } - - protected boolean isExternalAsec() { - return (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; - } - protected boolean isEphemeral() { return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; } @@ -14536,7 +14515,7 @@ public class PackageManagerService extends IPackageManager.Stub } /** - * Logic to handle installation of non-ASEC applications, including copying + * Logic to handle installation of new applications, including copying * and renaming logic. */ class FileInstallArgs extends InstallArgs { @@ -14558,9 +14537,6 @@ public class PackageManagerService extends IPackageManager.Stub params.grantedRuntimePermissions, params.traceMethod, params.traceCookie, params.signingDetails, params.installReason, params.mParentInstallParams); - if (isFwdLocked()) { - throw new IllegalArgumentException("Forward locking only supported in ASEC"); - } } /** Existing install */ @@ -15291,7 +15267,7 @@ public class PackageManagerService extends IPackageManager.Stub // We didn't need to disable the .apk as a current system package, // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. - res.removedInfo.args = createInstallArgsForExisting(0, + res.removedInfo.args = createInstallArgsForExisting( oldPackage.applicationInfo.getCodePath(), oldPackage.applicationInfo.getResourcePath(), getAppDexInstructionSets(oldPackage.applicationInfo)); @@ -15414,8 +15390,10 @@ public class PackageManagerService extends IPackageManager.Stub try { + prepareScanResultLocked(scanResult); commitScanResultLocked(scanResult); } catch (PackageManagerException e) { + unprepareScanResultLocked(scanResult); res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR); res.setError("Package couldn't be installed in " + pkg.codePath, e); return false; @@ -15570,8 +15548,6 @@ public class PackageManagerService extends IPackageManager.Stub */ private void executePostCommitSteps(CommitRequest commitRequest) { for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { - final boolean forwardLocked = - ((reconciledPkg.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0); final boolean instantApp = ((reconciledPkg.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0); final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg; @@ -15604,10 +15580,8 @@ public class PackageManagerService extends IPackageManager.Stub // This update happens in place! // // We only need to dexopt if the package meets ALL of the following conditions: - // 1) it is not forward locked. - // 2) it is not on on an external ASEC container. - // 3) it is not an instant app or if it is then dexopt is enabled via gservices. - // 4) it is not debuggable. + // 1) it is not an instant app or if it is then dexopt is enabled via gservices. + // 2) it is not debuggable. // // Note that we do not dexopt instant apps by default. dexopt can take some time to // complete, so we skip this step during installation. Instead, we'll take extra time @@ -15615,9 +15589,8 @@ public class PackageManagerService extends IPackageManager.Stub // continuous progress to the useur instead of mysteriously blocking somewhere in the // middle of running an instant app. The default behaviour can be overridden // via gservices. - final boolean performDexopt = !forwardLocked - && !pkg.applicationInfo.isExternalAsec() - && (!instantApp || Global.getInt(mContext.getContentResolver(), + final boolean performDexopt = + (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0); @@ -15712,7 +15685,6 @@ public class PackageManagerService extends IPackageManager.Stub // Parse old package boolean oldExternal = isExternal(oldPackage); int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY - | (oldPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) | (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME; try { @@ -15830,9 +15802,7 @@ public class PackageManagerService extends IPackageManager.Stub final String installerPackageName = args.installerPackageName; final String volumeUuid = args.volumeUuid; final File tmpPackageFile = new File(args.getCodePath()); - final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0); - final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0) - || (args.volumeUuid != null)); + final boolean onExternal = args.volumeUuid != null; final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0); final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0); final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0); @@ -15859,16 +15829,14 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile); // Sanity check - if (instantApp && (forwardLocked || onExternal)) { - Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked - + " external=" + onExternal); + if (instantApp && onExternal) { + Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal); throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID); } // Retrieve PackageSettings and parse package @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE - | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0) | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0); @@ -16213,7 +16181,7 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString; } - } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) { + } else { // Enable SCAN_NO_DEX flag to skip dexopt at a later stage scanFlags |= SCAN_NO_DEX; @@ -16745,19 +16713,6 @@ public class PackageManagerService extends IPackageManager.Stub return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } - private int packageFlagsToInstallFlags(PackageSetting ps) { - int installFlags = 0; - if (isExternal(ps) && TextUtils.isEmpty(ps.volumeUuid)) { - // This existing package was an external ASEC install when we have - // the external flag without a UUID - installFlags |= PackageManager.INSTALL_EXTERNAL; - } - if (ps.isForwardLocked()) { - installFlags |= PackageManager.INSTALL_FORWARD_LOCK; - } - return installFlags; - } - private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) { if (isExternal(pkg)) { if (TextUtils.isEmpty(pkg.volumeUuid)) { @@ -16773,9 +16728,6 @@ public class PackageManagerService extends IPackageManager.Stub private void deleteTempPackageFiles() { final FilenameFilter filter = (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp"); - for (File file : sDrmAppPrivateInstallDir.listFiles(filter)) { - file.delete(); - } } @Override @@ -17766,7 +17718,7 @@ public class PackageManagerService extends IPackageManager.Stub // Delete application code and resources only for parent packages if (ps.parentPackageName == null) { if (deleteCodeAndResources && (outInfo != null)) { - outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), + outInfo.args = createInstallArgsForExisting( ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps)); if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); } @@ -18477,7 +18429,7 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mPackages") private int getUidTargetSdkVersionLockedLPr(int uid) { - Object obj = mSettings.getUserIdLPr(uid); + Object obj = mSettings.getSettingLPr(uid); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; int vers = Build.VERSION_CODES.CUR_DEVELOPMENT; @@ -21698,7 +21650,6 @@ public class PackageManagerService extends IPackageManager.Stub final StorageManager storage = mContext.getSystemService(StorageManager.class); final PackageManager pm = mContext.getPackageManager(); - final boolean currentAsec; final String currentVolumeUuid; final File codeFile; final String installerPackageName; @@ -21732,22 +21683,13 @@ public class PackageManagerService extends IPackageManager.Stub "3rd party apps are not allowed on internal storage"); } - if (pkg.applicationInfo.isExternalAsec()) { - currentAsec = true; - currentVolumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL; - } else if (pkg.applicationInfo.isForwardLocked()) { - currentAsec = true; - currentVolumeUuid = "forward_locked"; - } else { - currentAsec = false; - currentVolumeUuid = ps.volumeUuid; + currentVolumeUuid = ps.volumeUuid; - final File probe = new File(pkg.codePath); - final File probeOat = new File(probe, "oat"); - if (!probe.isDirectory() || !probeOat.isDirectory()) { - throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, - "Move only supported for modern cluster style installs"); - } + final File probe = new File(pkg.codePath); + final File probeOat = new File(probe, "oat"); + if (!probe.isDirectory() || !probeOat.isDirectory()) { + throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, + "Move only supported for modern cluster style installs"); } if (Objects.equals(currentVolumeUuid, volumeUuid)) { @@ -21784,12 +21726,11 @@ public class PackageManagerService extends IPackageManager.Stub final boolean moveCompleteApp; final File measurePath; + installFlags = INSTALL_INTERNAL; if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { - installFlags = INSTALL_INTERNAL; - moveCompleteApp = !currentAsec; + moveCompleteApp = true; measurePath = Environment.getDataAppDirectory(volumeUuid); } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { - installFlags = INSTALL_EXTERNAL; moveCompleteApp = false; measurePath = storage.getPrimaryPhysicalVolume().getPath(); } else { @@ -21801,9 +21742,6 @@ public class PackageManagerService extends IPackageManager.Stub "Move location not mounted private volume"); } - Preconditions.checkState(!currentAsec); - - installFlags = INSTALL_INTERNAL; moveCompleteApp = true; measurePath = Environment.getDataAppDirectory(volumeUuid); } @@ -22588,7 +22526,7 @@ public class PackageManagerService extends IPackageManager.Stub private SigningDetails getSigningDetails(int uid) { synchronized (mPackages) { final int appId = UserHandle.getAppId(uid); - final Object obj = mSettings.getUserIdLPr(appId); + final Object obj = mSettings.getSettingLPr(appId); if (obj != null) { if (obj instanceof SharedUserSetting) { return ((SharedUserSetting) obj).signatures.mSigningDetails; diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 6f275ece1a1f..77f8c3a0308a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2193,9 +2193,6 @@ class PackageManagerShellCommand extends ShellCommand { boolean replaceExisting = true; while ((opt = getNextOption()) != null) { switch (opt) { - case "-l": - sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK; - break; case "-r": // ignore break; case "-R": @@ -2210,9 +2207,6 @@ class PackageManagerShellCommand extends ShellCommand { case "-t": sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST; break; - case "-s": - sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL; - break; case "-f": sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL; break; diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index b8506136d071..2c2cc7ea78f9 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -152,10 +152,6 @@ public final class PackageSetting extends PackageSettingBase { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; } - public boolean isForwardLocked() { - return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; - } - public boolean isSystem() { return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index 239dc995532a..fbf54391209c 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -64,7 +64,6 @@ abstract class SettingBase { | ApplicationInfo.PRIVATE_FLAG_VENDOR | ApplicationInfo.PRIVATE_FLAG_PRODUCT | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES - | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6009bd3e2c82..9e5a4c6a9888 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -381,11 +381,9 @@ public final class Settings { final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers = new SparseArray<CrossProfileIntentResolver>(); - final ArrayMap<String, SharedUserSetting> mSharedUsers = - new ArrayMap<String, SharedUserSetting>(); - private final ArrayList<Object> mUserIds = new ArrayList<Object>(); - private final SparseArray<Object> mOtherUserIds = - new SparseArray<Object>(); + final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>(); + private final ArrayList<SettingBase> mAppIds = new ArrayList<>(); + private final SparseArray<SettingBase> mOtherAppIds = new SparseArray<>(); // For reading/writing settings file. private final ArrayList<Signature> mPastSignatures = @@ -519,7 +517,7 @@ public final class Settings { SharedUserSetting s = mSharedUsers.get(name); if (s == null && create) { s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags); - s.userId = newUserIdLPw(s); + s.userId = acquireAndRegisterNewAppIdLPw(s); if (s.userId < 0) { // < 0 means we couldn't assign a userid; throw exception throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, @@ -612,7 +610,7 @@ public final class Settings { cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName, childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames); p.appId = uid; - if (addUserIdLPw(uid, p, name)) { + if (registerExistingAppIdLPw(uid, p, name)) { mPackages.put(name, p); return p; } @@ -635,7 +633,7 @@ public final class Settings { } s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags); s.userId = uid; - if (addUserIdLPw(uid, s, name)) { + if (registerExistingAppIdLPw(uid, s, name)) { mSharedUsers.put(name, s); return s; } @@ -885,13 +883,13 @@ public final class Settings { * Registers a user ID with the system. Potentially allocates a new user ID. * @throws PackageManagerException If a user ID could not be allocated. */ - void addUserToSettingLPw(PackageSetting p) throws PackageManagerException { + void registerAppIdLPw(PackageSetting p) throws PackageManagerException { if (p.appId == 0) { // Assign new user ID - p.appId = newUserIdLPw(p); + p.appId = acquireAndRegisterNewAppIdLPw(p); } else { // Add new setting to list of user IDs - addUserIdLPw(p.appId, p, p.name); + registerExistingAppIdLPw(p.appId, p, p.name); } if (p.appId < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, @@ -972,14 +970,14 @@ public final class Settings { // If the we know about this user id, we have to update it as it // has to point to the same PackageSetting instance as the package. - Object userIdPs = getUserIdLPr(p.appId); + Object userIdPs = getSettingLPr(p.appId); if (sharedUser == null) { if (userIdPs != null && userIdPs != p) { - replaceUserIdLPw(p.appId, p); + replaceAppIdLPw(p.appId, p); } } else { if (userIdPs != null && userIdPs != sharedUser) { - replaceUserIdLPw(p.appId, sharedUser); + replaceAppIdLPw(p.appId, sharedUser); } } @@ -1083,11 +1081,11 @@ public final class Settings { p.sharedUser.removePackage(p); if (p.sharedUser.packages.size() == 0) { mSharedUsers.remove(p.sharedUser.name); - removeUserIdLPw(p.sharedUser.userId); + removeAppIdLPw(p.sharedUser.userId); return p.sharedUser.userId; } } else { - removeUserIdLPw(p.appId); + removeAppIdLPw(p.appId); return p.appId; } } @@ -1115,65 +1113,69 @@ public final class Settings { mInstallerPackages.remove(packageName); } - private boolean addUserIdLPw(int uid, Object obj, Object name) { - if (uid > Process.LAST_APPLICATION_UID) { + /** Returns true if the requested AppID was valid and not already registered. */ + private boolean registerExistingAppIdLPw(int appId, SettingBase obj, Object name) { + if (appId > Process.LAST_APPLICATION_UID) { return false; } - if (uid >= Process.FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - Process.FIRST_APPLICATION_UID; - while (index >= N) { - mUserIds.add(null); - N++; + if (appId >= Process.FIRST_APPLICATION_UID) { + int size = mAppIds.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + // fill the array until our index becomes valid + while (index >= size) { + mAppIds.add(null); + size++; } - if (mUserIds.get(index) != null) { + if (mAppIds.get(index) != null) { PackageManagerService.reportSettingsProblem(Log.ERROR, - "Adding duplicate user id: " + uid + "Adding duplicate app id: " + appId + " name=" + name); return false; } - mUserIds.set(index, obj); + mAppIds.set(index, obj); } else { - if (mOtherUserIds.get(uid) != null) { + if (mOtherAppIds.get(appId) != null) { PackageManagerService.reportSettingsProblem(Log.ERROR, - "Adding duplicate shared id: " + uid + "Adding duplicate shared id: " + appId + " name=" + name); return false; } - mOtherUserIds.put(uid, obj); + mOtherAppIds.put(appId, obj); } return true; } - public Object getUserIdLPr(int uid) { - if (uid >= Process.FIRST_APPLICATION_UID) { - final int N = mUserIds.size(); - final int index = uid - Process.FIRST_APPLICATION_UID; - return index < N ? mUserIds.get(index) : null; + /** Gets the setting associated with the provided App ID */ + public SettingBase getSettingLPr(int appId) { + if (appId >= Process.FIRST_APPLICATION_UID) { + final int size = mAppIds.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + return index < size ? mAppIds.get(index) : null; } else { - return mOtherUserIds.get(uid); + return mOtherAppIds.get(appId); } } - private void removeUserIdLPw(int uid) { - if (uid >= Process.FIRST_APPLICATION_UID) { - final int N = mUserIds.size(); - final int index = uid - Process.FIRST_APPLICATION_UID; - if (index < N) mUserIds.set(index, null); + /** Unregisters the provided app ID. */ + void removeAppIdLPw(int appId) { + if (appId >= Process.FIRST_APPLICATION_UID) { + final int size = mAppIds.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + if (index < size) mAppIds.set(index, null); } else { - mOtherUserIds.remove(uid); + mOtherAppIds.remove(appId); } - setFirstAvailableUid(uid+1); + setFirstAvailableUid(appId + 1); } - private void replaceUserIdLPw(int uid, Object obj) { - if (uid >= Process.FIRST_APPLICATION_UID) { - final int N = mUserIds.size(); - final int index = uid - Process.FIRST_APPLICATION_UID; - if (index < N) mUserIds.set(index, obj); + private void replaceAppIdLPw(int appId, SettingBase obj) { + if (appId >= Process.FIRST_APPLICATION_UID) { + final int size = mAppIds.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + if (index < size) mAppIds.set(index, obj); } else { - mOtherUserIds.put(uid, obj); + mOtherAppIds.put(appId, obj); } } @@ -3157,7 +3159,7 @@ public final class Settings { for (int i = 0; i < N; i++) { final PackageSetting p = mPendingPackages.get(i); final int sharedUserId = p.getSharedUserId(); - final Object idObj = getUserIdLPr(sharedUserId); + final Object idObj = getSettingLPr(sharedUserId); if (idObj instanceof SharedUserSetting) { final SharedUserSetting sharedUser = (SharedUserSetting) idObj; p.sharedUser = sharedUser; @@ -3202,7 +3204,7 @@ public final class Settings { final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator(); while (disabledIt.hasNext()) { final PackageSetting disabledPs = disabledIt.next(); - final Object id = getUserIdLPr(disabledPs.appId); + final Object id = getSettingLPr(disabledPs.appId); if (id != null && id instanceof SharedUserSetting) { disabledPs.sharedUser = (SharedUserSetting) id; } @@ -3656,7 +3658,6 @@ public final class Settings { private static int PRE_M_APP_INFO_FLAG_HIDDEN = 1<<27; private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28; - private static int PRE_M_APP_INFO_FLAG_FORWARD_LOCK = 1<<29; private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30; private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException { @@ -3756,15 +3757,11 @@ public final class Settings { if ((pkgFlags & PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE) != 0) { pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; } - if ((pkgFlags & PRE_M_APP_INFO_FLAG_FORWARD_LOCK) != 0) { - pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK; - } if ((pkgFlags & PRE_M_APP_INFO_FLAG_PRIVILEGED) != 0) { pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; } pkgFlags &= ~(PRE_M_APP_INFO_FLAG_HIDDEN | PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE - | PRE_M_APP_INFO_FLAG_FORWARD_LOCK | PRE_M_APP_INFO_FLAG_PRIVILEGED); } else { // For backward compatibility @@ -4206,24 +4203,24 @@ public final class Settings { } } - // Returns -1 if we could not find an available UserId to assign - private int newUserIdLPw(Object obj) { + /** Returns a new AppID or -1 if we could not find an available AppID to assign */ + private int acquireAndRegisterNewAppIdLPw(SettingBase obj) { // Let's be stupidly inefficient for now... - final int N = mUserIds.size(); - for (int i = mFirstAvailableUid; i < N; i++) { - if (mUserIds.get(i) == null) { - mUserIds.set(i, obj); + final int size = mAppIds.size(); + for (int i = mFirstAvailableUid; i < size; i++) { + if (mAppIds.get(i) == null) { + mAppIds.set(i, obj); return Process.FIRST_APPLICATION_UID + i; } } // None left? - if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) { + if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) { return -1; } - mUserIds.add(obj); - return Process.FIRST_APPLICATION_UID + N; + mAppIds.add(obj); + return Process.FIRST_APPLICATION_UID + size; } public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() { @@ -4428,7 +4425,6 @@ public final class Settings { ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE", ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE", ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE, "DIRECT_BOOT_AWARE", - ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK", ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS, "HAS_DOMAIN_URLS", ApplicationInfo.PRIVATE_FLAG_HIDDEN, "HIDDEN", ApplicationInfo.PRIVATE_FLAG_INSTANT, "EPHEMERAL", diff --git a/services/core/java/com/android/server/pm/ShareTargetInfo.java b/services/core/java/com/android/server/pm/ShareTargetInfo.java new file mode 100644 index 000000000000..9e8b73e36f69 --- /dev/null +++ b/services/core/java/com/android/server/pm/ShareTargetInfo.java @@ -0,0 +1,101 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.pm; + +import android.text.TextUtils; + +/** + * Represents a Share Target definition, read from the application's manifest (shortcuts.xml) + */ +class ShareTargetInfo { + static class TargetData { + final String mScheme; + final String mHost; + final String mPort; + final String mPath; + final String mPathPattern; + final String mPathPrefix; + final String mMimeType; + + TargetData(String scheme, String host, String port, String path, String pathPattern, + String pathPrefix, String mimeType) { + mScheme = scheme; + mHost = host; + mPort = port; + mPath = path; + mPathPattern = pathPattern; + mPathPrefix = pathPrefix; + mMimeType = mimeType; + } + + public void toStringInner(StringBuilder strBuilder) { + if (!TextUtils.isEmpty(mScheme)) { + strBuilder.append(" scheme=").append(mScheme); + } + if (!TextUtils.isEmpty(mHost)) { + strBuilder.append(" host=").append(mHost); + } + if (!TextUtils.isEmpty(mPort)) { + strBuilder.append(" port=").append(mPort); + } + if (!TextUtils.isEmpty(mPath)) { + strBuilder.append(" path=").append(mPath); + } + if (!TextUtils.isEmpty(mPathPattern)) { + strBuilder.append(" pathPattern=").append(mPathPattern); + } + if (!TextUtils.isEmpty(mPathPrefix)) { + strBuilder.append(" pathPrefix=").append(mPathPrefix); + } + if (!TextUtils.isEmpty(mMimeType)) { + strBuilder.append(" mimeType=").append(mMimeType); + } + } + + @Override + public String toString() { + StringBuilder strBuilder = new StringBuilder(); + toStringInner(strBuilder); + return strBuilder.toString(); + } + } + + final TargetData[] mTargetData; + final String mTargetClass; + final String[] mCategories; + + ShareTargetInfo(TargetData[] data, String targetClass, String[] categories) { + mTargetData = data; + mTargetClass = targetClass; + mCategories = categories; + } + + @Override + public String toString() { + StringBuilder strBuilder = new StringBuilder(); + strBuilder.append("targetClass=").append(mTargetClass); + for (int i = 0; i < mTargetData.length; i++) { + strBuilder.append(" data={"); + mTargetData[i].toStringInner(strBuilder); + strBuilder.append("}"); + } + for (int i = 0; i < mCategories.length; i++) { + strBuilder.append(" category=").append(mCategories[i]); + } + + return strBuilder.toString(); + } +} diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 92e261a72617..83f0fde066ec 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -111,6 +111,11 @@ class ShortcutPackage extends ShortcutPackageItem { final private ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>(); /** + * All the share targets from the package + */ + private final ArrayList<ShareTargetInfo> mShareTargets = new ArrayList<>(0); + + /** * # of times the package has called rate-limited APIs. */ private int mApiCallCount; @@ -739,15 +744,16 @@ class ShortcutPackage extends ShortcutPackageItem { List<ShortcutInfo> newManifestShortcutList = null; try { newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService, - getPackageName(), getPackageUserId()); + getPackageName(), getPackageUserId(), mShareTargets); } catch (IOException|XmlPullParserException e) { Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e); } final int manifestShortcutSize = newManifestShortcutList == null ? 0 : newManifestShortcutList.size(); if (ShortcutService.DEBUG) { - Slog.d(TAG, String.format("Package %s has %d manifest shortcut(s)", - getPackageName(), manifestShortcutSize)); + Slog.d(TAG, + String.format("Package %s has %d manifest shortcut(s), and %d share target(s)", + getPackageName(), manifestShortcutSize, mShareTargets.size())); } if (isNewApp && (manifestShortcutSize == 0)) { // If it's a new app, and it doesn't have manifest shortcuts, then nothing to do. @@ -1657,6 +1663,11 @@ class ShortcutPackage extends ShortcutPackageItem { return new ArrayList<>(mShortcuts.values()); } + @VisibleForTesting + List<ShareTargetInfo> getAllShareTargetsForTest() { + return new ArrayList<>(mShareTargets); + } + @Override public void verifyStates() { super.verifyStates(); diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java index 866c46c643ee..90f08c30139a 100644 --- a/services/core/java/com/android/server/pm/ShortcutParser.java +++ b/services/core/java/com/android/server/pm/ShortcutParser.java @@ -15,6 +15,7 @@ */ package com.android.server.pm; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; @@ -55,10 +56,14 @@ public class ShortcutParser { private static final String TAG_SHORTCUT = "shortcut"; private static final String TAG_INTENT = "intent"; private static final String TAG_CATEGORIES = "categories"; + private static final String TAG_SHARE_TARGET = "share-target"; + private static final String TAG_DATA = "data"; + private static final String TAG_CATEGORY = "category"; @Nullable - public static List<ShortcutInfo> parseShortcuts(ShortcutService service, - String packageName, @UserIdInt int userId) throws IOException, XmlPullParserException { + public static List<ShortcutInfo> parseShortcuts(ShortcutService service, String packageName, + @UserIdInt int userId, @NonNull List<ShareTargetInfo> outShareTargets) + throws IOException, XmlPullParserException { if (ShortcutService.DEBUG) { Slog.d(TAG, String.format("Scanning package %s for manifest shortcuts on user %d", packageName, userId)); @@ -69,6 +74,7 @@ public class ShortcutParser { } List<ShortcutInfo> result = null; + outShareTargets.clear(); try { final int size = activities.size(); @@ -82,8 +88,8 @@ public class ShortcutParser { service.getActivityInfoWithMetadata( activityInfoNoMetadata.getComponentName(), userId); if (activityInfoWithMetadata != null) { - result = parseShortcutsOneFile( - service, activityInfoWithMetadata, packageName, userId, result); + result = parseShortcutsOneFile(service, activityInfoWithMetadata, packageName, + userId, result, outShareTargets); } } } catch (RuntimeException e) { @@ -99,7 +105,8 @@ public class ShortcutParser { private static List<ShortcutInfo> parseShortcutsOneFile( ShortcutService service, ActivityInfo activityInfo, String packageName, @UserIdInt int userId, - List<ShortcutInfo> result) throws IOException, XmlPullParserException { + List<ShortcutInfo> result, @NonNull List<ShareTargetInfo> outShareTargets) + throws IOException, XmlPullParserException { if (ShortcutService.DEBUG) { Slog.d(TAG, String.format( "Checking main activity %s", activityInfo.getComponentName())); @@ -126,9 +133,19 @@ public class ShortcutParser { // after parsing <intent>. We keep the current one in here. ShortcutInfo currentShortcut = null; + // We instantiate ShareTargetInfo at <share-target>, but add it to outShareTargets at + // </share-target>, after parsing <data> and <category>. We keep the current one here. + ShareTargetInfo currentShareTarget = null; + + // Keeps parsed categories for both ShortcutInfo and ShareTargetInfo Set<String> categories = null; + + // Keeps parsed intents for ShortcutInfo final ArrayList<Intent> intents = new ArrayList<>(); + // Keeps parsed data fields for ShareTargetInfo + final ArrayList<ShareTargetInfo.TargetData> dataList = new ArrayList<>(); + outer: while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > 0)) { @@ -194,6 +211,32 @@ public class ShortcutParser { continue; } + // When a share-target tag is closing, publish. + if ((type == XmlPullParser.END_TAG) && (depth == 2) + && (TAG_SHARE_TARGET.equals(tag))) { + if (currentShareTarget == null) { + // ShareTarget was invalid. + continue; + } + final ShareTargetInfo sti = currentShareTarget; + currentShareTarget = null; // Make sure to null out for the next iteration. + + if (categories == null || categories.isEmpty() || dataList.isEmpty()) { + // Incomplete ShareTargetInfo. + continue; + } + + final ShareTargetInfo newShareTarget = new ShareTargetInfo( + dataList.toArray(new ShareTargetInfo.TargetData[dataList.size()]), + sti.mTargetClass, categories.toArray(new String[categories.size()])); + outShareTargets.add(newShareTarget); + if (ShortcutService.DEBUG) { + Slog.d(TAG, "ShareTarget added: " + newShareTarget.toString()); + } + categories = null; + dataList.clear(); + } + // Otherwise, just look at start tags. if (type != XmlPullParser.START_TAG) { continue; @@ -224,6 +267,17 @@ public class ShortcutParser { categories = null; continue; } + if (depth == 2 && TAG_SHARE_TARGET.equals(tag)) { + final ShareTargetInfo sti = parseShareTargetAttributes(service, attrs); + if (sti == null) { + // ShareTarget was invalid. + continue; + } + currentShareTarget = sti; + categories = null; + dataList.clear(); + continue; + } if (depth == 3 && TAG_INTENT.equals(tag)) { if ((currentShortcut == null) || !currentShortcut.isEnabled()) { @@ -258,6 +312,34 @@ public class ShortcutParser { categories.add(name); continue; } + if (depth == 3 && TAG_CATEGORY.equals(tag)) { + if ((currentShareTarget == null)) { + continue; + } + final String name = parseCategory(service, attrs); + if (TextUtils.isEmpty(name)) { + Log.e(TAG, "Empty category found. activity=" + activity); + continue; + } + + if (categories == null) { + categories = new ArraySet<>(); + } + categories.add(name); + continue; + } + if (depth == 3 && TAG_DATA.equals(tag)) { + if ((currentShareTarget == null)) { + continue; + } + final ShareTargetInfo.TargetData data = parseShareTargetData(service, attrs); + if (data == null) { + Log.e(TAG, "Invalid data tag found. activity=" + activity); + continue; + } + dataList.add(data); + continue; + } Log.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth)); } @@ -369,4 +451,57 @@ public class ShortcutParser { null, // bitmap path disabledReason); } + + private static String parseCategory(ShortcutService service, AttributeSet attrs) { + final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs, + R.styleable.IntentCategory); + try { + if (sa.getType(R.styleable.IntentCategory_name) != TypedValue.TYPE_STRING) { + Log.w(TAG, "android:name must be string literal."); + return null; + } + return sa.getString(R.styleable.IntentCategory_name); + } finally { + sa.recycle(); + } + } + + private static ShareTargetInfo parseShareTargetAttributes(ShortcutService service, + AttributeSet attrs) { + final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs, + R.styleable.Intent); + try { + String targetClass = sa.getString(R.styleable.Intent_targetClass); + if (TextUtils.isEmpty(targetClass)) { + Log.w(TAG, "android:targetClass must be provided."); + return null; + } + return new ShareTargetInfo(null, targetClass, null); + } finally { + sa.recycle(); + } + } + + private static ShareTargetInfo.TargetData parseShareTargetData(ShortcutService service, + AttributeSet attrs) { + final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs, + R.styleable.AndroidManifestData); + try { + if (sa.getType(R.styleable.AndroidManifestData_mimeType) != TypedValue.TYPE_STRING) { + Log.w(TAG, "android:mimeType must be string literal."); + return null; + } + String scheme = sa.getString(R.styleable.AndroidManifestData_scheme); + String host = sa.getString(R.styleable.AndroidManifestData_host); + String port = sa.getString(R.styleable.AndroidManifestData_port); + String path = sa.getString(R.styleable.AndroidManifestData_path); + String pathPattern = sa.getString(R.styleable.AndroidManifestData_pathPattern); + String pathPrefix = sa.getString(R.styleable.AndroidManifestData_pathPrefix); + String mimeType = sa.getString(R.styleable.AndroidManifestData_mimeType); + return new ShareTargetInfo.TargetData(scheme, host, port, path, pathPattern, pathPrefix, + mimeType); + } finally { + sa.recycle(); + } + } } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index b9c304890420..2b773f47e3e9 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -41,8 +41,8 @@ import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.ShortcutQuery; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; @@ -98,8 +98,8 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; -import com.android.server.LocalServices; import com.android.internal.util.StatLogger; +import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.ShortcutUser.PackageWithUser; @@ -1172,7 +1172,7 @@ public class ShortcutService extends IShortcutService.Stub { return true; } } - + // If the local copy says the user is locked, check with AM for the actual state, since // the user might just have been unlocked. // Note we just don't use isUserUnlockingOrUnlocked() here, because it'll return false diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index 505e4ee60529..1fd9b69e521d 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -294,13 +294,14 @@ class ShortcutUser { */ public void detectLocaleChange() { final String currentLocales = mService.injectGetLocaleTagsForUser(mUserId); - if (getKnownLocales().equals(currentLocales)) { + if (!TextUtils.isEmpty(mKnownLocales) && mKnownLocales.equals(currentLocales)) { return; } if (ShortcutService.DEBUG) { - Slog.d(TAG, "Locale changed from " + currentLocales + " to " + mKnownLocales + Slog.d(TAG, "Locale changed from " + mKnownLocales + " to " + currentLocales + " for user " + mUserId); } + mKnownLocales = currentLocales; forAllPackages(pkg -> { diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 774134c994b3..21cc14e20bc7 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -195,7 +195,6 @@ public final class DefaultPermissionGrantPolicy { // STOPSHIP(b/112545973): remove once feature enabled by default if (SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)) { MEDIA_AURAL_PERMISSIONS.add(Manifest.permission.READ_MEDIA_AUDIO); - MEDIA_AURAL_PERMISSIONS.add(Manifest.permission.WRITE_MEDIA_AUDIO); } } @@ -203,10 +202,8 @@ public final class DefaultPermissionGrantPolicy { static { // STOPSHIP(b/112545973): remove once feature enabled by default if (SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)) { - MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.READ_MEDIA_IMAGES); - MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.WRITE_MEDIA_IMAGES); MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.READ_MEDIA_VIDEO); - MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.WRITE_MEDIA_VIDEO); + MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.READ_MEDIA_IMAGES); } } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 3179ce90a6f9..aa11e1e3285c 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -51,6 +51,7 @@ import android.net.wifi.WifiActivityEnergyInfo; import android.os.BatteryStats; import android.os.BatteryStatsInternal; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; @@ -1517,6 +1518,21 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } + private void pullBuildInformation(int tagId, + long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeString(Build.FINGERPRINT); + e.writeString(Build.BRAND); + e.writeString(Build.PRODUCT); + e.writeString(Build.DEVICE); + e.writeString(Build.VERSION.RELEASE); + e.writeString(Build.ID); + e.writeString(Build.VERSION.INCREMENTAL); + e.writeString(Build.TYPE); + e.writeString(Build.TAGS); + pulledData.add(e); + } + private BatteryStatsHelper getBatteryStatsHelper() { if (mBatteryStatsHelper == null) { final long callingToken = Binder.clearCallingIdentity(); @@ -1810,6 +1826,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.BUILD_INFORMATION: { + pullBuildInformation(tagId, elapsedNanos, wallClockNanos, ret); + break; + } case StatsLog.PROCESS_CPU_TIME: { pullProcessCpuTime(tagId, elapsedNanos, wallClockNanos, ret); break; diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 1eb44a058d61..361622fd2934 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1177,12 +1177,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void onNotificationSmartReplySent(String key, int replyIndex) + public void onNotificationSmartReplySent( + String key, int replyIndex, CharSequence reply, boolean generatedByAssistant) throws RemoteException { enforceStatusBarService(); long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onNotificationSmartReplySent(key, replyIndex); + mNotificationDelegate.onNotificationSmartReplySent(key, replyIndex, reply, + generatedByAssistant); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java index da0a794c74f3..4b413e5f76bb 100644 --- a/services/core/java/com/android/server/timezone/RulesManagerService.java +++ b/services/core/java/com/android/server/timezone/RulesManagerService.java @@ -49,7 +49,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import libcore.icu.ICU; import libcore.timezone.TzDataSetVersion; import libcore.timezone.TimeZoneFinder; -import libcore.util.ZoneInfoDB; +import libcore.timezone.ZoneInfoDB; import static android.app.timezone.RulesState.DISTRO_STATUS_INSTALLED; import static android.app.timezone.RulesState.DISTRO_STATUS_NONE; diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 409d2b43f694..6ede423f63c8 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -88,7 +88,6 @@ import android.util.SparseArray; import android.util.Xml; import android.view.Display; import android.view.IWindowManager; -import android.view.WindowManager; import com.android.internal.R; import com.android.internal.content.PackageMonitor; @@ -487,6 +486,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private void generateCrop(WallpaperData wallpaper) { boolean success = false; + // Only generate crop for default display. + final WallpaperData.DisplayData wpData = getDisplayDataOrCreate(wallpaper, DEFAULT_DISPLAY); Rect cropHint = new Rect(wallpaper.cropHint); if (DEBUG) { @@ -494,7 +495,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub + Integer.toHexString(wallpaper.whichPending) + " to " + wallpaper.cropFile.getName() + " crop=(" + cropHint.width() + 'x' + cropHint.height() - + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')'); + + ") dim=(" + wpData.mWidth + 'x' + wpData.mHeight + ')'); } // Analyse the source; needed in multiple cases @@ -533,11 +534,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } // scale if the crop height winds up not matching the recommended metrics - needScale = (wallpaper.height != cropHint.height()); + needScale = (wpData.mHeight != cropHint.height()); if (DEBUG) { Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height()); - Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height); + Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight); Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale); } @@ -567,7 +568,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // just let the decode take care of it because we also want to remap where the // cropHint rectangle lies in the decoded [super]rect. final BitmapFactory.Options scaler; - final int actualScale = cropHint.height() / wallpaper.height; + final int actualScale = cropHint.height() / wpData.mHeight; int scale = 1; while (2*scale < actualScale) { scale *= 2; @@ -593,17 +594,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub cropHint.offsetTo(0, 0); cropHint.right /= scale; // adjust by downsampling factor cropHint.bottom /= scale; - final float heightR = ((float)wallpaper.height) / ((float)cropHint.height()); + final float heightR = + ((float) wpData.mHeight) / ((float) cropHint.height()); if (DEBUG) { Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint); } final int destWidth = (int)(cropHint.width() * heightR); final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, - destWidth, wallpaper.height, true); + destWidth, wpData.mHeight, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); - Slog.v(TAG, " dims: w=" + wallpaper.width - + " h=" + wallpaper.height); + Slog.v(TAG, " dims: w=" + wpData.mWidth + + " h=" + wpData.mHeight); Slog.v(TAG, " out: w=" + finalCrop.getWidth() + " h=" + finalCrop.getHeight()); } @@ -670,13 +672,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (connector == null) return; connector.disconnectLocked(); mLastWallpaper.connection.removeDisplayConnector(displayId); + mLastWallpaper.removeDisplayData(displayId); } } } @Override public void onDisplayChanged(int displayId) { - // TODO(b/115486823) Review that do we need to handle display changes. } }; @@ -778,16 +780,23 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private RemoteCallbackList<IWallpaperManagerCallback> callbacks = new RemoteCallbackList<IWallpaperManagerCallback>(); - int width = -1; - int height = -1; + private static final class DisplayData { + int mWidth = -1; + int mHeight = -1; + final Rect mPadding = new Rect(0, 0, 0, 0); + final int mDisplayId; + + DisplayData(int displayId) { + mDisplayId = displayId; + } + } + private SparseArray<DisplayData> mDisplayDatas = new SparseArray<>(); /** * The crop hint supplied for displaying a subset of the source image */ final Rect cropHint = new Rect(0, 0, 0, 0); - final Rect padding = new Rect(0, 0, 0, 0); - WallpaperData(int userId, String inputFileName, String cropFileName) { this.userId = userId; final File wallpaperDir = getWallpaperDir(userId); @@ -803,6 +812,44 @@ public class WallpaperManagerService extends IWallpaperManager.Stub boolean sourceExists() { return wallpaperFile.exists(); } + + void removeDisplayData(int displayId) { + mDisplayDatas.remove(displayId); + } + } + + private WallpaperData.DisplayData getDisplayDataOrCreate(WallpaperData data, int displayId) { + WallpaperData.DisplayData wpdData = data.mDisplayDatas.get(displayId); + if (wpdData == null) { + wpdData = new WallpaperData.DisplayData(displayId); + ensureSaneWallpaperDisplaySize(wpdData, displayId); + data.mDisplayDatas.append(displayId, wpdData); + } + return wpdData; + } + + private void ensureSaneWallpaperDisplaySize(WallpaperData.DisplayData wpdData, + int displayId) { + // We always want to have some reasonable width hint. + final int baseSize = getMaximumSizeDimension(displayId); + if (wpdData.mWidth < baseSize) { + wpdData.mWidth = baseSize; + } + if (wpdData.mHeight < baseSize) { + wpdData.mHeight = baseSize; + } + } + + private int getMaximumSizeDimension(int displayId) { + Display display = mDisplayManager.getDisplay(displayId); + return display.getMaximumSizeDimension(); + } + + void forEachDisplayData(WallpaperData data, Consumer<WallpaperData.DisplayData> action) { + for (int i = data.mDisplayDatas.size() - 1; i >= 0; i--) { + final WallpaperData.DisplayData wpdData = data.mDisplayDatas.valueAt(i); + action.accept(wpdData); + } } int makeWallpaperIdLocked() { @@ -830,9 +877,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } void ensureStatusHandled() { + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(mWallpaper, + mDisplayId); if (mDimensionsChanged) { try { - mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height); + mEngine.setDesiredSize(wpdData.mWidth, wpdData.mHeight); } catch (RemoteException e) { Slog.w(TAG, "Failed to set wallpaper dimensions", e); } @@ -840,7 +889,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } if (mPaddingChanged) { try { - mEngine.setDisplayPadding(mWallpaper.padding); + mEngine.setDisplayPadding(wpdData.mPadding); } catch (RemoteException e) { Slog.w(TAG, "Failed to set wallpaper padding", e); } @@ -857,16 +906,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return; } + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, + mDisplayId); try { - // TODO(b/115486823) Consider the size of non-default display connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false, - wallpaper.width, wallpaper.height, - wallpaper.padding, mDisplayId); + wpdData.mWidth, wpdData.mHeight, + wpdData.mPadding, mDisplayId); } catch (RemoteException e) { Slog.w(TAG, "Failed attaching wallpaper on display", e); - // TODO(b/115486823) Failed when attaching a new engine, however, other engines - // may still working. Should we abandon them all or just ignore this one. - if (mLastWallpaper != null && !mLastWallpaper.wallpaperUpdating) { + if (mLastWallpaper != null && !mLastWallpaper.wallpaperUpdating + && connection.getConnectedEngineSize() == 0) { bindWallpaperComponentLocked(null /* componentName */, false /* force */, false /* fromUser */, wallpaper, null /* reply */); } @@ -952,11 +1001,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub void forEachDisplayConnector(Consumer<DisplayConnector> action) { for (int i = mDisplayConnector.size() - 1; i >= 0; i--) { - final DisplayConnector connector = mDisplayConnector.get(i); + final DisplayConnector connector = mDisplayConnector.valueAt(i); action.accept(connector); } } + int getConnectedEngineSize() { + int engineSize = 0; + for (int i = mDisplayConnector.size() - 1; i >= 0; i--) { + final DisplayConnector connector = mDisplayConnector.valueAt(i); + if (connector.mEngine != null) engineSize++; + } + return engineSize; + } + DisplayConnector getDisplayConnectorOrCreate(int displayId) { DisplayConnector connector = mDisplayConnector.get(displayId); if (connector == null) { @@ -1128,7 +1186,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub Slog.w(TAG, "Failed to set ambient mode state", e); } } - // TODO(b/115486823) Extends for secondary display. + // TODO(multi-display) So far, we have shared the same wallpaper on each display. + // Once we have multiple wallpapers on multiple displays, please complete here. if (displayId == DEFAULT_DISPLAY) { try { // This will trigger onComputeColors in the wallpaper engine. @@ -1560,7 +1619,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent; final WallpaperData fallback = new WallpaperData(wallpaper.userId, WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); - ensureSaneWallpaperData(fallback); + ensureSaneWallpaperData(fallback, DEFAULT_DISPLAY); bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply); mWaitingForUnlock = true; } @@ -1705,8 +1764,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return false; } - // TODO(b/115486823) Extends this method with specific display. - public void setDimensionHints(int width, int height, String callingPackage) + private boolean isValidDisplay(int displayId) { + return mDisplayManager.getDisplay(displayId) != null; + } + + /** + * Sets the dimension hint for the wallpaper. These hints indicate the desired + * minimum width and height for the wallpaper in a particular display. + */ + public void setDimensionHints(int width, int height, String callingPackage, int displayId) throws RemoteException { checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); if (!isWallpaperSupported(callingPackage)) { @@ -1719,90 +1785,113 @@ public class WallpaperManagerService extends IWallpaperManager.Stub throw new IllegalArgumentException("width and height must be > 0"); } - if (width != wallpaper.width || height != wallpaper.height) { - wallpaper.width = width; - wallpaper.height = height; - saveSettingsLocked(userId); + if (!isValidDisplay(displayId)) { + throw new IllegalArgumentException("Cannot find display with id=" + displayId); + } + + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, displayId); + if (width != wpdData.mWidth || height != wpdData.mHeight) { + wpdData.mWidth = width; + wpdData.mHeight = height; + if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId); if (mCurrentUserId != userId) return; // Don't change the properties now if (wallpaper.connection != null) { - // TODO(b/115486823) Extends this method with specific display. - final IWallpaperEngine engine = wallpaper.connection - .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine; + final WallpaperConnection.DisplayConnector connector = wallpaper.connection + .getDisplayConnectorOrCreate(displayId); + final IWallpaperEngine engine = connector != null ? connector.mEngine : null; if (engine != null) { try { engine.setDesiredSize(width, height); } catch (RemoteException e) { } notifyCallbacksLocked(wallpaper); - } else if (wallpaper.connection.mService != null) { + } else if (wallpaper.connection.mService != null && connector != null) { // We've attached to the service but the engine hasn't attached back to us // yet. This means it will be created with the previous dimensions, so we // need to update it to the new dimensions once it attaches. - // TODO(b/115486823) Extends this method with specific display. - wallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY) - .mDimensionsChanged = true; + connector.mDimensionsChanged = true; } } } } } - public int getWidthHint() throws RemoteException { + /** + * Returns the desired minimum width for the wallpaper in a particular display. + */ + public int getWidthHint(int displayId) throws RemoteException { synchronized (mLock) { + if (!isValidDisplay(displayId)) { + throw new IllegalArgumentException("Cannot find display with id=" + displayId); + } WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); if (wallpaper != null) { - return wallpaper.width; + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, + displayId); + return wpdData.mWidth; } else { return 0; } } } - public int getHeightHint() throws RemoteException { + /** + * Returns the desired minimum height for the wallpaper in a particular display. + */ + public int getHeightHint(int displayId) throws RemoteException { synchronized (mLock) { + if (!isValidDisplay(displayId)) { + throw new IllegalArgumentException("Cannot find display with id=" + displayId); + } WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); if (wallpaper != null) { - return wallpaper.height; + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, + displayId); + return wpdData.mHeight; } else { return 0; } } } - // TODO(b/115486823) Extends this method with specific display. - public void setDisplayPadding(Rect padding, String callingPackage) { + /** + * Sets extra padding that we would like the wallpaper to have outside of the display. + */ + public void setDisplayPadding(Rect padding, String callingPackage, int displayId) { checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); if (!isWallpaperSupported(callingPackage)) { return; } synchronized (mLock) { + if (!isValidDisplay(displayId)) { + throw new IllegalArgumentException("Cannot find display with id=" + displayId); + } int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) { throw new IllegalArgumentException("padding must be positive: " + padding); } - if (!padding.equals(wallpaper.padding)) { - wallpaper.padding.set(padding); - saveSettingsLocked(userId); + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, displayId); + if (!padding.equals(wpdData.mPadding)) { + wpdData.mPadding.set(padding); + if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId); if (mCurrentUserId != userId) return; // Don't change the properties now if (wallpaper.connection != null) { - // TODO(b/115486823) Extends this method with specific display. - final IWallpaperEngine engine = wallpaper.connection - .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine; + final WallpaperConnection.DisplayConnector connector = wallpaper.connection + .getDisplayConnectorOrCreate(displayId); + final IWallpaperEngine engine = connector != null ? connector.mEngine : null; if (engine != null) { try { engine.setDisplayPadding(padding); } catch (RemoteException e) { } notifyCallbacksLocked(wallpaper); - } else if (wallpaper.connection.mService != null) { + } else if (wallpaper.connection.mService != null && connector != null) { // We've attached to the service but the engine hasn't attached back to us // yet. This means it will be created with the previous dimensions, so we // need to update it to the new dimensions once it attaches. - // TODO(b/115486823) Extends this method with specific display. - wallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY) - .mPaddingChanged = true; + connector.mPaddingChanged = true; } } } @@ -1850,10 +1939,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // user switch) return null; } + // Only for default display. + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, + DEFAULT_DISPLAY); try { if (outParams != null) { - outParams.putInt("width", wallpaper.width); - outParams.putInt("height", wallpaper.height); + outParams.putInt("width", wpdData.mWidth); + outParams.putInt("height", wpdData.mHeight); } if (cb != null) { wallpaper.callbacks.register(cb); @@ -2075,10 +2167,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // We know a-priori that there is no lock-only wallpaper currently WallpaperData lockWP = new WallpaperData(userId, WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); + final WallpaperData.DisplayData lockWPDData = getDisplayDataOrCreate(lockWP, + DEFAULT_DISPLAY); + final WallpaperData.DisplayData sysWPDData = getDisplayDataOrCreate(sysWP, + DEFAULT_DISPLAY); lockWP.wallpaperId = sysWP.wallpaperId; lockWP.cropHint.set(sysWP.cropHint); - lockWP.width = sysWP.width; - lockWP.height = sysWP.height; + lockWPDData.mWidth = sysWPDData.mWidth; + lockWPDData.mHeight = sysWPDData.mHeight; lockWP.allowBackup = sysWP.allowBackup; lockWP.primaryColors = sysWP.primaryColors; @@ -2478,27 +2574,29 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (DEBUG) { Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId); } + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, + DEFAULT_DISPLAY); out.startTag(null, tag); out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId)); - out.attribute(null, "width", Integer.toString(wallpaper.width)); - out.attribute(null, "height", Integer.toString(wallpaper.height)); + out.attribute(null, "width", Integer.toString(wpdData.mWidth)); + out.attribute(null, "height", Integer.toString(wpdData.mHeight)); out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left)); out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top)); out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right)); out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom)); - if (wallpaper.padding.left != 0) { - out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left)); + if (wpdData.mPadding.left != 0) { + out.attribute(null, "paddingLeft", Integer.toString(wpdData.mPadding.left)); } - if (wallpaper.padding.top != 0) { - out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top)); + if (wpdData.mPadding.top != 0) { + out.attribute(null, "paddingTop", Integer.toString(wpdData.mPadding.top)); } - if (wallpaper.padding.right != 0) { - out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right)); + if (wpdData.mPadding.right != 0) { + out.attribute(null, "paddingRight", Integer.toString(wpdData.mPadding.right)); } - if (wallpaper.padding.bottom != 0) { - out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom)); + if (wpdData.mPadding.bottom != 0) { + out.attribute(null, "paddingBottom", Integer.toString(wpdData.mPadding.bottom)); } if (wallpaper.primaryColors != null) { @@ -2601,14 +2699,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper = new WallpaperData(userId, WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); mLockWallpaperMap.put(userId, wallpaper); - ensureSaneWallpaperData(wallpaper); + ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY); } else { // sanity fallback: we're in bad shape, but establishing a known // valid system+lock WallpaperData will keep us from dying. Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!"); wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP); mWallpaperMap.put(userId, wallpaper); - ensureSaneWallpaperData(wallpaper); + ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY); } } } @@ -2637,6 +2735,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } boolean success = false; + final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, + DEFAULT_DISPLAY); try { stream = new FileInputStream(file); XmlPullParser parser = Xml.newPullParser(); @@ -2663,8 +2763,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } if (DEBUG) { - Slog.v(TAG, "mWidth:" + wallpaper.width); - Slog.v(TAG, "mHeight:" + wallpaper.height); + Slog.v(TAG, "mWidth:" + wpdData.mWidth); + Slog.v(TAG, "mHeight:" + wpdData.mHeight); Slog.v(TAG, "cropRect:" + wallpaper.cropHint); Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors); Slog.v(TAG, "mName:" + wallpaper.name); @@ -2700,10 +2800,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub IoUtils.closeQuietly(stream); if (!success) { - wallpaper.width = -1; - wallpaper.height = -1; + wpdData.mWidth = -1; + wpdData.mHeight = -1; wallpaper.cropHint.set(0, 0, 0, 0); - wallpaper.padding.set(0, 0, 0, 0); + wpdData.mPadding.set(0, 0, 0, 0); wallpaper.name = ""; mLockWallpaperMap.remove(userId); @@ -2717,26 +2817,22 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - ensureSaneWallpaperData(wallpaper); + ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY); WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); if (lockWallpaper != null) { - ensureSaneWallpaperData(lockWallpaper); + ensureSaneWallpaperData(lockWallpaper, DEFAULT_DISPLAY); } } - private void ensureSaneWallpaperData(WallpaperData wallpaper) { - // We always want to have some reasonable width hint. - int baseSize = getMaximumSizeDimension(); - if (wallpaper.width < baseSize) { - wallpaper.width = baseSize; - } - if (wallpaper.height < baseSize) { - wallpaper.height = baseSize; - } - // and crop, if not previously specified - if (wallpaper.cropHint.width() <= 0 - || wallpaper.cropHint.height() <= 0) { - wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height); + private void ensureSaneWallpaperData(WallpaperData wallpaper, int displayId) { + final WallpaperData.DisplayData size = getDisplayDataOrCreate(wallpaper, displayId); + + if (displayId == DEFAULT_DISPLAY) { + // crop, if not previously specified + if (wallpaper.cropHint.width() <= 0 + || wallpaper.cropHint.height() <= 0) { + wallpaper.cropHint.set(0, 0, size.mWidth, size.mHeight); + } } } @@ -2752,19 +2848,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper.wallpaperId = makeWallpaperIdLocked(); } + final WallpaperData.DisplayData wpData = getDisplayDataOrCreate(wallpaper, DEFAULT_DISPLAY); + if (!keepDimensionHints) { - wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width")); - wallpaper.height = Integer.parseInt(parser - .getAttributeValue(null, "height")); + wpData.mWidth = Integer.parseInt(parser.getAttributeValue(null, "width")); + wpData.mHeight = Integer.parseInt(parser.getAttributeValue(null, "height")); } wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0); wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0); wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0); wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); - wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0); - wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0); - wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0); - wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0); + wpData.mPadding.left = getAttributeInt(parser, "paddingLeft", 0); + wpData.mPadding.top = getAttributeInt(parser, "paddingTop", 0); + wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0); + wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0); int colorsCount = getAttributeInt(parser, "colorsCount", 0); if (colorsCount > 0) { Color primary = null, secondary = null, tertiary = null; @@ -2787,12 +2884,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup")); } - private int getMaximumSizeDimension() { - WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); - Display d = wm.getDefaultDisplay(); - return d.getMaximumSizeDimension(); - } - // Called by SystemBackupAgent after files are restored to disk. public void settingsRestored() { // Verify caller is the system @@ -2832,7 +2923,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success + " id=" + wallpaper.wallpaperId); if (success) { - generateCrop(wallpaper); // based on the new image + metadata + generateCrop(wallpaper); // based on the new image + metadata bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false, wallpaper, null); } @@ -2937,12 +3028,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperData wallpaper = mWallpaperMap.valueAt(i); pw.print(" User "); pw.print(wallpaper.userId); pw.print(": id="); pw.println(wallpaper.wallpaperId); - pw.print(" mWidth="); - pw.print(wallpaper.width); - pw.print(" mHeight="); - pw.println(wallpaper.height); + forEachDisplayData(wallpaper, wpSize -> { + pw.print(" displayId="); + pw.println(wpSize.mDisplayId); + pw.print(" mWidth="); + pw.print(wpSize.mWidth); + pw.print(" mHeight="); + pw.println(wpSize.mHeight); + pw.print(" mPadding="); pw.println(wpSize.mPadding); + }); pw.print(" mCropHint="); pw.println(wallpaper.cropHint); - pw.print(" mPadding="); pw.println(wallpaper.padding); pw.print(" mName="); pw.println(wallpaper.name); pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup); pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent); @@ -2973,11 +3068,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub for (int i = 0; i < mLockWallpaperMap.size(); i++) { WallpaperData wallpaper = mLockWallpaperMap.valueAt(i); pw.print(" User "); pw.print(wallpaper.userId); - pw.print(": id="); pw.println(wallpaper.wallpaperId); - pw.print(" mWidth="); pw.print(wallpaper.width); - pw.print(" mHeight="); pw.println(wallpaper.height); + pw.print(": id="); pw.println(wallpaper.wallpaperId); + forEachDisplayData(wallpaper, wpSize -> { + pw.print(" displayId="); + pw.println(wpSize.mDisplayId); + pw.print(" mWidth="); pw.print(wpSize.mWidth); + pw.print(" mHeight="); pw.println(wpSize.mHeight); + pw.print(" mPadding="); pw.println(wpSize.mPadding); + }); pw.print(" mCropHint="); pw.println(wallpaper.cropHint); - pw.print(" mPadding="); pw.println(wallpaper.padding); pw.print(" mName="); pw.println(wallpaper.name); pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup); } diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index ed366453028e..33584d4a1710 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -39,8 +39,6 @@ import static com.android.server.am.ActivityDisplayProto.ID; import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityDisplayProto.STACKS; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStackSupervisor.FindTaskResult; -import static com.android.server.wm.ActivityStackSupervisor.TAG_STATES; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; @@ -48,6 +46,8 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.RootActivityContainer.FindTaskResult; +import static com.android.server.wm.RootActivityContainer.TAG_STATES; import android.annotation.Nullable; import android.app.ActivityOptions; @@ -84,7 +84,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> */ private static int sNextFreeStackId = 0; - private ActivityStackSupervisor mSupervisor; + private ActivityTaskManagerService mService; + private RootActivityContainer mRootActivityContainer; /** Actual Display this object tracks. */ int mDisplayId; Display mDisplay; @@ -141,8 +142,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> private final FindTaskResult mTmpFindTaskResult = new FindTaskResult(); - ActivityDisplay(ActivityStackSupervisor supervisor, Display display) { - mSupervisor = supervisor; + ActivityDisplay(RootActivityContainer root, Display display) { + mRootActivityContainer = root; + mService = root.mService; mDisplayId = display.getDisplayId(); mDisplay = display; mWindowContainerController = createWindowContainerController(); @@ -168,7 +170,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (displayId != DEFAULT_DISPLAY) { final int displayState = mDisplay.getState(); if (displayState == Display.STATE_OFF && mOffToken == null) { - mOffToken = mSupervisor.mService.acquireSleepToken("Display-off", displayId); + mOffToken = mService.acquireSleepToken("Display-off", displayId); } else if (displayState == Display.STATE_ON && mOffToken != null) { mOffToken.release(); mOffToken = null; @@ -189,7 +191,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> + " to displayId=" + mDisplayId + " position=" + position); addStackReferenceIfNeeded(stack); positionChildAt(stack, position); - mSupervisor.mService.updateSleepIfNeededLocked(); + mService.updateSleepIfNeededLocked(); } void removeChild(ActivityStack stack) { @@ -201,7 +203,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } removeStackReferenceIfNeeded(stack); releaseSelfIfNeeded(); - mSupervisor.mService.updateSleepIfNeededLocked(); + mService.updateSleepIfNeededLocked(); onStackOrderChanged(); } @@ -252,7 +254,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> final ActivityStack currentFocusedStack = getFocusedStack(); if (currentFocusedStack != prevFocusedStack) { mLastFocusedStack = prevFocusedStack; - EventLogTags.writeAmFocusedStack(mSupervisor.mCurrentUser, mDisplayId, + EventLogTags.writeAmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId, currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(), mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), updateLastFocusedStackReason); @@ -409,10 +411,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } } - final ActivityTaskManagerService service = mSupervisor.mService; - if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow, - service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement, - service.mSupportsPictureInPicture, activityType)) { + if (!isWindowingModeSupported(windowingMode, mService.mSupportsMultiWindow, + mService.mSupportsSplitScreenMultiWindow, + mService.mSupportsFreeformWindowManagement, mService.mSupportsPictureInPicture, + activityType)) { throw new IllegalArgumentException("Can't create stack for unsupported windowingMode=" + windowingMode); } @@ -425,10 +427,12 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop) { if (windowingMode == WINDOWING_MODE_PINNED) { - return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop); + return (T) new PinnedActivityStack(this, stackId, + mRootActivityContainer.mStackSupervisor, onTop); } - return (T) new ActivityStack( - this, stackId, mSupervisor, windowingMode, activityType, onTop); + return (T) new ActivityStack(this, stackId, + mRootActivityContainer.mStackSupervisor, windowingMode, activityType, + onTop); } /** @@ -543,7 +547,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = mStacks.get(stackNdx); // TODO(b/111541062): Check if resumed activity on this display instead - if (!mSupervisor.isTopDisplayFocusedStack(stack) + if (!mRootActivityContainer.isTopDisplayFocusedStack(stack) && stack.getResumedActivity() != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack + " mResumedActivity=" + stack.getResumedActivity()); @@ -608,7 +612,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (stack.getWindowingMode() != windowingMode) { continue; } - mSupervisor.removeStack(stack); + mRootActivityContainer.mStackSupervisor.removeStack(stack); } } } @@ -623,7 +627,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> for (int i = mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = mStacks.get(i); if (stack.getActivityType() == activityType) { - mSupervisor.removeStack(stack); + mRootActivityContainer.mStackSupervisor.removeStack(stack); } } } @@ -685,7 +689,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } private void onSplitScreenModeDismissed() { - mSupervisor.mWindowManager.deferSurfaceLayout(); + mRootActivityContainer.mWindowManager.deferSurfaceLayout(); try { // Adjust the windowing mode of any stack in secondary split-screen to fullscreen. for (int i = mStacks.size() - 1; i >= 0; --i) { @@ -709,12 +713,12 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> mHomeStack.moveToFront("onSplitScreenModeDismissed"); topFullscreenStack.moveToFront("onSplitScreenModeDismissed"); } - mSupervisor.mWindowManager.continueSurfaceLayout(); + mRootActivityContainer.mWindowManager.continueSurfaceLayout(); } } private void onSplitScreenModeActivated() { - mSupervisor.mWindowManager.deferSurfaceLayout(); + mRootActivityContainer.mWindowManager.deferSurfaceLayout(); try { // Adjust the windowing mode of any affected by split-screen to split-screen secondary. for (int i = mStacks.size() - 1; i >= 0; --i) { @@ -729,7 +733,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> false /* creating */); } } finally { - mSupervisor.mWindowManager.continueSurfaceLayout(); + mRootActivityContainer.mWindowManager.continueSurfaceLayout(); } } @@ -824,11 +828,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable TaskRecord task, int activityType) { // Make sure the windowing mode we are trying to use makes sense for what is supported. - final ActivityTaskManagerService service = mSupervisor.mService; - boolean supportsMultiWindow = service.mSupportsMultiWindow; - boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow; - boolean supportsFreeform = service.mSupportsFreeformWindowManagement; - boolean supportsPip = service.mSupportsPictureInPicture; + boolean supportsMultiWindow = mService.mSupportsMultiWindow; + boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow; + boolean supportsFreeform = mService.mSupportsFreeformWindowManagement; + boolean supportsPip = mService.mSupportsPictureInPicture; if (supportsMultiWindow) { if (task != null) { supportsMultiWindow = task.isResizeable(); @@ -932,7 +935,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> // This activity can be considered the top running activity if we are not considering // the locked state, the keyguard isn't locked, or we can show when locked. if (topRunning != null && considerKeyguardState - && mSupervisor.getKeyguardController().isKeyguardLocked() + && mRootActivityContainer.mStackSupervisor.getKeyguardController().isKeyguardLocked() && !topRunning.canShowWhenLocked()) { return null; } @@ -1010,7 +1013,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> @Override protected ConfigurationContainer getParent() { - return mSupervisor; + return mRootActivityContainer; } boolean isPrivate() { @@ -1043,8 +1046,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> // released (no more ActivityStack). But, we cannot release it at that moment or the // related WindowContainer and WindowContainerController will also be removed. So, we // set display as removed after reparenting stack finished. - final ActivityDisplay toDisplay = mSupervisor.getDefaultDisplay(); - mSupervisor.beginDeferResume(); + final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay(); + mRootActivityContainer.mStackSupervisor.beginDeferResume(); try { int numStacks = mStacks.size(); // Keep the order from bottom to top. @@ -1070,7 +1073,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> numStacks = mStacks.size(); } } finally { - mSupervisor.endDeferResume(); + mRootActivityContainer.mStackSupervisor.endDeferResume(); } mRemoved = true; @@ -1082,9 +1085,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> releaseSelfIfNeeded(); if (!mAllSleepTokens.isEmpty()) { - mSupervisor.mSleepTokens.removeAll(mAllSleepTokens); + mRootActivityContainer.mSleepTokens.removeAll(mAllSleepTokens); mAllSleepTokens.clear(); - mSupervisor.mService.updateSleepIfNeededLocked(); + mService.updateSleepIfNeededLocked(); } } @@ -1092,8 +1095,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (mStacks.isEmpty() && mRemoved) { mWindowContainerController.removeContainer(); mWindowContainerController = null; - mSupervisor.removeChild(this); - mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId); + mRootActivityContainer.removeChild(this); + mRootActivityContainer.mStackSupervisor + .getKeyguardController().onDisplayRemoved(mDisplayId); } } @@ -1122,7 +1126,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> boolean shouldSleep() { return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty()) - && (mSupervisor.mService.mRunningVoice == null); + && (mService.mRunningVoice == null); } void setFocusedApp(ActivityRecord r, boolean moveFocusNow) { @@ -1213,7 +1217,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> @Nullable ActivityRecord getHomeActivity() { - return getHomeActivityForUser(mSupervisor.mCurrentUser); + return getHomeActivityForUser(mRootActivityContainer.mCurrentUser); } @Nullable diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 1c08d039207b..0c0c818e0baa 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -277,7 +277,8 @@ class ActivityMetricsLogger { mLastLogTimeSecs = now; mWindowState = WINDOW_STATE_INVALID; - ActivityStack stack = mSupervisor.getTopDisplayFocusedStack(); + ActivityStack stack = + mSupervisor.mRootActivityContainer.getTopDisplayFocusedStack(); if (stack == null) { return; } @@ -289,7 +290,7 @@ class ActivityMetricsLogger { @WindowingMode int windowingMode = stack.getWindowingMode(); if (windowingMode == WINDOWING_MODE_PINNED) { - stack = mSupervisor.findStackBehind(stack); + stack = mSupervisor.mRootActivityContainer.findStackBehind(stack); windowingMode = stack.getWindowingMode(); } switch (windowingMode) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5e92b9e4d46a..61168ec26430 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -322,6 +322,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo private boolean inHistory; // are we in the history stack? final ActivityStackSupervisor mStackSupervisor; + final RootActivityContainer mRootActivityContainer; static final int STARTING_WINDOW_NOT_SHOWN = 0; static final int STARTING_WINDOW_SHOWN = 1; @@ -844,6 +845,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor, ActivityOptions options, ActivityRecord sourceRecord) { service = _service; + mRootActivityContainer = _service.mRootActivityContainer; appToken = new Token(this, _intent); info = aInfo; launchedFromPid = _launchedFromPid; @@ -1200,7 +1202,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } boolean isFocusable() { - return mStackSupervisor.isFocusable(this, isAlwaysFocusable()); + return mRootActivityContainer.isFocusable(this, isAlwaysFocusable()); } boolean isResizeable() { @@ -1353,7 +1355,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return false; } - if (mStackSupervisor.getTopResumedActivity() == this) { + if (mRootActivityContainer.getTopResumedActivity() == this) { if (DEBUG_FOCUS) { Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this); } @@ -1366,7 +1368,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo stack.moveToFront(reason, task); // Report top activity change to tracking services and WM - if (mStackSupervisor.getTopResumedActivity() == this) { + if (mRootActivityContainer.getTopResumedActivity() == this) { // TODO(b/111361570): Support multiple focused apps in WM service.setResumedActivityUncheckLocked(this, reason); } @@ -1864,9 +1866,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } else { if (deferRelaunchUntilPaused) { stack.destroyActivityLocked(this, true /* removeFromApp */, "stop-config"); - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } else { - mStackSupervisor.updatePreviousProcessLocked(this); + mRootActivityContainer.updatePreviousProcess(this); } } } @@ -2036,7 +2038,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // another activity to start or has stopped, then the key dispatching // timeout should not be caused by this. if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this) || stopped) { - final ActivityStack stack = mStackSupervisor.getTopDisplayFocusedStack(); + final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack(); // Try to use the one which is closest to top. ActivityRecord r = stack.getResumedActivity(); if (r == null) { @@ -2224,7 +2226,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo void setRequestedOrientation(int requestedOrientation) { final int displayId = getDisplayId(); final Configuration displayConfig = - mStackSupervisor.getDisplayOverrideConfiguration(displayId); + mRootActivityContainer.getDisplayOverrideConfiguration(displayId); final Configuration config = mWindowContainerController.setOrientation(requestedOrientation, displayId, displayConfig, mayFreezeScreenLocked(app)); @@ -2232,7 +2234,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo frozenBeforeDestroy = true; if (!service.updateDisplayOverrideConfigurationLocked(config, this, false /* deferResume */, displayId)) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } service.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( @@ -2867,7 +2869,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo void setShowWhenLocked(boolean showWhenLocked) { mShowWhenLocked = showWhenLocked; - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0 /* configChanges */, + mRootActivityContainer.ensureActivitiesVisible(null, 0 /* configChanges */, false /* preserveWindows */); } @@ -2905,7 +2907,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } boolean isTopRunningActivity() { - return mStackSupervisor.topRunningActivityLocked() == this; + return mRootActivityContainer.topRunningActivity() == this; } /** diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index bd3e43c380b6..f49c689d0a9f 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -63,7 +63,6 @@ import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStackSupervisor.FindTaskResult; import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; @@ -103,6 +102,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.RootActivityContainer.FindTaskResult; import static java.lang.Integer.MAX_VALUE; @@ -267,7 +267,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mStackSupervisor.resizeDockedStackLocked( getOverrideBounds(), mTmpRect2, mTmpRect2, null, null, PRESERVE_WINDOWS); } - mStackSupervisor.updateUIDsPresentOnDisplay(); + mRootActivityContainer.updateUIDsPresentOnDisplay(); } enum ActivityState { @@ -390,6 +390,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai /** Run all ActivityStacks through this */ protected final ActivityStackSupervisor mStackSupervisor; + protected final RootActivityContainer mRootActivityContainer; private boolean mTopActivityOccludesKeyguard; private ActivityRecord mTopDismissingKeyguardActivity; @@ -489,6 +490,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai int windowingMode, int activityType, boolean onTop) { mStackSupervisor = supervisor; mService = supervisor.mService; + mRootActivityContainer = mService.mRootActivityContainer; mHandler = new ActivityStackHandler(supervisor.mLooper); mWindowManager = mService.mWindowManager; mStackId = stackId; @@ -508,7 +510,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai T createStackWindowController(int displayId, boolean onTop, Rect outBounds) { return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds, - mStackSupervisor.mWindowManager); + mRootActivityContainer.mWindowManager); } T getWindowContainerController() { @@ -532,7 +534,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_STACK) Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason); setResumedActivity(record, reason + " - onActivityStateChanged"); - if (record == mStackSupervisor.getTopResumedActivity()) { + if (record == mRootActivityContainer.getTopResumedActivity()) { // TODO(b/111361570): Support multiple focused apps in WM mService.setResumedActivityUncheckLocked(record, reason); } @@ -622,7 +624,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai display.onStackWindowingModeChanged(this); } if (hasNewOverrideBounds) { - mStackSupervisor.resizeStackLocked(this, mTmpRect2, null, null, PRESERVE_WINDOWS, + mRootActivityContainer.resizeStack(this, mTmpRect2, null, null, PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, true /* deferResume */); } if (prevIsAlwaysOnTop != isAlwaysOnTop()) { @@ -819,8 +821,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } if (!deferEnsuringVisibility) { - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } @@ -854,10 +856,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai /** Resume next focusable stack after reparenting to another display. */ void postReparent() { adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */); - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); // Update visibility of activities before notifying WM. This way it won't try to resize // windows that are no longer visible. - mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, + mRootActivityContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); } @@ -882,7 +884,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } ActivityDisplay getDisplay() { - return mStackSupervisor.getActivityDisplay(mDisplayId); + return mRootActivityContainer.getActivityDisplay(mDisplayId); } /** @@ -1034,7 +1036,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } /** - * This is a simplified version of topRunningActivityLocked that provides a number of + * This is a simplified version of topRunningActivity that provides a number of * optional skip-over modes. It is intended for use with the ActivityController hook only. * * @param token If non-null, any history records matching this token will be skipped. @@ -1236,7 +1238,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai boolean isFocusable() { final ActivityRecord r = topRunningActivityLocked(); - return mStackSupervisor.isFocusable(this, r != null && r.isFocusable()); + return mRootActivityContainer.isFocusable(this, r != null && r.isFocusable()); } boolean isFocusableAndVisible() { @@ -1398,7 +1400,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final TaskRecord task = mTaskHistory.get(i); if (task.okToShowLocked()) { - if (DEBUG_TASKS) Slog.d(TAG_TASKS, "switchUserLocked: stack=" + getStackId() + + if (DEBUG_TASKS) Slog.d(TAG_TASKS, "switchUser: stack=" + getStackId() + " moving " + task + " to top"); mTaskHistory.remove(i); mTaskHistory.add(task); @@ -1587,7 +1589,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (prev == null) { if (resuming == null) { Slog.wtf(TAG, "Trying to pause when nothing is resumed"); - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } return false; } @@ -1665,7 +1667,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // pause, so just treat it as being paused now. if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next."); if (resuming == null) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } return false; } @@ -1704,7 +1706,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } } - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); } private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) { @@ -1757,9 +1759,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } if (resumeNext) { - final ActivityStack topStack = mStackSupervisor.getTopDisplayFocusedStack(); + final ActivityStack topStack = mRootActivityContainer.getTopDisplayFocusedStack(); if (!topStack.shouldSleepOrShutDownActivities()) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(topStack, prev, null); + mRootActivityContainer.resumeFocusedStacksTopActivities(topStack, prev, null); } else { checkReadyForSleep(); ActivityRecord top = topStack.topRunningActivityLocked(); @@ -1768,7 +1770,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // something. Also if the top activity on the stack is not the just paused // activity, we need to go ahead and resume it to ensure we complete an // in-flight app switch. - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } } @@ -1799,7 +1801,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false; } - mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS); } private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) { @@ -2011,7 +2013,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai /** * Ensure visibility with an option to also update the configuration of visible activities. * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean) - * @see ActivityStackSupervisor#ensureActivitiesVisibleLocked(ActivityRecord, int, boolean) + * @see RootActivityContainer#ensureActivitiesVisible(ActivityRecord, int, boolean) */ // TODO: Should be re-worked based on the fact that each task as a stack in most cases. final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, @@ -2032,7 +2034,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai boolean aboveTop = top != null; final boolean stackShouldBeVisible = shouldBeVisible(starting); boolean behindFullscreenActivity = !stackShouldBeVisible; - boolean resumeNextActivity = mStackSupervisor.isTopDisplayFocusedStack(this) + boolean resumeNextActivity = mRootActivityContainer.isTopDisplayFocusedStack(this) && (isInStackLocked(starting) == null); final boolean isTopNotPinnedStack = isAttached() && getDisplay().isTopNotPinnedStack(this); @@ -2443,7 +2445,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * * NOTE: It is not safe to call this method directly as it can cause an activity in a * non-focused stack to be resumed. - * Use {@link ActivityStackSupervisor#resumeFocusedStacksTopActivitiesLocked} to resume the + * Use {@link RootActivityContainer#resumeFocusedStacksTopActivities} to resume the * right activity for the current system state. */ @GuardedBy("mService") @@ -2513,7 +2515,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - mStackSupervisor.cancelInitializingActivities(); + mRootActivityContainer.cancelInitializingActivities(); // Remember how we'll process this pause/resume situation, and ensure // that the state is reset however we wind up proceeding. @@ -2536,7 +2538,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai executeAppTransition(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Top activity resumed " + next); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } @@ -2544,7 +2545,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // activity is paused, well that is the state we want. if (shouldSleepOrShutDownActivities() && mLastPausedActivity == next - && mStackSupervisor.allPausedActivitiesComplete()) { + && mRootActivityContainer.allPausedActivitiesComplete()) { // If the current top activity may be able to occlude keyguard but the occluded state // has not been set, update visibility and check again if we should continue to resume. boolean nothingToResume = true; @@ -2565,7 +2566,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai executeAppTransition(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Going to sleep and all paused"); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } } @@ -2576,7 +2576,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (!mService.mAmInternal.hasStartedUserState(next.userId)) { Slog.w(TAG, "Skipping resume of top activity " + next + ": user " + next.userId + " is stopped"); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } @@ -2590,10 +2589,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); // If we are currently pausing an activity, then don't do anything until that is done. - if (!mStackSupervisor.allPausedActivitiesComplete()) { + if (!mRootActivityContainer.allPausedActivitiesComplete()) { if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE, "resumeTopActivityLocked: Skip resume: some activity pausing."); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } @@ -2640,7 +2638,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, true /* updateLru */, true /* activityChange */, false /* updateOomAdj */); } - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); if (lastResumed != null) { lastResumed.setWillCloseOrEnterPip(true); } @@ -2655,7 +2652,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai executeAppTransition(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } @@ -2673,7 +2669,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (prev != null && prev != next) { if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev) - && next != null && !next.nowVisible) { + && !next.nowVisible) { mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming top, waiting visible to hide: " + prev); @@ -2814,7 +2810,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // result of invisible window resize. // TODO: Remove this once visibilities are set correctly immediately when // starting an activity. - notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId, + notUpdated = !mRootActivityContainer.ensureVisibilityAndConfig(next, mDisplayId, true /* markFrozenIfConfigChanged */, false /* deferResume */); } @@ -2836,7 +2832,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai next.setVisibility(true); } next.completeResumeLocked(); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } @@ -2899,7 +2894,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai false /* taskSwitch */); } mStackSupervisor.startSpecificActivityLocked(next, true, false); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } @@ -2913,7 +2907,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai Slog.w(TAG, "Exception thrown during resume of " + next, e); requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null, "resume-exception", true); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } } else { @@ -2931,7 +2924,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mStackSupervisor.startSpecificActivityLocked(next, true, true); } - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } @@ -2942,7 +2934,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Try to move focus to the next visible stack with a running activity if this // stack is not covering the entire screen or is on a secondary display (with no home // stack). - return mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(nextFocusedStack, prev, + return mRootActivityContainer.resumeFocusedStacksTopActivities(nextFocusedStack, prev, null /* targetOptions */); } @@ -2950,8 +2942,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityInNextFocusableStack: " + reason + ", go home"); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); - return mStackSupervisor.resumeHomeActivity(prev, reason, mDisplayId); + return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId); } /** Returns the position the input task should be placed in this stack. */ @@ -3536,7 +3527,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } private void adjustFocusedActivityStack(ActivityRecord r, String reason) { - if (!mStackSupervisor.isTopDisplayFocusedStack(this) || + if (!mRootActivityContainer.isTopDisplayFocusedStack(this) || ((mResumedActivity != r) && (mResumedActivity != null))) { return; } @@ -3545,7 +3536,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final String myReason = reason + " adjustFocus"; if (next == r) { - final ActivityRecord top = mStackSupervisor.topRunningActivityLocked(); + final ActivityRecord top = mRootActivityContainer.topRunningActivity(); if (top != null) { top.moveFocusableActivityToTop(myReason); } @@ -3569,7 +3560,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final ActivityStack nextFocusableStack = adjustFocusToNextFocusableStack(myReason); if (nextFocusableStack != null) { final ActivityRecord top = nextFocusableStack.topRunningActivityLocked(); - if (top != null && top == mStackSupervisor.getTopResumedActivity()) { + if (top != null && top == mRootActivityContainer.getTopResumedActivity()) { // TODO(b/111361570): Remove this and update focused app per-display in // WindowManager every time an activity becomes resumed in // ActivityTaskManagerService#setResumedActivityUncheckLocked(). @@ -3597,7 +3588,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai */ private ActivityStack adjustFocusToNextFocusableStack(String reason, boolean allowFocusSelf) { final ActivityStack stack = - mStackSupervisor.getNextFocusableStackLocked(this, !allowFocusSelf); + mRootActivityContainer.getNextFocusableStack(this, !allowFocusSelf); final String myReason = reason + " adjustFocusToNextFocusableStack"; if (stack == null) { return null; @@ -4018,11 +4009,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // stack, need to make something visible in its place. Also if the display does not // have running activity, the configuration may need to be updated for restoring // original orientation of the display. - mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId, + mRootActivityContainer.ensureVisibilityAndConfig(next, mDisplayId, false /* markFrozenIfConfigChanged */, true /* deferResume */); } if (activityRemoved) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "destroyActivityLocked: finishCurrentActivityLocked r=" + r + @@ -4035,7 +4026,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r); mStackSupervisor.mFinishingActivities.add(r); r.resumeKeyDispatchingLocked(); - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); return r; } @@ -4377,7 +4368,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } if (activityRemoved) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } @@ -4568,7 +4559,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list, @@ -4712,7 +4703,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai task.mLastTimeMoved *= -1; } } - mStackSupervisor.invalidateTaskLayers(); + mRootActivityContainer.invalidateTaskLayers(); } final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options, @@ -4788,7 +4779,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai topActivity.supportsEnterPipOnTaskSwitch = true; } - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId); mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.taskId); @@ -4860,7 +4851,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return true; } - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); return true; } @@ -4907,7 +4898,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (updatedConfig) { // Ensure the resumed state of the focus activity if we updated the configuration of // any activity. - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } @@ -5099,7 +5090,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai */ void getRunningTasks(List<TaskRecord> tasksOut, @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed) { - boolean focusedStack = mStackSupervisor.getTopDisplayFocusedStack() == this; + boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this; boolean topTask = true; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); @@ -5164,7 +5155,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return removeHistoryRecordsForAppLocked(app); } - void handleAppCrashLocked(WindowProcessController app) { + void handleAppCrash(WindowProcessController app) { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { @@ -5311,7 +5302,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // We only need to adjust focused stack if this stack is in focus and we are not in the // process of moving the task to the top of the stack that will be focused. if (mode != REMOVE_TASK_MODE_MOVING_TO_TOP - && mStackSupervisor.isTopDisplayFocusedStack(this)) { + && mRootActivityContainer.isTopDisplayFocusedStack(this)) { String myReason = reason + " leftTaskHistoryEmpty"; if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) { getDisplay().moveHomeStackToFront(myReason); @@ -5417,7 +5408,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // The task might have already been running and its visibility needs to be synchronized with // the visibility of the stack / windows. ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) { @@ -5484,7 +5475,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai moveToFront(reason); // If the original state is resumed, there is no state change to update focused app. // So here makes sure the activity focus is set if it is the top. - if (origState == RESUMED && r == mStackSupervisor.getTopResumedActivity()) { + if (origState == RESUMED && r == mRootActivityContainer.getTopResumedActivity()) { // TODO(b/111361570): Support multiple focused apps in WM mService.setResumedActivityUncheckLocked(r, reason); } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 0ffa523a76bf..a71f5f3999a2 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -25,28 +25,18 @@ import static android.app.ActivityManager.START_FLAG_DEBUG; import static android.app.ActivityManager.START_FLAG_NATIVE_DEBUGGING; import static android.app.ActivityManager.START_FLAG_TRACK_ALLOCATION; import static android.app.ActivityManager.START_TASK_TO_FRONT; -import static android.app.ActivityTaskManager.INVALID_STACK_ID; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WaitResult.INVALID_DELAY; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.app.WindowConfiguration.activityTypeToString; -import static android.app.WindowConfiguration.windowingModeToString; -import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; -import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; -import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -59,26 +49,13 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; -import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; -import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS; -import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID; -import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT; -import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; -import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES; -import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY; -import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; -import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; @@ -86,9 +63,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IDLE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; @@ -96,6 +71,10 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_ONLY; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; +import static com.android.server.wm.RootActivityContainer.TAG_STATES; import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; @@ -103,20 +82,11 @@ import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; -import static java.lang.Integer.MAX_VALUE; - import android.Manifest; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManager.RunningTaskInfo; -import android.app.ActivityManager.StackInfo; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; -import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.ProfilerInfo; import android.app.ResultInfo; @@ -139,17 +109,11 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.Rect; -import android.hardware.display.DisplayManager; -import android.hardware.display.DisplayManager.DisplayListener; -import android.hardware.display.DisplayManagerInternal; -import android.hardware.power.V1_0.PowerHint; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Debug; -import android.os.FactoryTest; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -163,20 +127,13 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.provider.MediaStore; -import android.service.voice.IVoiceInteractionSession; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.DisplayMetrics; import android.util.EventLog; -import android.util.IntArray; import android.util.MergedConfiguration; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; -import android.util.TimeUtils; -import android.util.proto.ProtoOutputStream; -import android.view.Display; -import android.view.DisplayInfo; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -185,34 +142,28 @@ import com.android.internal.os.TransferPipe; import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.pooled.PooledLambda; -import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; -import com.android.server.am.AppTimeTracker; import com.android.server.am.EventLogTags; import com.android.server.am.UserState; -import com.android.server.wm.ActivityStack.ActivityState; -import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import java.util.Set; -public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener, - RecentTasks.Callbacks, RootWindowContainerListener { +// TODO: This class has become a dumping ground. Let's +// - Move things relating to the hierarchy to RootWindowContainer +// - Move things relating to activity life cycles to maybe a new class called ActivityLifeCycler +// - Move interface things to ActivityTaskManagerService. +// - All other little things to other files. +public class ActivityStackSupervisor implements RecentTasks.Callbacks { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_ATM; private static final String TAG_IDLE = TAG + POSTFIX_IDLE; private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; - private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE; private static final String TAG_STACK = TAG + POSTFIX_STACK; private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; - static final String TAG_STATES = TAG + POSTFIX_STATES; static final String TAG_TASKS = TAG + POSTFIX_TASKS; /** How long we wait until giving up on the last activity telling us it is idle. */ @@ -233,12 +184,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14; static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 15; - private static final String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay"; - - // Used to indicate if an object (e.g. stack) that we are trying to get - // should be created if it doesn't exist already. - static final boolean CREATE_IF_NEEDED = true; - // Used to indicate that windows of activities should be preserved during the resize. static final boolean PRESERVE_WINDOWS = true; @@ -270,25 +215,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private Rect mPendingTempOtherTaskBounds; private Rect mPendingTempOtherTaskInsetBounds; - /** - * The modes which affect which tasks are returned when calling - * {@link ActivityStackSupervisor#anyTaskForIdLocked(int)}. - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - MATCH_TASK_IN_STACKS_ONLY, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE - }) - public @interface AnyTaskForIdMatchTaskMode {} - // Match only tasks in the current stacks - static final int MATCH_TASK_IN_STACKS_ONLY = 0; - // Match either tasks in the current stacks, or in the recent tasks if not found in the stacks - static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS = 1; - // Match either tasks in the current stacks, or in the recent tasks, restoring it to the - // provided stack id - static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE = 2; - // Activity actions an app cannot start if it uses a permission which is not granted. private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = new ArrayMap<>(); @@ -315,20 +241,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** The number of distinct task ids that can be assigned to the tasks of a single user */ private static final int MAX_TASK_IDS_PER_USER = UserHandle.PER_USER_RANGE; - ActivityTaskManagerService mService; + final ActivityTaskManagerService mService; + RootActivityContainer mRootActivityContainer; /** The historial list of recent tasks including inactive tasks */ RecentTasks mRecentTasks; /** Helper class to abstract out logic for fetching the set of currently running tasks */ - private RunningTasks mRunningTasks; + RunningTasks mRunningTasks; final ActivityStackSupervisorHandler mHandler; final Looper mLooper; /** Short cut */ WindowManagerService mWindowManager; - DisplayManager mDisplayManager; /** Common synchronization logic used to save things to disks. */ PersisterQueue mPersisterQueue; @@ -341,9 +267,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ private final SparseIntArray mCurTaskIdForUser = new SparseIntArray(20); - /** The current user */ - int mCurrentUser; - /** List of activities that are waiting for a new activity to become visible before completing * whatever operation they are supposed to do. */ // TODO: Remove mActivitiesWaitingForVisibleActivity list and just remove activity from @@ -392,9 +315,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * is being brought in front of us. */ boolean mUserLeaving = false; - /** Set when a power hint has started, but not ended. */ - private boolean mPowerHintSent; - /** * We don't want to allow the device to go to sleep while in the process * of launching an activity. This is primarily to allow alarm intent @@ -410,29 +330,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ PowerManager.WakeLock mGoingToSleep; - /** - * A list of tokens that cause the top activity to be put to sleep. - * They are used by components that may hide and block interaction with underlying - * activities. - */ - final ArrayList<SleepToken> mSleepTokens = new ArrayList<>(); - - /** Stack id of the front stack when user switched, indexed by userId. */ - SparseIntArray mUserStackInFront = new SparseIntArray(2); - - /** Reference to default display so we can quickly look it up. */ - private ActivityDisplay mDefaultDisplay; - - /** - * List of displays which contain activities, sorted by z-order. - * The last entry in the list is the topmost. - */ - private final ArrayList<ActivityDisplay> mActivityDisplays = new ArrayList<>(); - - private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>(); - - private DisplayManagerInternal mDisplayManagerInternal; - /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */ boolean inResumeTopActivity; @@ -443,50 +340,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private final Rect tempRect = new Rect(); private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic(); - // The default minimal size that will be used if the activity doesn't specify its minimal size. - // It will be calculated when the default display gets added. - int mDefaultMinSizeOfResizeableTaskDp = -1; - - // Whether tasks have moved and we need to rank the tasks before next OOM scoring - private boolean mTaskLayersChanged = true; - private ActivityMetricsLogger mActivityMetricsLogger; - private final ArrayList<ActivityRecord> mTmpActivityList = new ArrayList<>(); - - @Override - protected int getChildCount() { - return mActivityDisplays.size(); - } - - @Override - protected ActivityDisplay getChildAt(int index) { - return mActivityDisplays.get(index); - } - - @Override - protected ConfigurationContainer getParent() { - return null; - } - - Configuration getDisplayOverrideConfiguration(int displayId) { - final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId); - if (activityDisplay == null) { - throw new IllegalArgumentException("No display found with id: " + displayId); - } - - return activityDisplay.getOverrideConfiguration(); - } - - void setDisplayOverrideConfiguration(Configuration overrideConfiguration, int displayId) { - final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId); - if (activityDisplay == null) { - throw new IllegalArgumentException("No display found with id: " + displayId); - } - - activityDisplay.onOverrideConfigurationChanged(overrideConfiguration); - } - /** Check if placing task or activity on specified display is allowed. */ boolean canPlaceEntityOnDisplay(int displayId, int callingPid, int callingUid, ActivityInfo activityInfo) { @@ -508,44 +363,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Check if configuration of specified display matches current global config. - * Used to check if we can put a non-resizeable activity on a secondary display and it will get - * the same config as on the default display. - * @param displayId Id of the display to check. - * @return {@code true} if configuration matches. - */ - private boolean displayConfigMatchesGlobal(int displayId) { - if (displayId == DEFAULT_DISPLAY) { - return true; - } - if (displayId == INVALID_DISPLAY) { - return false; - } - final ActivityDisplay targetDisplay = getActivityDisplayOrCreateLocked(displayId); - if (targetDisplay == null) { - throw new IllegalArgumentException("No display found with id: " + displayId); - } - return getConfiguration().equals(targetDisplay.getConfiguration()); - } - - static class FindTaskResult { - ActivityRecord mRecord; - boolean mIdealMatch; - - void clear() { - mRecord = null; - mIdealMatch = false; - } - - void setTo(FindTaskResult result) { - mRecord = result.mRecord; - mIdealMatch = result.mIdealMatch; - } - } - - private final FindTaskResult mTmpFindTaskResult = new FindTaskResult(); - - /** * Used to keep track whether app visibilities got changed since the last pause. Useful to * determine whether to invoke the task stack change listener after pausing. */ @@ -565,11 +382,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ private boolean mAllowDockedStackResize = true; - /** - * Is dock currently minimized. - */ - boolean mIsDockMinimized; - private KeyguardController mKeyguardController; private PowerManager mPowerManager; @@ -577,8 +389,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private boolean mInitialized; - private RootWindowContainerController mWindowContainerController; - /** * Description of a request to start a new activity, which has been held * due to app switches being disabled. @@ -617,16 +427,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mHandler = new ActivityStackSupervisorHandler(looper); } - @VisibleForTesting - void setService(ActivityTaskManagerService service) { - mService = service; - } - - @VisibleForTesting - void setWindowContainerController(RootWindowContainerController controller) { - mWindowContainerController = controller; - } - public void initialize() { if (mInitialized) { return; @@ -681,321 +481,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void setWindowManager(WindowManagerService wm) { mWindowManager = wm; getKeyguardController().setWindowManager(wm); - setWindowContainerController(new RootWindowContainerController(this)); - - mDisplayManager = mService.mContext.getSystemService(DisplayManager.class); - mDisplayManager.registerDisplayListener(this, mHandler); - mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); - - final Display[] displays = mDisplayManager.getDisplays(); - for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) { - final Display display = displays[displayNdx]; - final ActivityDisplay activityDisplay = new ActivityDisplay(this, display); - if (activityDisplay.mDisplayId == DEFAULT_DISPLAY) { - mDefaultDisplay = activityDisplay; - } - addChild(activityDisplay, ActivityDisplay.POSITION_TOP); - } - calculateDefaultMinimalSizeOfResizeableTasks(); - - final ActivityDisplay defaultDisplay = getDefaultDisplay(); - - defaultDisplay.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); - positionChildAt(defaultDisplay, ActivityDisplay.POSITION_TOP); - } - - /** Change the z-order of the given display. */ - private void positionChildAt(ActivityDisplay display, int position) { - if (position >= mActivityDisplays.size()) { - position = mActivityDisplays.size() - 1; - } else if (position < 0) { - position = 0; - } - - if (mActivityDisplays.isEmpty()) { - mActivityDisplays.add(display); - } else if (mActivityDisplays.get(position) != display) { - mActivityDisplays.remove(display); - mActivityDisplays.add(position, display); - } - } - - @Override - public void onChildPositionChanged(DisplayWindowController childController, int position) { - // Assume AM lock is held from positionChildAt of controller in each hierarchy. - final ActivityDisplay display = getActivityDisplay(childController.getDisplayId()); - if (display != null) { - positionChildAt(display, position); - } - } - - ActivityStack getTopDisplayFocusedStack() { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityStack focusedStack = mActivityDisplays.get(i).getFocusedStack(); - if (focusedStack != null) { - return focusedStack; - } - } - return null; - } - - ActivityRecord getTopResumedActivity() { - final ActivityStack focusedStack = getTopDisplayFocusedStack(); - if (focusedStack == null) { - return null; - } - final ActivityRecord resumedActivity = focusedStack.getResumedActivity(); - if (resumedActivity != null && resumedActivity.app != null) { - return resumedActivity; - } - // The top focused stack might not have a resumed activity yet - look on all displays in - // focus order. - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - final ActivityRecord resumedActivityOnDisplay = display.getResumedActivity(); - if (resumedActivityOnDisplay != null) { - return resumedActivityOnDisplay; - } - } - return null; - } - - boolean isFocusable(ConfigurationContainer container, boolean alwaysFocusable) { - if (container.inSplitScreenPrimaryWindowingMode() && mIsDockMinimized) { - return false; - } - - return container.getWindowConfiguration().canReceiveKeys() || alwaysFocusable; - } - - boolean isTopDisplayFocusedStack(ActivityStack stack) { - return stack != null && stack == getTopDisplayFocusedStack(); } void moveRecentsStackToFront(String reason) { - final ActivityStack recentsStack = getDefaultDisplay().getStack( + final ActivityStack recentsStack = mRootActivityContainer.getDefaultDisplay().getStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); if (recentsStack != null) { recentsStack.moveToFront(reason); } } - boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) { - if (!mService.isBooting() && !mService.isBooted()) { - // Not ready yet! - return false; - } - - if (displayId == INVALID_DISPLAY) { - displayId = DEFAULT_DISPLAY; - } - - final ActivityRecord r = getActivityDisplay(displayId).getHomeActivity(); - final String myReason = reason + " resumeHomeActivity"; - - // Only resume home activity if isn't finishing. - if (r != null && !r.finishing) { - r.moveFocusableActivityToTop(myReason); - return resumeFocusedStacksTopActivitiesLocked(r.getStack(), prev, null); - } - return startHomeOnDisplay(mCurrentUser, myReason, displayId); - } - - /** - * Check if home activity start should be allowed on a display. - * @param homeInfo {@code ActivityInfo} of the home activity that is going to be launched. - * @param displayId The id of the target display. - * @param allowInstrumenting Whether launching home should be allowed if being instrumented. - * @return {@code true} if allow to launch, {@code false} otherwise. - */ - boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId, - boolean allowInstrumenting) { - if (mService.mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL - && mService.mTopAction == null) { - // We are running in factory test mode, but unable to find the factory test app, so - // just sit around displaying the error message and don't try to start anything. - return false; - } - - final WindowProcessController app = - mService.getProcessController(homeInfo.processName, homeInfo.applicationInfo.uid); - if (!allowInstrumenting && app != null && app.isInstrumenting()) { - // Don't do this if the home app is currently being instrumented. - return false; - } - - if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY - && displayId == mService.mVr2dDisplayId)) { - // No restrictions to default display or vr 2d display. - return true; - } - - final ActivityDisplay display = getActivityDisplay(displayId); - if (display == null || display.isRemoved() || !display.supportsSystemDecorations()) { - // Can't launch home on display that doesn't support system decorations. - return false; - } - - final boolean supportMultipleInstance = homeInfo.launchMode != LAUNCH_SINGLE_TASK - && homeInfo.launchMode != LAUNCH_SINGLE_INSTANCE - && homeInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q; - if (!supportMultipleInstance) { - // Can't launch home on other displays if it requested to be single instance. Also we - // don't allow home applications that target before Q to have multiple home activity - // instances because they may not be expected to have multiple home scenario and - // haven't explicitly request for single instance. - return false; - } - - return true; - } - - TaskRecord anyTaskForIdLocked(int id) { - return anyTaskForIdLocked(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE); - } - - TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode) { - return anyTaskForIdLocked(id, matchMode, null, !ON_TOP); - } - - /** - * Returns a {@link TaskRecord} for the input id if available. {@code null} otherwise. - * @param id Id of the task we would like returned. - * @param matchMode The mode to match the given task id in. - * @param aOptions The activity options to use for restoration. Can be null. - * @param onTop If the stack for the task should be the topmost on the display. - */ - TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode, - @Nullable ActivityOptions aOptions, boolean onTop) { - // If options are set, ensure that we are attempting to actually restore a task - if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) { - throw new IllegalArgumentException("Should not specify activity options for non-restore" - + " lookup"); - } - - int numDisplays = mActivityDisplays.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final TaskRecord task = stack.taskForIdLocked(id); - if (task == null) { - continue; - } - if (aOptions != null) { - // Resolve the stack the task should be placed in now based on options - // and reparent if needed. - final ActivityStack launchStack = getLaunchStack(null, aOptions, task, onTop); - if (launchStack != null && stack != launchStack) { - final int reparentMode = onTop - ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE; - task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME, - "anyTaskForIdLocked"); - } - } - return task; - } - } - - // If we are matching stack tasks only, return now - if (matchMode == MATCH_TASK_IN_STACKS_ONLY) { - return null; - } - - // Otherwise, check the recent tasks and return if we find it there and we are not restoring - // the task from recents - if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents"); - final TaskRecord task = mRecentTasks.getTask(id); - - if (task == null) { - if (DEBUG_RECENTS) { - Slog.d(TAG_RECENTS, "\tDidn't find task id=" + id + " in recents"); - } - - return null; - } - - if (matchMode == MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) { - return task; - } - - // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE - if (!restoreRecentTaskLocked(task, aOptions, onTop)) { - if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, - "Couldn't restore task id=" + id + " found in recents"); - return null; - } - if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents"); - return task; - } - - ActivityRecord isInAnyStackLocked(IBinder token) { - int numDisplays = mActivityDisplays.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final ActivityRecord r = stack.isInStackLocked(token); - if (r != null) { - return r; - } - } - } - return null; - } - - /** - * Detects whether we should show a lock screen in front of this task for a locked user. - * <p> - * We'll do this if either of the following holds: - * <ul> - * <li>The top activity explicitly belongs to {@param userId}.</li> - * <li>The top activity returns a result to an activity belonging to {@param userId}.</li> - * </ul> - * - * @return {@code true} if the top activity looks like it belongs to {@param userId}. - */ - private boolean taskTopActivityIsUser(TaskRecord task, @UserIdInt int userId) { - // To handle the case that work app is in the task but just is not the top one. - final ActivityRecord activityRecord = task.getTopActivity(); - final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null); - - return (activityRecord != null && activityRecord.userId == userId) - || (resultTo != null && resultTo.userId == userId); - } - - /** - * Find all visible task stacks containing {@param userId} and intercept them with an activity - * to block out the contents and possibly start a credential-confirming intent. - * - * @param userId user handle for the locked managed profile. - */ - void lockAllProfileTasks(@UserIdInt int userId) { - mWindowManager.deferSurfaceLayout(); - try { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final List<TaskRecord> tasks = stack.getAllTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) { - final TaskRecord task = tasks.get(taskNdx); - - // Check the task for a top activity belonging to userId, or returning a - // result to an activity belonging to userId. Example case: a document - // picker for personal files, opened by a work app, should still get locked. - if (taskTopActivityIsUser(task, userId)) { - mService.getTaskChangeNotificationController().notifyTaskProfileLocked( - task.taskId, userId); - } - } - } - } - } finally { - mWindowManager.continueSurfaceLayout(); - } - } - void setNextTaskIdForUserLocked(int taskId, int userId) { final int currentTaskId = mCurTaskIdForUser.get(userId, -1); if (taskId > currentTaskId) { @@ -1019,7 +514,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on. int candidateTaskId = nextTaskIdForUser(currentTaskId, userId); while (mRecentTasks.containsTaskId(candidateTaskId, userId) - || anyTaskForIdLocked( + || mRootActivityContainer.anyTaskForId( candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) { candidateTaskId = nextTaskIdForUser(candidateTaskId, userId); if (candidateTaskId == currentTaskId) { @@ -1034,145 +529,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return candidateTaskId; } - boolean attachApplicationLocked(WindowProcessController app) throws RemoteException { - final String processName = app.mName; - boolean didSomething = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - if (!isTopDisplayFocusedStack(stack)) { - continue; - } - stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList); - final ActivityRecord top = stack.topRunningActivityLocked(); - final int size = mTmpActivityList.size(); - for (int i = 0; i < size; i++) { - final ActivityRecord activity = mTmpActivityList.get(i); - if (activity.app == null && app.mUid == activity.info.applicationInfo.uid - && processName.equals(activity.processName)) { - try { - if (realStartActivityLocked(activity, app, - top == activity /* andResume */, true /* checkConfig */)) { - didSomething = true; - } - } catch (RemoteException e) { - Slog.w(TAG, "Exception in new application when starting activity " - + top.intent.getComponent().flattenToShortString(), e); - throw e; - } - } - } - } - } - if (!didSomething) { - ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); - } - return didSomething; - } - - boolean allResumedActivitiesIdle() { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - // TODO(b/117135575): Check resumed activities on all visible stacks. - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - if (display.isSleeping()) { - // No resumed activities while display is sleeping. - continue; - } - - // If the focused stack is not null or not empty, there should have some activities - // resuming or resumed. Make sure these activities are idle. - final ActivityStack stack = display.getFocusedStack(); - if (stack == null || stack.numActivities() == 0) { - continue; - } - final ActivityRecord resumedActivity = stack.getResumedActivity(); - if (resumedActivity == null || !resumedActivity.idle) { - if (DEBUG_STATES) { - Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack=" - + stack.mStackId + " " + resumedActivity + " not idle"); - } - return false; - } - } - // Send launch end powerhint when idle - sendPowerHintForLaunchEndIfNeeded(); - return true; - } - - private boolean allResumedActivitiesVisible() { - boolean foundResumed = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final ActivityRecord r = stack.getResumedActivity(); - if (r != null) { - if (!r.nowVisible || mActivitiesWaitingForVisibleActivity.contains(r)) { - return false; - } - foundResumed = true; - } - } - } - return foundResumed; - } - - private void executeAppTransitionForAllDisplay() { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - display.getWindowContainerController().executeAppTransition(); - } - } - - /** - * Pause all activities in either all of the stacks or just the back stacks. - * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving(). - * @param resuming The resuming activity. - * @param dontWait The resuming activity isn't going to wait for all activities to be paused - * before resuming. - * @return true if any activity was paused as a result of this call. - */ - boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) { - boolean someActivityPaused = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - someActivityPaused |= mActivityDisplays.get(displayNdx) - .pauseBackStacks(userLeaving, resuming, dontWait); - } - return someActivityPaused; - } - - boolean allPausedActivitiesComplete() { - boolean pausing = true; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final ActivityRecord r = stack.mPausingActivity; - if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) { - if (DEBUG_STATES) { - Slog.d(TAG_STATES, - "allPausedActivitiesComplete: r=" + r + " state=" + r.getState()); - pausing = false; - } else { - return false; - } - } - } - } - return pausing; - } - - void cancelInitializingActivities() { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.cancelInitializingActivities(); - } - } - } - void waitActivityVisible(ComponentName name, WaitResult result, long startTimeMs) { final WaitInfo waitInfo = new WaitInfo(name, result, startTimeMs); mWaitingForActivityVisible.add(waitInfo); @@ -1263,24 +619,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - ActivityRecord topRunningActivityLocked() { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityRecord topActivity = mActivityDisplays.get(i).topRunningActivity(); - if (topActivity != null) { - return topActivity; - } - } - return null; - } - - @VisibleForTesting - void getRunningTasks(int maxNum, List<RunningTaskInfo> list, - @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode, - int callingUid, boolean allowed) { - mRunningTasks.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, - mActivityDisplays, callingUid, allowed); - } - ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags, ProfilerInfo profilerInfo) { final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null; @@ -1360,10 +698,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return resolveActivity(intent, rInfo, startFlags, profilerInfo); } - private boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, + boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { - if (!allPausedActivitiesComplete()) { + if (!mRootActivityContainer.allPausedActivitiesComplete()) { // While there are activities pausing we skipping starting any new activities until // pauses are complete. NOTE: that we also do this for activities that are starting in // the paused state because they will first be resumed then paused on the client side. @@ -1398,7 +736,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Deferring resume here because we're going to launch new activity shortly. // We don't want to perform a redundant launch of the same record while ensuring // configurations and trying to resume top activity of focused stack. - ensureVisibilityAndConfig(r, r.getDisplayId(), + mRootActivityContainer.ensureVisibilityAndConfig(r, r.getDisplayId(), false /* markFrozenIfConfigChanged */, true /* deferResume */); } @@ -1568,7 +906,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // launching the initial activity (that is, home), so that it can have // a chance to initialize itself while in the background, making the // switch back to it faster and look better. - if (isTopDisplayFocusedStack(stack)) { + if (mRootActivityContainer.isTopDisplayFocusedStack(stack)) { mService.getActivityStartController().startSetupActivity(); } @@ -1581,47 +919,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - /** - * Ensure all activities visibility, update orientation and configuration. - * - * @param starting The currently starting activity or {@code null} if there is none. - * @param displayId The id of the display where operation is executed. - * @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to - * {@code true} if config changed. - * @param deferResume Whether to defer resume while updating config. - * @return 'true' if starting activity was kept or wasn't provided, 'false' if it was relaunched - * because of configuration update. - */ - boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId, - boolean markFrozenIfConfigChanged, boolean deferResume) { - // First ensure visibility without updating the config just yet. We need this to know what - // activities are affecting configuration now. - // Passing null here for 'starting' param value, so that visibility of actual starting - // activity will be properly updated. - ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, - false /* preserveWindows */, false /* notifyClients */); - - if (displayId == INVALID_DISPLAY) { - // The caller didn't provide a valid display id, skip updating config. - return true; - } - - // Force-update the orientation from the WindowManager, since we need the true configuration - // to send to the client now. - final Configuration config = mWindowManager.updateOrientationFromAppTokens( - getDisplayOverrideConfiguration(displayId), - starting != null && starting.mayFreezeScreenLocked(starting.app) - ? starting.appToken : null, - displayId, true /* forceUpdate */); - if (starting != null && markFrozenIfConfigChanged && config != null) { - starting.frozenBeforeDestroy = true; - } - - // Update the configuration of the activities on the display. - return mService.updateDisplayOverrideConfigurationLocked(config, starting, deferResume, - displayId); - } - private void logIfTransactionTooLarge(Intent intent, Bundle icicle) { int extrasSize = 0; if (intent != null) { @@ -1677,47 +974,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mService.mH.sendMessage(msg); } - void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) { - boolean sendHint = forceSend; - - if (!sendHint) { - // Send power hint if we don't know what we're launching yet - sendHint = targetActivity == null || targetActivity.app == null; - } - - if (!sendHint) { // targetActivity != null - // Send power hint when the activity's process is different than the current resumed - // activity on all displays, or if there are no resumed activities in the system. - boolean noResumedActivities = true; - boolean allFocusedProcessesDiffer = true; - for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { - final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); - final ActivityRecord resumedActivity = activityDisplay.getResumedActivity(); - final WindowProcessController resumedActivityProcess = - resumedActivity == null ? null : resumedActivity.app; - - noResumedActivities &= resumedActivityProcess == null; - if (resumedActivityProcess != null) { - allFocusedProcessesDiffer &= !resumedActivityProcess.equals(targetActivity.app); - } - } - sendHint = noResumedActivities || allFocusedProcessesDiffer; - } - - if (sendHint && mService.mPowerManagerInternal != null) { - mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 1); - mPowerHintSent = true; - } - } - - void sendPowerHintForLaunchEndIfNeeded() { - // Trigger launch power hint if activity is launched - if (mPowerHintSent && mService.mPowerManagerInternal != null) { - mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 0); - mPowerHintSent = false; - } - } - boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, boolean ignoreTargetSecurity, boolean launchingInTask, @@ -1796,7 +1052,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(launchDisplayId); + final ActivityDisplay activityDisplay = + mRootActivityContainer.getActivityDisplayOrCreate(launchDisplayId); if (activityDisplay == null || activityDisplay.isRemoved()) { Slog.w(TAG, "Launch on display check: display not found"); return false; @@ -1858,21 +1115,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } - /** Update lists of UIDs that are present on displays and have access to them. */ - void updateUIDsPresentOnDisplay() { - mDisplayAccessUIDs.clear(); - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); - // Only bother calculating the whitelist for private displays - if (activityDisplay.isPrivate()) { - mDisplayAccessUIDs.append( - activityDisplay.mDisplayId, activityDisplay.getPresentUIDs()); - } - } - // Store updated lists in DisplayManager. Callers from outside of AM should get them there. - mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs); - } - UserInfo getUserInfo(int userId) { final long identity = Binder.clearCallingIdentity(); try { @@ -2024,7 +1266,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Check if able to finish booting when device is booting and all resumed activities // are idle. - if ((mService.isBooting() && allResumedActivitiesIdle()) || fromTimeout) { + if ((mService.isBooting() && mRootActivityContainer.allResumedActivitiesIdle()) + || fromTimeout) { booting = checkFinishBootingLocked(); } @@ -2033,7 +1276,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D r.mRelaunchReason = RELAUNCH_REASON_NONE; } - if (allResumedActivitiesIdle()) { + if (mRootActivityContainer.allResumedActivitiesIdle()) { if (r != null) { mService.scheduleAppGcsLocked(); } @@ -2046,7 +1289,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } mLaunchingActivity.release(); } - ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); } // Atomically retrieve all of the other things to do. @@ -2102,186 +1345,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D //mWindowManager.dump(); if (activityRemoved) { - resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } return r; } - boolean handleAppDiedLocked(WindowProcessController app) { - boolean hasVisibleActivities = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - hasVisibleActivities |= stack.handleAppDiedLocked(app); - } - } - return hasVisibleActivities; - } - - void closeSystemDialogsLocked() { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.closeSystemDialogsLocked(); - } - } - } - - void removeUserLocked(int userId) { - mUserStackInFront.delete(userId); - } - - /** - * Update the last used stack id for non-current user (current user's last - * used stack is the focused stack) - */ - void updateUserStackLocked(int userId, ActivityStack stack) { - if (userId != mCurrentUser) { - mUserStackInFront.put(userId, stack != null ? stack.getStackId() - : getDefaultDisplay().getHomeStack().mStackId); - } - } - - /** - * @return true if some activity was finished (or would have finished if doit were true). - */ - boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses, - boolean doit, boolean evenPersistent, int userId) { - boolean didSomething = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - if (stack.finishDisabledPackageActivitiesLocked( - packageName, filterByClasses, doit, evenPersistent, userId)) { - didSomething = true; - } - } - } - return didSomething; - } - - void updatePreviousProcessLocked(ActivityRecord r) { - // Now that this process has stopped, we may want to consider - // it to be the previous app to try to keep around in case - // the user wants to return to it. - - // First, found out what is currently the foreground app, so that - // we don't blow away the previous app if this activity is being - // hosted by the process that is actually still the foreground. - WindowProcessController fgApp = null; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - if (isTopDisplayFocusedStack(stack)) { - final ActivityRecord resumedActivity = stack.getResumedActivity(); - if (resumedActivity != null) { - fgApp = resumedActivity.app; - } else if (stack.mPausingActivity != null) { - fgApp = stack.mPausingActivity.app; - } - break; - } - } - } - - // Now set this one as the previous process, only if that really - // makes sense to. - if (r.hasProcess() && fgApp != null && r.app != fgApp - && r.lastVisibleTime > mService.mPreviousProcessVisibleTime - && r.app != mService.mHomeProcess) { - mService.mPreviousProcess = r.app; - mService.mPreviousProcessVisibleTime = r.lastVisibleTime; - } - } - - boolean resumeFocusedStacksTopActivitiesLocked() { - return resumeFocusedStacksTopActivitiesLocked(null, null, null); - } - - boolean resumeFocusedStacksTopActivitiesLocked( - ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { - - if (!readyToResume()) { - return false; - } - - if (targetStack != null && (targetStack.isTopStackOnDisplay() - || getTopDisplayFocusedStack() == targetStack)) { - return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); - } - - // Resume all top activities in focused stacks on all displays. - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - final ActivityStack focusedStack = display.getFocusedStack(); - if (focusedStack == null) { - continue; - } - final ActivityRecord r = focusedStack.topRunningActivityLocked(); - if (r == null || !r.isState(RESUMED)) { - focusedStack.resumeTopActivityUncheckedLocked(null, null); - } else if (r.isState(RESUMED)) { - // Kick off any lingering app transitions form the MoveTaskToFront operation. - focusedStack.executeAppTransition(targetOptions); - } - } - - return false; - } - - void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.updateActivityApplicationInfoLocked(aInfo); - } - } - } - - /** - * Finish the topmost activities in all stacks that belong to the crashed app. - * @param app The app that crashed. - * @param reason Reason to perform this action. - * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished. - */ - int finishTopCrashedActivitiesLocked(WindowProcessController app, String reason) { - TaskRecord finishedTask = null; - ActivityStack focusedStack = getTopDisplayFocusedStack(); - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - // It is possible that request to finish activity might also remove its task and stack, - // so we need to be careful with indexes in the loop and check child count every time. - for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason); - if (stack == focusedStack || finishedTask == null) { - finishedTask = t; - } - } - } - return finishedTask != null ? finishedTask.taskId : INVALID_TASK_ID; - } - - void finishVoiceTask(IVoiceInteractionSession session) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - final int numStacks = display.getChildCount(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.finishVoiceTask(session); - } - } - } - - /** - * This doesn't just find a task, it also moves the task to front. - */ + /** This doesn't just find a task, it also moves the task to front. */ void findTaskToMoveToFront(TaskRecord task, int flags, ActivityOptions options, String reason, boolean forceNonResizeable) { ActivityStack currentStack = task.getStack(); @@ -2301,7 +1371,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final Rect bounds = options.getLaunchBounds(); task.updateOverrideConfiguration(bounds); - ActivityStack stack = getLaunchStack(null, options, task, ON_TOP); + ActivityStack stack = + mRootActivityContainer.getLaunchStack(null, options, task, ON_TOP); if (stack != currentStack) { moveHomeStackToFrontIfNeeded(flags, stack.getDisplay(), reason); @@ -2313,7 +1384,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // still need moveTaskToFrontLocked() below for any transition settings. } if (stack.resizeStackWithLaunchBounds()) { - resizeStackLocked(stack, bounds, null /* tempTaskBounds */, + mRootActivityContainer.resizeStack(stack, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); } else { @@ -2366,388 +1437,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return mLaunchParamsController; } - protected <T extends ActivityStack> T getStack(int stackId) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final T stack = mActivityDisplays.get(i).getStack(stackId); - if (stack != null) { - return stack; - } - } - return null; - } - - /** @see ActivityDisplay#getStack(int, int) */ - private <T extends ActivityStack> T getStack(int windowingMode, int activityType) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final T stack = mActivityDisplays.get(i).getStack(windowingMode, activityType); - if (stack != null) { - return stack; - } - } - return null; - } - - int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options, - @Nullable TaskRecord task) { - // Preference is given to the activity type for the activity then the task since the type - // once set shouldn't change. - int activityType = r != null ? r.getActivityType() : ACTIVITY_TYPE_UNDEFINED; - if (activityType == ACTIVITY_TYPE_UNDEFINED && task != null) { - activityType = task.getActivityType(); - } - if (activityType != ACTIVITY_TYPE_UNDEFINED) { - return activityType; - } - if (options != null) { - activityType = options.getLaunchActivityType(); - } - return activityType != ACTIVITY_TYPE_UNDEFINED ? activityType : ACTIVITY_TYPE_STANDARD; - } - - <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, - @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) { - return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */); - } - - /** - * Returns the right stack to use for launching factoring in all the input parameters. - * - * @param r The activity we are trying to launch. Can be null. - * @param options The activity options used to the launch. Can be null. - * @param candidateTask The possible task the activity might be launched in. Can be null. - * @params launchParams The resolved launch params to use. - * - * @return The stack to use for the launch or INVALID_STACK_ID. - */ - <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, - @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop, - @Nullable LaunchParamsController.LaunchParams launchParams) { - int taskId = INVALID_TASK_ID; - int displayId = INVALID_DISPLAY; - //Rect bounds = null; - - // We give preference to the launch preference in activity options. - if (options != null) { - taskId = options.getLaunchTaskId(); - displayId = options.getLaunchDisplayId(); - } - - // First preference for stack goes to the task Id set in the activity options. Use the stack - // associated with that if possible. - if (taskId != INVALID_TASK_ID) { - // Temporarily set the task id to invalid in case in re-entry. - options.setLaunchTaskId(INVALID_TASK_ID); - final TaskRecord task = anyTaskForIdLocked(taskId, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop); - options.setLaunchTaskId(taskId); - if (task != null) { - return task.getStack(); - } - } - - final int activityType = resolveActivityType(r, options, candidateTask); - T stack; - - // Next preference for stack goes to the display Id set the candidate display. - if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) { - displayId = launchParams.mPreferredDisplayId; - } - if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) { - if (r != null) { - stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options, - launchParams); - if (stack != null) { - return stack; - } - } - final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); - if (display != null) { - stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop); - if (stack != null) { - return stack; - } - } - } - - // Give preference to the stack and display of the input task and activity if they match the - // mode we want to launch into. - stack = null; - ActivityDisplay display = null; - if (candidateTask != null) { - stack = candidateTask.getStack(); - } - if (stack == null && r != null) { - stack = r.getStack(); - } - if (stack != null) { - display = stack.getDisplay(); - if (display != null && canLaunchOnDisplay(r, display.mDisplayId)) { - int windowingMode = launchParams != null ? launchParams.mWindowingMode - : WindowConfiguration.WINDOWING_MODE_UNDEFINED; - if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) { - windowingMode = display.resolveWindowingMode(r, options, candidateTask, - activityType); - } - if (stack.isCompatible(windowingMode, activityType)) { - return stack; - } - if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY - && display.getSplitScreenPrimaryStack() == stack - && candidateTask == stack.topTask()) { - // This is a special case when we try to launch an activity that is currently on - // top of split-screen primary stack, but is targeting split-screen secondary. - // In this case we don't want to move it to another stack. - // TODO(b/78788972): Remove after differentiating between preferred and required - // launch options. - return stack; - } - } - } - - if (display == null || !canLaunchOnDisplay(r, display.mDisplayId)) { - display = getDefaultDisplay(); - } - - return display.getOrCreateStack(r, options, candidateTask, activityType, onTop); - } - - /** @return true if activity record is null or can be launched on provided display. */ - private boolean canLaunchOnDisplay(ActivityRecord r, int displayId) { - if (r == null) { - return true; - } - return r.canBeLaunchedOnDisplay(displayId); - } - - /** - * Get a topmost stack on the display, that is a valid launch stack for specified activity. - * If there is no such stack, new dynamic stack can be created. - * @param displayId Target display. - * @param r Activity that should be launched there. - * @param candidateTask The possible task the activity might be put in. - * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null. - */ - private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r, - @Nullable TaskRecord candidateTask, @Nullable ActivityOptions options, - @Nullable LaunchParamsController.LaunchParams launchParams) { - final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId); - if (activityDisplay == null) { - throw new IllegalArgumentException( - "Display with displayId=" + displayId + " not found."); - } - - if (!r.canBeLaunchedOnDisplay(displayId)) { - return null; - } - - // If {@code r} is already in target display and its task is the same as the candidate task, - // the intention should be getting a launch stack for the reusable activity, so we can use - // the existing stack. - if (r.getDisplayId() == displayId && r.getTask() == candidateTask) { - return candidateTask.getStack(); - } - - // Return the topmost valid stack on the display. - for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = activityDisplay.getChildAt(i); - if (isValidLaunchStack(stack, displayId, r)) { - return stack; - } - } - - // If there is no valid stack on the external display - check if new dynamic stack will do. - if (displayId != DEFAULT_DISPLAY) { - final int windowingMode; - if (launchParams != null) { - // When launch params is not null, we always defer to its windowing mode. Sometimes - // it could be unspecified, which indicates it should inherit windowing mode from - // display. - windowingMode = launchParams.mWindowingMode; - } else { - windowingMode = options != null ? options.getLaunchWindowingMode() - : r.getWindowingMode(); - } - return activityDisplay.createStack( - windowingMode, - options != null ? options.getLaunchActivityType() : r.getActivityType(), - true /*onTop*/); - } - - Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId); - return null; - } - - ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r, - @Nullable ActivityOptions options, - @Nullable LaunchParamsController.LaunchParams launchParams) { - return getValidLaunchStackOnDisplay(displayId, r, null /* candidateTask */, options, - launchParams); - } - - // TODO: Can probably be consolidated into getLaunchStack()... - private boolean isValidLaunchStack(ActivityStack stack, int displayId, ActivityRecord r) { - switch (stack.getActivityType()) { - case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome(); - case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents(); - case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant(); - } - // There is a 1-to-1 relationship between stack and task when not in - // primary split-windowing mode. - if (stack.getWindowingMode() != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - return false; - } else { - return r.supportsSplitScreenWindowingMode(); - } - } - - /** - * Get next focusable stack in the system. This will search through the stack on the same - * display as the current focused stack, looking for a focusable and visible stack, different - * from the target stack. If no valid candidates will be found, it will then go through all - * displays and stacks in last-focused order. - * - * @param currentFocus The stack that previously had focus. - * @param ignoreCurrent If we should ignore {@param currentFocus} when searching for next - * candidate. - * @return Next focusable {@link ActivityStack}, {@code null} if not found. - */ - ActivityStack getNextFocusableStackLocked(@NonNull ActivityStack currentFocus, - boolean ignoreCurrent) { - // First look for next focusable stack on the same display - final ActivityDisplay preferredDisplay = currentFocus.getDisplay(); - final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack( - currentFocus, ignoreCurrent); - if (preferredFocusableStack != null) { - return preferredFocusableStack; - } - if (preferredDisplay.supportsSystemDecorations()) { - // Stop looking for focusable stack on other displays because the preferred display - // supports system decorations. Home activity would be launched on the same display if - // no focusable stack found. - return null; - } - - // Now look through all displays - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - if (display == preferredDisplay) { - // We've already checked this one - continue; - } - final ActivityStack nextFocusableStack = display.getNextFocusableStack(currentFocus, - ignoreCurrent); - if (nextFocusableStack != null) { - return nextFocusableStack; - } - } - - return null; - } - - /** - * Get next valid stack for launching provided activity in the system. This will search across - * displays and stacks in last-focused order for a focusable and visible stack, except those - * that are on a currently focused display. - * - * @param r The activity that is being launched. - * @param currentFocus The display that previously had focus and thus needs to be ignored when - * searching for the next candidate. - * @return Next valid {@link ActivityStack}, null if not found. - */ - ActivityStack getNextValidLaunchStackLocked(@NonNull ActivityRecord r, int currentFocus) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - if (display.mDisplayId == currentFocus) { - continue; - } - final ActivityStack stack = getValidLaunchStackOnDisplay(display.mDisplayId, r, - null /* options */, null /* launchParams */); - if (stack != null) { - return stack; - } - } - return null; - } - - ActivityRecord getDefaultDisplayHomeActivity() { - return getDefaultDisplayHomeActivityForUser(mCurrentUser); - } - - ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) { - return getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId); - } - - void resizeStackLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds, - Rect tempTaskInsetBounds, boolean preserveWindows, boolean allowResizeInDockedMode, - boolean deferResume) { - - if (stack.inSplitScreenPrimaryWindowingMode()) { - resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null, - preserveWindows, deferResume); - return; - } - - final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenPrimaryStack(); - if (!allowResizeInDockedMode - && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) { - // If the docked stack exists, don't resize non-floating stacks independently of the - // size computed from the docked stack size (otherwise they will be out of sync) - return; - } - - Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stack.mStackId); - mWindowManager.deferSurfaceLayout(); - try { - if (stack.affectedBySplitScreenResize()) { - if (bounds == null && stack.inSplitScreenWindowingMode()) { - // null bounds = fullscreen windowing mode...at least for now. - stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - } else if (splitScreenActive) { - // If we are in split-screen mode and this stack support split-screen, then - // it should be split-screen secondary mode. i.e. adjacent to the docked stack. - stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - } - } - stack.resize(bounds, tempTaskBounds, tempTaskInsetBounds); - if (!deferResume) { - stack.ensureVisibleActivitiesConfigurationLocked( - stack.topRunningActivityLocked(), preserveWindows); - } - } finally { - mWindowManager.continueSurfaceLayout(); - Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); - } - } - - void deferUpdateRecentsHomeStackBounds() { - deferUpdateBounds(ACTIVITY_TYPE_RECENTS); - deferUpdateBounds(ACTIVITY_TYPE_HOME); - } - - void deferUpdateBounds(int activityType) { - final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); - if (stack != null) { - stack.deferUpdateBounds(); - } + private void deferUpdateRecentsHomeStackBounds() { + mRootActivityContainer.deferUpdateBounds(ACTIVITY_TYPE_RECENTS); + mRootActivityContainer.deferUpdateBounds(ACTIVITY_TYPE_HOME); } - void continueUpdateRecentsHomeStackBounds() { - continueUpdateBounds(ACTIVITY_TYPE_RECENTS); - continueUpdateBounds(ACTIVITY_TYPE_HOME); - } - - void continueUpdateBounds(int activityType) { - final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); - if (stack != null) { - stack.continueUpdateBounds(); - } + private void continueUpdateRecentsHomeStackBounds() { + mRootActivityContainer.continueUpdateBounds(ACTIVITY_TYPE_RECENTS); + mRootActivityContainer.continueUpdateBounds(ACTIVITY_TYPE_HOME); } void notifyAppTransitionDone() { continueUpdateRecentsHomeStackBounds(); for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) { final int taskId = mResizingTasksDuringAnimation.valueAt(i); - final TaskRecord task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY); + final TaskRecord task = + mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task != null) { task.setTaskDockedResizing(false); } @@ -2766,7 +1471,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D try { final int windowingMode = fromStack.getWindowingMode(); final boolean inPinnedWindowingMode = windowingMode == WINDOWING_MODE_PINNED; - final ActivityDisplay toDisplay = getActivityDisplay(toDisplayId); + final ActivityDisplay toDisplay = + mRootActivityContainer.getActivityDisplay(toDisplayId); if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Tell the display we are exiting split-screen mode. @@ -2823,8 +1529,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); - resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } finally { mAllowDockedStackResize = true; mWindowManager.continueSurfaceLayout(); @@ -2870,7 +1576,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D false /* deferResume */); } - private void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, + void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows, boolean deferResume) { @@ -2879,7 +1585,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - final ActivityStack stack = getDefaultDisplay().getSplitScreenPrimaryStack(); + final ActivityStack stack = + mRootActivityContainer.getDefaultDisplay().getSplitScreenPrimaryStack(); if (stack == null) { Slog.w(TAG, "resizeDockedStackLocked: docked stack not found"); return; @@ -2918,7 +1625,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // static stacks need to be adjusted so they don't overlap with the docked stack. // We get the bounds to use from window manager which has been adjusted for any // screen controls and is also the same for all stacks. - final ActivityDisplay display = getDefaultDisplay(); + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); final Rect otherTaskRect = new Rect(); for (int i = display.getChildCount() - 1; i >= 0; --i) { final ActivityStack current = display.getChildAt(i); @@ -2938,7 +1645,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D tempRect /* outStackBounds */, otherTaskRect /* outTempTaskBounds */); - resizeStackLocked(current, !tempRect.isEmpty() ? tempRect : null, + mRootActivityContainer.resizeStack(current, + !tempRect.isEmpty() ? tempRect : null, !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows, true /* allowResizeInDockedMode */, deferResume); @@ -2956,7 +1664,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) { // TODO(multi-display): Pinned stack display should be passed in. - final PinnedActivityStack stack = getDefaultDisplay().getPinnedStack(); + final PinnedActivityStack stack = + mRootActivityContainer.getDefaultDisplay().getPinnedStack(); if (stack == null) { Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found"); return; @@ -3037,22 +1746,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Removes stacks in the input windowing modes from the system if they are of activity type - * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED - */ - void removeStacksInWindowingModes(int... windowingModes) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - mActivityDisplays.get(i).removeStacksInWindowingModes(windowingModes); - } - } - - void removeStacksWithActivityTypes(int... activityTypes) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - mActivityDisplays.get(i).removeStacksWithActivityTypes(activityTypes); - } - } - - /** * See {@link #removeTaskByIdLocked(int, boolean, boolean, boolean)} */ boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents, @@ -3073,7 +1766,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents, boolean pauseImmediately, String reason) { - final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); + final TaskRecord tr = + mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr != null) { tr.removeTaskActivitiesLocked(pauseImmediately, reason); cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents); @@ -3162,7 +1856,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * @return true if the task has been restored successfully. */ boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions, boolean onTop) { - final ActivityStack stack = getLaunchStack(null, aOptions, task, onTop); + final ActivityStack stack = + mRootActivityContainer.getLaunchStack(null, aOptions, task, onTop); final ActivityStack currentStack = task.getStack(); if (currentStack != null) { // Task has already been restored once. See if we need to do anything more @@ -3204,39 +1899,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Move stack with all its existing content to specified display. - * @param stackId Id of stack to move. - * @param displayId Id of display to move stack to. - * @param onTop Indicates whether container should be place on top or on bottom. - */ - void moveStackToDisplayLocked(int stackId, int displayId, boolean onTop) { - final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId); - if (activityDisplay == null) { - throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown displayId=" - + displayId); - } - final ActivityStack stack = getStack(stackId); - if (stack == null) { - throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown stackId=" - + stackId); - } - - final ActivityDisplay currentDisplay = stack.getDisplay(); - if (currentDisplay == null) { - throw new IllegalStateException("moveStackToDisplayLocked: Stack with stack=" + stack - + " is not attached to any display."); - } - - if (currentDisplay.mDisplayId == displayId) { - throw new IllegalArgumentException("Trying to move stack=" + stack - + " to its current displayId=" + displayId); - } - - stack.reparent(activityDisplay, onTop, false /* displayRemoved */); - // TODO(multi-display): resize stacks properly if moved from split-screen. - } - - /** * Returns the reparent target stack, creating the stack if necessary. This call also enforces * the various checks on tasks that are going to be reparented from one stack to another. */ @@ -3288,159 +1950,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return stack; } - boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect destBounds) { - final ActivityStack stack = getStack(stackId); - if (stack == null) { - throw new IllegalArgumentException( - "moveTopStackActivityToPinnedStackLocked: Unknown stackId=" + stackId); - } - - final ActivityRecord r = stack.topRunningActivityLocked(); - if (r == null) { - Slog.w(TAG, "moveTopStackActivityToPinnedStackLocked: No top running activity" - + " in stack=" + stack); - return false; - } - - if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) { - Slog.w(TAG, - "moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for " - + " r=" + r); - return false; - } - - moveActivityToPinnedStackLocked(r, null /* sourceBounds */, 0f /* aspectRatio */, - "moveTopActivityToPinnedStack"); - return true; - } - - void moveActivityToPinnedStackLocked(ActivityRecord r, Rect sourceHintBounds, float aspectRatio, - String reason) { - - mWindowManager.deferSurfaceLayout(); - - final ActivityDisplay display = r.getStack().getDisplay(); - PinnedActivityStack stack = display.getPinnedStack(); - - // This will clear the pinned stack by moving an existing task to the full screen stack, - // ensuring only one task is present. - if (stack != null) { - moveTasksToFullscreenStackLocked(stack, !ON_TOP); - } - - // Need to make sure the pinned stack exist so we can resize it below... - stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP); - - // Calculate the target bounds here before the task is reparented back into pinned windowing - // mode (which will reset the saved bounds) - final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio); - - try { - final TaskRecord task = r.getTask(); - // Resize the pinned stack to match the current size of the task the activity we are - // going to be moving is currently contained in. We do this to have the right starting - // animation bounds for the pinned stack to the desired bounds the caller wants. - resizeStackLocked(stack, task.getOverrideBounds(), null /* tempTaskBounds */, - null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, - true /* allowResizeInDockedMode */, !DEFER_RESUME); - - if (task.mActivities.size() == 1) { - // Defer resume until below, and do not schedule PiP changes until we animate below - task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, DEFER_RESUME, - false /* schedulePictureInPictureModeChange */, reason); - } else { - // There are multiple activities in the task and moving the top activity should - // reveal/leave the other activities in their original task. - - // Currently, we don't support reparenting activities across tasks in two different - // stacks, so instead, just create a new task in the same stack, reparent the - // activity into that task, and then reparent the whole task to the new stack. This - // ensures that all the necessary work to migrate states in the old and new stacks - // is also done. - final TaskRecord newTask = task.getStack().createTaskRecord( - getNextTaskIdForUserLocked(r.userId), r.info, r.intent, null, null, true); - r.reparent(newTask, MAX_VALUE, "moveActivityToStack"); - - // Defer resume until below, and do not schedule PiP changes until we animate below - newTask.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, - DEFER_RESUME, false /* schedulePictureInPictureModeChange */, reason); - } - - // Reset the state that indicates it can enter PiP while pausing after we've moved it - // to the pinned stack - r.supportsEnterPipOnTaskSwitch = false; - } finally { - mWindowManager.continueSurfaceLayout(); - } - - stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */, - true /* fromFullscreen */); - - // Update the visibility of all activities after the they have been reparented to the new - // stack. This MUST run after the animation above is scheduled to ensure that the windows - // drawn signal is scheduled after the bounds animation start call on the bounds animator - // thread. - ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); - resumeFocusedStacksTopActivitiesLocked(); - - mService.getTaskChangeNotificationController().notifyActivityPinned(r); - } - - ActivityRecord findTaskLocked(ActivityRecord r, int preferredDisplayId) { - if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r); - mTmpFindTaskResult.clear(); - - // Looking up task on preferred display first - final ActivityDisplay preferredDisplay = getActivityDisplay(preferredDisplayId); - if (preferredDisplay != null) { - preferredDisplay.findTaskLocked(r, true /* isPreferredDisplay */, mTmpFindTaskResult); - if (mTmpFindTaskResult.mIdealMatch) { - return mTmpFindTaskResult.mRecord; - } - } - - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - if (display.mDisplayId == preferredDisplayId) { - continue; - } - - display.findTaskLocked(r, false /* isPreferredDisplay */, mTmpFindTaskResult); - if (mTmpFindTaskResult.mIdealMatch) { - return mTmpFindTaskResult.mRecord; - } - } - - if (DEBUG_TASKS && mTmpFindTaskResult.mRecord == null) Slog.d(TAG_TASKS, "No task found"); - return mTmpFindTaskResult.mRecord; - } - - ActivityRecord findActivityLocked(Intent intent, ActivityInfo info, - boolean compareIntentFilters) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final ActivityRecord ar = stack.findActivityLocked( - intent, info, compareIntentFilters); - if (ar != null) { - return ar; - } - } - } - return null; - } - - boolean hasAwakeDisplay() { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - if (!display.shouldSleep()) { - return true; - } - } - return false; - } - void goingToSleepLocked() { scheduleSleepTimeout(); if (!mGoingToSleep.isHeld()) { @@ -3454,24 +1963,19 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - applySleepTokensLocked(false /* applyToStacks */); + mRootActivityContainer.applySleepTokens(false /* applyToStacks */); checkReadyForSleepLocked(true /* allowDelay */); } - void prepareForShutdownLocked() { - for (int i = 0; i < mActivityDisplays.size(); i++) { - createSleepTokenLocked("shutdown", mActivityDisplays.get(i).mDisplayId); - } - } - boolean shutdownLocked(int timeout) { goingToSleepLocked(); boolean timedout = false; final long endTime = System.currentTimeMillis() + timeout; while (true) { - if (!putStacksToSleepLocked(true /* allowDelay */, true /* shuttingDown */)) { + if (!mRootActivityContainer.putStacksToSleep( + true /* allowDelay */, true /* shuttingDown */)) { long timeRemaining = endTime - System.currentTimeMillis(); if (timeRemaining > 0) { try { @@ -3501,51 +2005,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - void applySleepTokensLocked(boolean applyToStacks) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - // Set the sleeping state of the display. - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - final boolean displayShouldSleep = display.shouldSleep(); - if (displayShouldSleep == display.isSleeping()) { - continue; - } - display.setIsSleeping(displayShouldSleep); - - if (!applyToStacks) { - continue; - } - - // Set the sleeping state of the stacks on the display. - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - if (displayShouldSleep) { - stack.goToSleepIfPossible(false /* shuttingDown */); - } else { - stack.awakeFromSleepingLocked(); - if (stack.isFocusedStackOnDisplay() && !getKeyguardController() - .isKeyguardOrAodShowing(display.mDisplayId)) { - // If the keyguard is unlocked - resume immediately. - // It is possible that the display will not be awake at the time we - // process the keyguard going away, which can happen before the sleep token - // is released. As a result, it is important we resume the activity here. - resumeFocusedStacksTopActivitiesLocked(); - } - } - } - - if (displayShouldSleep || mGoingToSleepActivities.isEmpty()) { - continue; - } - // The display is awake now, so clean up the going to sleep list. - for (Iterator<ActivityRecord> it = mGoingToSleepActivities.iterator(); it.hasNext(); ) { - final ActivityRecord r = it.next(); - if (r.getDisplayId() == display.mDisplayId) { - it.remove(); - } - } - } - } - void activitySleptLocked(ActivityRecord r) { mGoingToSleepActivities.remove(r); final ActivityStack s = r.getStack(); @@ -3562,12 +2021,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - if (!putStacksToSleepLocked(allowDelay, false /* shuttingDown */)) { + if (!mRootActivityContainer.putStacksToSleep( + allowDelay, false /* shuttingDown */)) { return; } // Send launch end powerhint before going sleep - sendPowerHintForLaunchEndIfNeeded(); + mRootActivityContainer.sendPowerHintForLaunchEndIfNeeded(); removeSleepTimeouts(); @@ -3579,52 +2039,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - // Tries to put all activity stacks to sleep. Returns true if all stacks were - // successfully put to sleep. - private boolean putStacksToSleepLocked(boolean allowDelay, boolean shuttingDown) { - boolean allSleep = true; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - if (allowDelay) { - allSleep &= stack.goToSleepIfPossible(shuttingDown); - } else { - stack.goToSleep(); - } - } - } - return allSleep; - } - boolean reportResumedActivityLocked(ActivityRecord r) { // A resumed activity cannot be stopping. remove from list mStoppingActivities.remove(r); final ActivityStack stack = r.getStack(); - if (isTopDisplayFocusedStack(stack)) { + if (mRootActivityContainer.isTopDisplayFocusedStack(stack)) { mService.updateUsageStats(r, true); } if (stack.getDisplay().allResumedActivitiesComplete()) { - ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); // Make sure activity & window visibility should be identical // for all displays in this stage. - executeAppTransitionForAllDisplay(); + mRootActivityContainer.executeAppTransitionForAllDisplay(); return true; } return false; } - void handleAppCrashLocked(WindowProcessController app) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.handleAppCrashLocked(app); - } - } - } - // Called when WindowManager has finished animating the launchingBehind activity to the back. private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) { final TaskRecord task = r.getTask(); @@ -3647,157 +2079,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget(); } - /** - * Make sure that all activities that need to be visible in the system actually are and update - * their configuration. - */ - void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, - boolean preserveWindows) { - ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows, - true /* notifyClients */); - } - - /** - * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean) - */ - void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, - boolean preserveWindows, boolean notifyClients) { - getKeyguardController().beginActivityVisibilityUpdate(); - try { - // First the front stacks. In case any are not fullscreen and are in front of home. - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows, - notifyClients); - } - } - } finally { - getKeyguardController().endActivityVisibilityUpdate(); - } - } - - void addStartingWindowsForVisibleActivities(boolean taskSwitch) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.addStartingWindowsForVisibleActivities(taskSwitch); - } - } - } - - void invalidateTaskLayers() { - mTaskLayersChanged = true; - } - - void rankTaskLayersIfNeeded() { - if (!mTaskLayersChanged) { - return; - } - mTaskLayersChanged = false; - for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - int baseLayer = 0; - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - baseLayer += stack.rankTaskLayers(baseLayer); - } - } - } - - void clearOtherAppTimeTrackers(AppTimeTracker except) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.clearOtherAppTimeTrackers(except); - } - } - } - - void scheduleDestroyAllActivities(WindowProcessController app, String reason) { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.scheduleDestroyActivities(app, reason); - } - } - } - - void releaseSomeActivitiesLocked(WindowProcessController app, String reason) { - // Tasks is non-null only if two or more tasks are found. - ArraySet<TaskRecord> tasks = app.getReleaseSomeActivitiesTasks(); - if (tasks == null) { - if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release"); - return; - } - // If we have activities in multiple tasks that are in a position to be destroyed, - // let's iterate through the tasks and release the oldest one. - final int numDisplays = mActivityDisplays.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - final int stackCount = display.getChildCount(); - // Step through all stacks starting from behind, to hit the oldest things first. - for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) { - final ActivityStack stack = display.getChildAt(stackNdx); - // Try to release activities in this stack; if we manage to, we are done. - if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) { - return; - } - } - } - } - - boolean switchUserLocked(int userId, UserState uss) { - final int focusStackId = getTopDisplayFocusedStack().getStackId(); - // We dismiss the docked stack whenever we switch users. - final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenPrimaryStack(); - if (dockedStack != null) { - moveTasksToFullscreenStackLocked(dockedStack, dockedStack.isFocusedStackOnDisplay()); - } - // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will - // also cause all tasks to be moved to the fullscreen stack at a position that is - // appropriate. - removeStacksInWindowingModes(WINDOWING_MODE_PINNED); - - mUserStackInFront.put(mCurrentUser, focusStackId); - final int restoreStackId = - mUserStackInFront.get(userId, getDefaultDisplay().getHomeStack().mStackId); - mCurrentUser = userId; - - mStartingUsers.add(uss); - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.switchUserLocked(userId); - TaskRecord task = stack.topTask(); - if (task != null) { - stack.positionChildWindowContainerAtTop(task); - } - } - } - - ActivityStack stack = getStack(restoreStackId); - if (stack == null) { - stack = getDefaultDisplay().getHomeStack(); - } - final boolean homeInFront = stack.isActivityTypeHome(); - if (stack.isOnHomeDisplay()) { - stack.moveToFront("switchUserOnHomeDisplay"); - } else { - // Stack was moved to another display while user was swapped out. - resumeHomeActivity(null, "switchUserOnOtherDisplay", DEFAULT_DISPLAY); - } - return homeInFront; - } - /** Checks whether the userid is a profile of the current user. */ boolean isCurrentProfileLocked(int userId) { - if (userId == mCurrentUser) return true; + if (userId == mRootActivityContainer.mCurrentUser) return true; return mService.mAmInternal.isCurrentProfile(userId); } @@ -3822,7 +2106,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean remove, boolean processPausingActivities) { ArrayList<ActivityRecord> stops = null; - final boolean nowVisible = allResumedActivitiesVisible(); + final boolean nowVisible = mRootActivityContainer.allResumedActivitiesVisible(); for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) { ActivityRecord s = mStoppingActivities.get(activityNdx); boolean waitingVisible = mActivitiesWaitingForVisibleActivity.contains(s); @@ -3872,134 +2156,26 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return stops; } - void validateTopActivitiesLocked() { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final ActivityRecord r = stack.topRunningActivityLocked(); - final ActivityState state = r == null ? DESTROYED : r.getState(); - if (isTopDisplayFocusedStack(stack)) { - if (r == null) Slog.e(TAG, - "validateTop...: null top activity, stack=" + stack); - else { - final ActivityRecord pausing = stack.mPausingActivity; - if (pausing != null && pausing == r) Slog.e(TAG, - "validateTop...: top stack has pausing activity r=" + r - + " state=" + state); - if (state != INITIALIZING && state != RESUMED) Slog.e(TAG, - "validateTop...: activity in front not resumed r=" + r - + " state=" + state); - } - } else { - final ActivityRecord resumed = stack.getResumedActivity(); - if (resumed != null && resumed == r) Slog.e(TAG, - "validateTop...: back stack has resumed activity r=" + r - + " state=" + state); - if (r != null && (state == INITIALIZING || state == RESUMED)) Slog.e(TAG, - "validateTop...: activity in back resumed r=" + r + " state=" + state); - } - } - } - } - - public void dumpDisplays(PrintWriter pw) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - pw.print("[id:" + display.mDisplayId + " stacks:"); - display.dumpStacks(pw); - pw.print("]"); - } - } - public void dump(PrintWriter pw, String prefix) { pw.println(); pw.println("ActivityStackSupervisor state:"); - pw.print(prefix); - pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack()); + mRootActivityContainer.dump(pw, prefix); pw.print(prefix); pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser); - pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - display.dump(pw, prefix); - } + pw.println(prefix + "mUserStackInFront=" + mRootActivityContainer.mUserStackInFront); if (!mWaitingForActivityVisible.isEmpty()) { - pw.print(prefix); pw.println("mWaitingForActivityVisible="); + pw.println(prefix + "mWaitingForActivityVisible="); for (int i = 0; i < mWaitingForActivityVisible.size(); ++i) { - pw.print(prefix); pw.print(prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix); + pw.print(prefix + prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix); } } pw.print(prefix); pw.print("isHomeRecentsComponent="); - pw.print(mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); + pw.print(mRecentTasks.isRecentsComponentHomeActivity(mRootActivityContainer.mCurrentUser)); getKeyguardController().dump(pw, prefix); mService.getLockTaskController().dump(pw, prefix); } - public void writeToProto(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */); - for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { - final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); - activityDisplay.writeToProto(proto, DISPLAYS); - } - getKeyguardController().writeToProto(proto, KEYGUARD_CONTROLLER); - // TODO(b/111541062): Update tests to look for resumed activities on all displays - final ActivityStack focusedStack = getTopDisplayFocusedStack(); - if (focusedStack != null) { - proto.write(FOCUSED_STACK_ID, focusedStack.mStackId); - final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity(); - if (focusedActivity != null) { - focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); - } - } else { - proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); - } - proto.write(IS_HOME_RECENTS_COMPONENT, - mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); - mService.getActivityStartController().writeToProto(proto, PENDING_ACTIVITIES); - proto.end(token); - } - - /** - * Dump all connected displays' configurations. - * @param prefix Prefix to apply to each line of the dump. - */ - void dumpDisplayConfigs(PrintWriter pw, String prefix) { - pw.print(prefix); pw.println("Display override configurations:"); - final int displayCount = mActivityDisplays.size(); - for (int i = 0; i < displayCount; i++) { - final ActivityDisplay activityDisplay = mActivityDisplays.get(i); - pw.print(prefix); pw.print(" "); pw.print(activityDisplay.mDisplayId); pw.print(": "); - pw.println(activityDisplay.getOverrideConfiguration()); - } - } - - /** - * Dumps the activities matching the given {@param name} in the either the focused stack - * or all visible stacks if {@param dumpVisibleStacks} is true. - */ - ArrayList<ActivityRecord> getDumpActivitiesLocked(String name, boolean dumpVisibleStacksOnly, - boolean dumpFocusedStackOnly) { - if (dumpFocusedStackOnly) { - return getTopDisplayFocusedStack().getDumpActivitiesLocked(name); - } else { - ArrayList<ActivityRecord> activities = new ArrayList<>(); - int numDisplays = mActivityDisplays.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { - activities.addAll(stack.getDumpActivitiesLocked(name)); - } - } - } - return activities; - } - } - static boolean printThisActivity(PrintWriter pw, ActivityRecord activity, String dumpPackage, boolean needSep, String prefix) { if (activity != null) { @@ -4015,73 +2191,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } - boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll, - boolean dumpClient, String dumpPackage) { - boolean printed = false; - boolean needSep = false; - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); - pw.print("Display #"); pw.print(activityDisplay.mDisplayId); - pw.println(" (activities from top to bottom):"); - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - pw.println(); - pw.println(" Stack #" + stack.mStackId - + ": type=" + activityTypeToString(stack.getActivityType()) - + " mode=" + windowingModeToString(stack.getWindowingMode())); - pw.println(" isSleeping=" + stack.shouldSleepActivities()); - pw.println(" mBounds=" + stack.getOverrideBounds()); - - printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, - needSep); - - printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, - !dumpAll, false, dumpPackage, true, - " Running activities (most recent first):", null); - - needSep = printed; - boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, - " mPausingActivity: "); - if (pr) { - printed = true; - needSep = false; - } - pr = printThisActivity(pw, stack.getResumedActivity(), dumpPackage, needSep, - " mResumedActivity: "); - if (pr) { - printed = true; - needSep = false; - } - if (dumpAll) { - pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, - " mLastPausedActivity: "); - if (pr) { - printed = true; - needSep = true; - } - printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, - needSep, " mLastNoHistoryActivity: "); - } - needSep = printed; - } - printThisActivity(pw, activityDisplay.getResumedActivity(), dumpPackage, needSep, - " ResumedActivity:"); - } - - printed |= dumpHistoryList(fd, pw, mFinishingActivities, " ", "Fin", false, !dumpAll, - false, dumpPackage, true, " Activities waiting to finish:", null); - printed |= dumpHistoryList(fd, pw, mStoppingActivities, " ", "Stop", false, !dumpAll, - false, dumpPackage, true, " Activities waiting to stop:", null); - printed |= dumpHistoryList(fd, pw, mActivitiesWaitingForVisibleActivity, " ", "Wait", - false, !dumpAll, false, dumpPackage, true, - " Activities waiting for another to become visible:", null); - printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, " ", "Sleep", false, !dumpAll, - false, dumpPackage, true, " Activities waiting to sleep:", null); - - return printed; - } - static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list, String prefix, String label, boolean complete, boolean brief, boolean client, String dumpPackage, boolean needNL, String header, TaskRecord lastTask) { @@ -4191,294 +2300,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT); } - @Override - public void onDisplayAdded(int displayId) { - if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId); - synchronized (mService.mGlobalLock) { - getActivityDisplayOrCreateLocked(displayId); - // Do not start home before booting, or it may accidentally finish booting before it - // starts. Instead, we expect home activities to be launched when the system is ready - // (ActivityManagerService#systemReady). - if (mService.isBooted() || mService.isBooting()) { - startHomeOnDisplay(mCurrentUser, "displayAdded", displayId); - } - } - } - - @Override - public void onDisplayRemoved(int displayId) { - if (DEBUG_STACK) Slog.v(TAG, "Display removed displayId=" + displayId); - if (displayId == DEFAULT_DISPLAY) { - throw new IllegalArgumentException("Can't remove the primary display."); - } - - synchronized (mService.mGlobalLock) { - final ActivityDisplay activityDisplay = getActivityDisplay(displayId); - if (activityDisplay == null) { - return; - } - - activityDisplay.remove(); - } - } - - @Override - public void onDisplayChanged(int displayId) { - if (DEBUG_STACK) Slog.v(TAG, "Display changed displayId=" + displayId); - synchronized (mService.mGlobalLock) { - final ActivityDisplay activityDisplay = getActivityDisplay(displayId); - if (activityDisplay != null) { - activityDisplay.onDisplayChanged(); - } - } - } - - /** Check if display with specified id is added to the list. */ - boolean isDisplayAdded(int displayId) { - return getActivityDisplayOrCreateLocked(displayId) != null; - } - - // TODO: Look into consolidating with getActivityDisplayOrCreateLocked() - ActivityDisplay getActivityDisplay(int displayId) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay activityDisplay = mActivityDisplays.get(i); - if (activityDisplay.mDisplayId == displayId) { - return activityDisplay; - } - } - return null; - } - - // TODO(multi-display): Look at all callpoints to make sure they make sense in multi-display. - ActivityDisplay getDefaultDisplay() { - return mDefaultDisplay; - } - - /** - * Get an existing instance of {@link ActivityDisplay} or create new if there is a - * corresponding record in display manager. - */ - // TODO: Look into consolidating with getActivityDisplay() - ActivityDisplay getActivityDisplayOrCreateLocked(int displayId) { - ActivityDisplay activityDisplay = getActivityDisplay(displayId); - if (activityDisplay != null) { - return activityDisplay; - } - if (mDisplayManager == null) { - // The system isn't fully initialized yet. - return null; - } - final Display display = mDisplayManager.getDisplay(displayId); - if (display == null) { - // The display is not registered in DisplayManager. - return null; - } - // The display hasn't been added to ActivityManager yet, create a new record now. - activityDisplay = new ActivityDisplay(this, display); - addChild(activityDisplay, ActivityDisplay.POSITION_BOTTOM); - return activityDisplay; - } - - /** - * Get an existing instance of {@link ActivityDisplay} that has the given uniqueId. Unique ID is - * defined in {@link DisplayInfo#uniqueId}. - * - * @param uniqueId the unique ID of the display - * @return the {@link ActivityDisplay} or {@code null} if nothing is found. - */ - ActivityDisplay getActivityDisplay(String uniqueId) { - for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { - final ActivityDisplay display = mActivityDisplays.get(i); - final boolean isValid = display.mDisplay.isValid(); - if (isValid && display.mDisplay.getUniqueId().equals(uniqueId)) { - return display; - } - } - - return null; - } - - boolean startHomeOnAllDisplays(int userId, String reason) { - boolean homeStarted = false; - for (int i = mActivityDisplays.size() - 1; i >= 0; i--) { - final int displayId = mActivityDisplays.get(i).mDisplayId; - homeStarted |= startHomeOnDisplay(userId, reason, displayId); - } - return homeStarted; - } - - /** - * This starts home activity on displays that can have system decorations and only if the - * home activity can have multiple instances. - */ - boolean startHomeOnDisplay(int userId, String reason, int displayId) { - final Intent homeIntent = mService.getHomeIntent(); - final ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent); - if (aInfo == null) { - return false; - } - - if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) { - return false; - } - - // Update the reason for ANR debugging to verify if the user activity is the one that - // actually launched. - final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId( - aInfo.applicationInfo.uid); - mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, - displayId); - return true; - } - - /** - * This resolves the home activity info and updates the home component of the given intent. - * @return the home activity info if any. - */ - private ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) { - final int flags = ActivityManagerService.STOCK_PM_FLAGS; - final ComponentName comp = homeIntent.getComponent(); - ActivityInfo aInfo = null; - try { - if (comp != null) { - // Factory test. - aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId); - } else { - final String resolvedType = - homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver()); - final ResolveInfo info = AppGlobals.getPackageManager() - .resolveIntent(homeIntent, resolvedType, flags, userId); - if (info != null) { - aInfo = info.activityInfo; - } - } - } catch (RemoteException e) { - // ignore - } - - if (aInfo == null) { - Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable()); - return null; - } - - homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); - aInfo = new ActivityInfo(aInfo); - aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId); - homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK); - return aInfo; - } - - @VisibleForTesting - void addChild(ActivityDisplay activityDisplay, int position) { - positionChildAt(activityDisplay, position); - mWindowContainerController.positionChildAt( - activityDisplay.getWindowContainerController(), position); - } - - void removeChild(ActivityDisplay activityDisplay) { - // The caller must tell the controller of {@link ActivityDisplay} to release its container - // {@link DisplayContent}. That is done in {@link ActivityDisplay#releaseSelfIfNeeded}). - mActivityDisplays.remove(activityDisplay); - } - - private void calculateDefaultMinimalSizeOfResizeableTasks() { - final Resources res = mService.mContext.getResources(); - final float minimalSize = res.getDimension( - com.android.internal.R.dimen.default_minimal_size_resizable_task); - final DisplayMetrics dm = res.getDisplayMetrics(); - - mDefaultMinSizeOfResizeableTaskDp = (int) (minimalSize / dm.density); - } - - SleepToken createSleepTokenLocked(String tag, int displayId) { - final ActivityDisplay display = getActivityDisplay(displayId); - if (display == null) { - throw new IllegalArgumentException("Invalid display: " + displayId); - } - - final SleepTokenImpl token = new SleepTokenImpl(tag, displayId); - mSleepTokens.add(token); - display.mAllSleepTokens.add(token); - return token; - } - - private void removeSleepTokenLocked(SleepTokenImpl token) { - mSleepTokens.remove(token); - - final ActivityDisplay display = getActivityDisplay(token.mDisplayId); - if (display != null) { - display.mAllSleepTokens.remove(token); - if (display.mAllSleepTokens.isEmpty()) { - mService.updateSleepIfNeededLocked(); - } - } - } - - private StackInfo getStackInfo(ActivityStack stack) { - final int displayId = stack.mDisplayId; - final ActivityDisplay display = getActivityDisplay(displayId); - StackInfo info = new StackInfo(); - stack.getWindowContainerBounds(info.bounds); - info.displayId = displayId; - info.stackId = stack.mStackId; - info.userId = stack.mCurrentUser; - info.visible = stack.shouldBeVisible(null); - // A stack might be not attached to a display. - info.position = display != null ? display.getIndexOf(stack) : 0; - info.configuration.setTo(stack.getConfiguration()); - - ArrayList<TaskRecord> tasks = stack.getAllTasks(); - final int numTasks = tasks.size(); - int[] taskIds = new int[numTasks]; - String[] taskNames = new String[numTasks]; - Rect[] taskBounds = new Rect[numTasks]; - int[] taskUserIds = new int[numTasks]; - for (int i = 0; i < numTasks; ++i) { - final TaskRecord task = tasks.get(i); - taskIds[i] = task.taskId; - taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString() - : task.realActivity != null ? task.realActivity.flattenToString() - : task.getTopActivity() != null ? task.getTopActivity().packageName - : "unknown"; - taskBounds[i] = new Rect(); - task.getWindowContainerBounds(taskBounds[i]); - taskUserIds[i] = task.userId; - } - info.taskIds = taskIds; - info.taskNames = taskNames; - info.taskBounds = taskBounds; - info.taskUserIds = taskUserIds; - - final ActivityRecord top = stack.topRunningActivityLocked(); - info.topActivity = top != null ? top.intent.getComponent() : null; - return info; - } - - StackInfo getStackInfo(int stackId) { - ActivityStack stack = getStack(stackId); - if (stack != null) { - return getStackInfo(stack); - } - return null; - } - - StackInfo getStackInfo(int windowingMode, int activityType) { - final ActivityStack stack = getStack(windowingMode, activityType); - return (stack != null) ? getStackInfo(stack) : null; - } - - ArrayList<StackInfo> getAllStackInfosLocked() { - ArrayList<StackInfo> list = new ArrayList<>(); - for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - list.add(getStackInfo(stack)); - } - } - return list; - } - void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode, int preferredDisplayId, ActivityStack actualStack) { handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId, @@ -4624,21 +2445,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - void setDockedStackMinimized(boolean minimized) { - // Get currently focused stack before setting mIsDockMinimized. We do this because if - // split-screen is active, primary stack will not be focusable (see #isFocusable) while - // still occluding other stacks. This will cause getTopDisplayFocusedStack() to return null. - final ActivityStack current = getTopDisplayFocusedStack(); - mIsDockMinimized = minimized; - if (mIsDockMinimized) { - if (current.inSplitScreenPrimaryWindowingMode()) { - // The primary split-screen stack can't be focused while it is minimize, so move - // focus to something else. - current.adjustFocusToNextFocusableStack("setDockedStackMinimized"); - } - } - } - void wakeUp(String reason) { mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.am:TURN_ON:" + reason); } @@ -4657,10 +2463,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mDeferResumeCount--; } - /** - * @return True if resume can be called. - */ - private boolean readyToResume() { + /** @return True if resume can be called. */ + boolean readyToResume() { return mDeferResumeCount == 0; } @@ -4712,7 +2516,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } break; case RESUME_TOP_ACTIVITY_MSG: { synchronized (mService.mGlobalLock) { - resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } break; case SLEEP_TIMEOUT_MSG: { @@ -4748,19 +2552,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - ActivityStack findStackBehind(ActivityStack stack) { - final ActivityDisplay display = getActivityDisplay(stack.mDisplayId); - if (display != null) { - for (int i = display.getChildCount() - 1; i >= 0; i--) { - if (display.getChildAt(i) == stack && i > 0) { - return display.getChildAt(i - 1); - } - } - } - throw new IllegalStateException("Failed to find a stack behind stack=" + stack - + " in=" + display); - } - /** * Puts a task into resizing mode during the next app transition. * @@ -4805,8 +2596,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false); } - task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, - activityOptions, ON_TOP); + task = mRootActivityContainer.anyTaskForId(taskId, + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP); if (task == null) { continueUpdateRecentsHomeStackBounds(); mWindowManager.executeAppTransition(); @@ -4819,7 +2610,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // from whatever is started from the recents activity, so move the home stack // forward. // TODO (b/115289124): Multi-display supports for recents. - getDefaultDisplay().moveHomeStackToFront("startActivityFromRecents"); + mRootActivityContainer.getDefaultDisplay().moveHomeStackToFront( + "startActivityFromRecents"); } // If the user must confirm credentials (e.g. when first launching a work app and the @@ -4828,7 +2620,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D && task.getRootActivity() != null) { final ActivityRecord targetActivity = task.getTopActivity(); - sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, targetActivity); + mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded( + true /* forceSend */, targetActivity); mActivityMetricsLogger.notifyActivityLaunching(task.intent); try { mService.moveTaskToFrontLocked(task.taskId, 0, options, @@ -4881,35 +2674,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * @return a list of activities which are the top ones in each visible stack. The first - * entry will be the focused activity. - */ - List<IBinder> getTopVisibleActivities() { - final ArrayList<IBinder> topActivityTokens = new ArrayList<>(); - final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); - // Traverse all displays. - for (int i = mActivityDisplays.size() - 1; i >= 0; i--) { - final ActivityDisplay display = mActivityDisplays.get(i); - // Traverse all stacks on a display. - for (int j = display.getChildCount() - 1; j >= 0; --j) { - final ActivityStack stack = display.getChildAt(j); - // Get top activity from a visible stack and add it to the list. - if (stack.shouldBeVisible(null /* starting */)) { - final ActivityRecord top = stack.getTopActivity(); - if (top != null) { - if (stack == topFocusedStack) { - topActivityTokens.add(0, top.appToken); - } else { - topActivityTokens.add(top.appToken); - } - } - } - } - } - return topActivityTokens; - } - - /** * Internal container to store a match qualifier alongside a WaitResult. */ static class WaitInfo { @@ -4947,30 +2711,4 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mResult.dump(pw, prefix); } } - - private final class SleepTokenImpl extends SleepToken { - private final String mTag; - private final long mAcquireTime; - private final int mDisplayId; - - public SleepTokenImpl(String tag, int displayId) { - mTag = tag; - mDisplayId = displayId; - mAcquireTime = SystemClock.uptimeMillis(); - } - - @Override - public void release() { - synchronized (mService.mGlobalLock) { - removeSleepTokenLocked(this); - } - } - - @Override - public String toString() { - return "{\"" + mTag + "\", display " + mDisplayId - + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}"; - } - } - } diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index ee5a43ce0edb..54a63a168588 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -70,6 +70,7 @@ class ActivityStartInterceptor { private final ActivityTaskManagerService mService; private final ActivityStackSupervisor mSupervisor; + private final RootActivityContainer mRootActivityContainer; private final Context mServiceContext; // UserManager cannot be final as it's not ready when this class is instantiated during boot @@ -102,14 +103,15 @@ class ActivityStartInterceptor { ActivityStartInterceptor( ActivityTaskManagerService service, ActivityStackSupervisor supervisor) { - this(service, supervisor, service.mContext); + this(service, supervisor, service.mRootActivityContainer, service.mContext); } @VisibleForTesting ActivityStartInterceptor(ActivityTaskManagerService service, ActivityStackSupervisor supervisor, - Context context) { + RootActivityContainer root, Context context) { mService = service; mSupervisor = supervisor; + mRootActivityContainer = root; mServiceContext = context; } @@ -279,7 +281,7 @@ class ActivityStartInterceptor { mActivityOptions = ActivityOptions.makeBasic(); } - ActivityRecord homeActivityRecord = mSupervisor.getDefaultDisplayHomeActivity(); + ActivityRecord homeActivityRecord = mRootActivityContainer.getDefaultDisplayHomeActivity(); if (homeActivityRecord != null && homeActivityRecord.getTask() != null) { // Showing credential confirmation activity in home task to avoid stopping multi-windowed // mode after showing the full-screen credential confirmation activity. diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index d4c1bcad57b3..d22623eeb14d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -137,6 +137,7 @@ class ActivityStarter { private static final int INVALID_LAUNCH_MODE = -1; private final ActivityTaskManagerService mService; + private final RootActivityContainer mRootActivityContainer; private final ActivityStackSupervisor mSupervisor; private final ActivityStartInterceptor mInterceptor; private final ActivityStartController mController; @@ -421,6 +422,7 @@ class ActivityStarter { ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) { mController = controller; mService = service; + mRootActivityContainer = service.mRootActivityContainer; mSupervisor = supervisor; mInterceptor = interceptor; reset(true); @@ -617,7 +619,7 @@ class ActivityStarter { ActivityRecord sourceRecord = null; ActivityRecord resultRecord = null; if (resultTo != null) { - sourceRecord = mSupervisor.isInAnyStackLocked(resultTo); + sourceRecord = mRootActivityContainer.isInAnyStack(resultTo); if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord); if (sourceRecord != null) { @@ -811,7 +813,8 @@ class ActivityStarter { null /*profilerInfo*/); if (DEBUG_PERMISSIONS_REVIEW) { - final ActivityStack focusedStack = mSupervisor.getTopDisplayFocusedStack(); + final ActivityStack focusedStack = + mRootActivityContainer.getTopDisplayFocusedStack(); Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + "} from uid " + callingUid + " on display " + (focusedStack == null ? DEFAULT_DISPLAY : focusedStack.mDisplayId)); @@ -847,7 +850,7 @@ class ActivityStarter { r.appTimeTracker = sourceRecord.appTimeTracker; } - final ActivityStack stack = mSupervisor.getTopDisplayFocusedStack(); + final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack(); // If we are starting an activity that is not from the same uid as the currently resumed // one, check whether app switches are allowed. @@ -1063,7 +1066,7 @@ class ActivityStarter { ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); synchronized (mService.mGlobalLock) { - final ActivityStack stack = mSupervisor.getTopDisplayFocusedStack(); + final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack(); stack.mConfigWillChange = globalConfig != null && mService.getGlobalConfiguration().diff(globalConfig) != 0; if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, @@ -1249,7 +1252,8 @@ class ActivityStarter { final ActivityRecord currentTop = startedActivityStack.topRunningActivityLocked(); if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) { - mSupervisor.ensureVisibilityAndConfig(currentTop, currentTop.getDisplayId(), + mRootActivityContainer.ensureVisibilityAndConfig( + currentTop, currentTop.getDisplayId(), true /* markFrozenIfConfigChanged */, false /* deferResume */); } } @@ -1284,7 +1288,7 @@ class ActivityStarter { // Do not start home activity if it cannot be launched on preferred display. We are not // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might // fallback to launch on other displays. - if (r.isActivityTypeHome() && !mSupervisor.canStartHomeOnDisplay(r.info, + if (r.isActivityTypeHome() && !mRootActivityContainer.canStartHomeOnDisplay(r.info, mPreferredDisplayId, true /* allowInstrumenting */)) { Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId); return START_CANCELED; @@ -1361,7 +1365,8 @@ class ActivityStarter { } } - mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity); + mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded + (false /* forceSend */, reusedActivity); reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity); @@ -1413,7 +1418,7 @@ class ActivityStarter { // If the activity being launched is the same as the one currently at the top, then // we need to check if it should only be launched once. - final ActivityStack topStack = mSupervisor.getTopDisplayFocusedStack(); + final ActivityStack topStack = mRootActivityContainer.getTopDisplayFocusedStack(); final ActivityRecord topFocused = topStack.getTopActivity(); final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop); final boolean dontStart = top != null && mStartActivity.resultTo == null @@ -1430,7 +1435,7 @@ class ActivityStarter { // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; if (mDoResume) { - mSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } ActivityOptions.abort(mOptions); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { @@ -1485,7 +1490,8 @@ class ActivityStarter { EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask()); mTargetStack.mLastPausedActivity = null; - mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity); + mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded( + false /* forceSend */, mStartActivity); mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition, mOptions); @@ -1512,16 +1518,16 @@ class ActivityStarter { // task stack to be focusable, then ensure that we now update the focused stack // accordingly. if (mTargetStack.isFocusable() - && !mSupervisor.isTopDisplayFocusedStack(mTargetStack)) { + && !mRootActivityContainer.isTopDisplayFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked"); } - mSupervisor.resumeFocusedStacksTopActivitiesLocked(mTargetStack, mStartActivity, - mOptions); + mRootActivityContainer.resumeFocusedStacksTopActivities( + mTargetStack, mStartActivity, mOptions); } } else if (mStartActivity != null) { mSupervisor.mRecentTasks.add(mStartActivity.getTask()); } - mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack); + mRootActivityContainer.updateUserStack(mStartActivity.userId, mTargetStack); mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode, mPreferredDisplayId, mTargetStack); @@ -1642,7 +1648,7 @@ class ActivityStarter { if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) { r.mTaskOverlay = true; if (!mOptions.canTaskOverlayResume()) { - final TaskRecord task = mSupervisor.anyTaskForIdLocked( + final TaskRecord task = mRootActivityContainer.anyTaskForId( mOptions.getLaunchTaskId()); final ActivityRecord top = task != null ? task.getTopActivity() : null; if (top != null && !top.isState(RESUMED)) { @@ -1678,7 +1684,7 @@ class ActivityStarter { if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { ActivityRecord checkedCaller = sourceRecord; if (checkedCaller == null) { - checkedCaller = mSupervisor.getTopDisplayFocusedStack() + checkedCaller = mRootActivityContainer.getTopDisplayFocusedStack() .topRunningNonDelayedActivityLocked(mNotTop); } if (!checkedCaller.realActivity.equals(r.realActivity)) { @@ -1840,26 +1846,28 @@ class ActivityStarter { putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null; ActivityRecord intentActivity = null; if (mOptions != null && mOptions.getLaunchTaskId() != -1) { - final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId()); + final TaskRecord task = mRootActivityContainer.anyTaskForId(mOptions.getLaunchTaskId()); intentActivity = task != null ? task.getTopActivity() : null; } else if (putIntoExistingTask) { if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) { // There can be one and only one instance of single instance activity in the // history, and it is always in its own unique task, so we do a special search. - intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, + intentActivity = mRootActivityContainer.findActivity(mIntent, mStartActivity.info, mStartActivity.isActivityTypeHome()); } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { // For the launch adjacent case we only want to put the activity in an existing // task if the activity already exists in the history. - intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, + intentActivity = mRootActivityContainer.findActivity(mIntent, mStartActivity.info, !(LAUNCH_SINGLE_TASK == mLaunchMode)); } else { // Otherwise find the best task to put the activity in. - intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId); + intentActivity = + mRootActivityContainer.findTask(mStartActivity, mPreferredDisplayId); } } - if (mStartActivity.isActivityTypeHome() && intentActivity != null + if (intentActivity != null + && (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome()) && intentActivity.getDisplayId() != mPreferredDisplayId) { // Do not reuse home activity on other displays. intentActivity = null; @@ -2066,11 +2074,11 @@ class ActivityStarter { private void resumeTargetStackIfNeeded() { if (mDoResume) { - mSupervisor.resumeFocusedStacksTopActivitiesLocked(mTargetStack, null, mOptions); + mRootActivityContainer.resumeFocusedStacksTopActivities(mTargetStack, null, mOptions); } else { ActivityOptions.abort(mOptions); } - mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack); + mRootActivityContainer.updateUserStack(mStartActivity.userId, mTargetStack); } private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) { @@ -2144,13 +2152,13 @@ class ActivityStarter { // be not suitable. Let's check other displays. if (mTargetStack == null && targetDisplayId != sourceStack.mDisplayId) { // Can't use target display, lets find a stack on the source display. - mTargetStack = mSupervisor.getValidLaunchStackOnDisplay( + mTargetStack = mRootActivityContainer.getValidLaunchStackOnDisplay( sourceStack.mDisplayId, mStartActivity, mOptions, mLaunchParams); } if (mTargetStack == null) { // There are no suitable stacks on the target and source display(s). Look on all // displays. - mTargetStack = mSupervisor.getNextValidLaunchStackLocked( + mTargetStack = mRootActivityContainer.getNextValidLaunchStack( mStartActivity, -1 /* currentFocus */); } } @@ -2181,7 +2189,7 @@ class ActivityStarter { // For paranoia, make sure we have correctly resumed the top activity. mTargetStack.mLastPausedActivity = null; if (mDoResume) { - mSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } ActivityOptions.abort(mOptions); return START_DELIVERED_TO_TOP; @@ -2199,7 +2207,7 @@ class ActivityStarter { deliverNewIntent(top); mTargetStack.mLastPausedActivity = null; if (mDoResume) { - mSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } return START_DELIVERED_TO_TOP; } @@ -2253,7 +2261,8 @@ class ActivityStarter { if (!mLaunchParams.mBounds.isEmpty()) { // TODO: Shouldn't we already know what stack to use by the time we get here? - ActivityStack stack = mSupervisor.getLaunchStack(null, null, mInTask, ON_TOP); + ActivityStack stack = mRootActivityContainer.getLaunchStack( + null, null, mInTask, ON_TOP); if (stack != mInTask.getStack()) { mInTask.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME, "inTaskToFront"); @@ -2347,7 +2356,7 @@ class ActivityStarter { } final ActivityStack currentStack = task != null ? task.getStack() : null; - final ActivityStack focusedStack = mSupervisor.getTopDisplayFocusedStack(); + final ActivityStack focusedStack = mRootActivityContainer.getTopDisplayFocusedStack(); if (currentStack != null) { if (focusedStack != currentStack) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, @@ -2368,18 +2377,18 @@ class ActivityStarter { if (mPreferredDisplayId != DEFAULT_DISPLAY) { // Try to put the activity in a stack on a secondary display. - stack = mSupervisor.getValidLaunchStackOnDisplay(mPreferredDisplayId, r, aOptions, - mLaunchParams); + stack = mRootActivityContainer.getValidLaunchStackOnDisplay( + mPreferredDisplayId, r, aOptions, mLaunchParams); if (stack == null) { // If source display is not suitable - look for topmost valid stack in the system. if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: Can't launch on mPreferredDisplayId=" + mPreferredDisplayId + ", looking on all displays."); - stack = mSupervisor.getNextValidLaunchStackLocked(r, mPreferredDisplayId); + stack = mRootActivityContainer.getNextValidLaunchStack(r, mPreferredDisplayId); } } if (stack == null) { - stack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP); + stack = mRootActivityContainer.getLaunchStack(r, aOptions, task, ON_TOP); } if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r=" + r + " stackId=" + stack.mStackId); @@ -2389,7 +2398,7 @@ class ActivityStarter { /** Check if provided activity record can launch in currently focused stack. */ // TODO: This method can probably be consolidated into getLaunchStack() below. private boolean canLaunchIntoFocusedStack(ActivityRecord r, boolean newTask) { - final ActivityStack focusedStack = mSupervisor.getTopDisplayFocusedStack(); + final ActivityStack focusedStack = mRootActivityContainer.getTopDisplayFocusedStack(); final boolean canUseFocusedStack; if (focusedStack.isActivityTypeAssistant()) { canUseFocusedStack = r.isActivityTypeAssistant(); @@ -2435,14 +2444,14 @@ class ActivityStarter { // full resolution. mLaunchParams.mPreferredDisplayId = mPreferredDisplayId != DEFAULT_DISPLAY ? mPreferredDisplayId : INVALID_DISPLAY; - final ActivityStack stack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP, - mLaunchParams); + final ActivityStack stack = + mRootActivityContainer.getLaunchStack(r, aOptions, task, ON_TOP, mLaunchParams); mLaunchParams.mPreferredDisplayId = mPreferredDisplayId; return stack; } // Otherwise handle adjacent launch. - final ActivityStack focusedStack = mSupervisor.getTopDisplayFocusedStack(); + final ActivityStack focusedStack = mRootActivityContainer.getTopDisplayFocusedStack(); // The parent activity doesn't want to launch the activity on top of itself, but // instead tries to put it onto other side in side-by-side mode. final ActivityStack parentStack = task != null ? task.getStack(): focusedStack; @@ -2460,7 +2469,8 @@ class ActivityStarter { if (parentStack != null && parentStack.inSplitScreenPrimaryWindowingMode()) { // If parent was in docked stack, the natural place to launch another activity // will be fullscreen, so it can appear alongside the docked window. - final int activityType = mSupervisor.resolveActivityType(r, mOptions, task); + final int activityType = + mRootActivityContainer.resolveActivityType(r, mOptions, task); return parentStack.getDisplay().getOrCreateStack( WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, activityType, ON_TOP); } else { @@ -2468,10 +2478,10 @@ class ActivityStarter { // and if yes, we will launch into that stack. If not, we just put the new // activity into parent's stack, because we can't find a better place. final ActivityStack dockedStack = - mSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); + mRootActivityContainer.getDefaultDisplay().getSplitScreenPrimaryStack(); if (dockedStack != null && !dockedStack.shouldBeVisible(r)) { // There is a docked stack, but it isn't visible, so we can't launch into that. - return mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP); + return mRootActivityContainer.getLaunchStack(r, aOptions, task, ON_TOP); } else { return dockedStack; } @@ -2659,7 +2669,7 @@ class ActivityStarter { prefix = prefix + " "; pw.print(prefix); pw.print("mCurrentUser="); - pw.println(mSupervisor.mCurrentUser); + pw.println(mRootActivityContainer.mCurrentUser); pw.print(prefix); pw.print("mLastStartReason="); pw.println(mLastStartReason); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 4f01d699d248..d480fb732df3 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -91,8 +91,6 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.Scr .PACKAGE; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; -import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY; -import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; @@ -122,6 +120,8 @@ import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRA import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_ONLY; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; @@ -341,7 +341,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ActivityManagerInternal mAmInternal; UriGrantsManagerInternal mUgmInternal; private PackageManagerInternal mPmInternal; - private ActivityTaskManagerInternal mInternal; + @VisibleForTesting + final ActivityTaskManagerInternal mInternal; PowerManagerInternal mPowerManagerInternal; private UsageStatsManagerInternal mUsageStatsInternal; @@ -351,6 +352,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /* Global service lock used by the package the owns this service. */ final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock(); ActivityStackSupervisor mStackSupervisor; + RootActivityContainer mRootActivityContainer; WindowManagerService mWindowManager; private UserManagerService mUserManager; private AppOpsService mAppOpsService; @@ -643,6 +645,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mSystemThread = ActivityThread.currentActivityThread(); mUiContext = mSystemThread.getSystemUiContext(); mLifecycleManager = new ClientLifecycleManager(); + mInternal = new LocalService(); GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED); } @@ -764,7 +767,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mTempConfig.setLocales(LocaleList.getDefault()); mConfigurationSeq = mTempConfig.seq = 1; mStackSupervisor = createStackSupervisor(); - mStackSupervisor.onConfigurationChanged(mTempConfig); + mRootActivityContainer = new RootActivityContainer(this); + mRootActivityContainer.onConfigurationChanged(mTempConfig); mTaskChangeNotificationController = new TaskChangeNotificationController(mGlobalLock, mStackSupervisor, mH); @@ -799,6 +803,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mWindowManager = wm; mLockTaskController.setWindowManager(wm); mStackSupervisor.setWindowManager(wm); + mRootActivityContainer.setWindowManager(wm); } } @@ -893,7 +898,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } private void start() { - mInternal = new LocalService(); LocalServices.addService(ActivityTaskManagerInternal.class, mInternal); } @@ -1254,7 +1258,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { sourceToken = resultTo; } - sourceRecord = mStackSupervisor.isInAnyStackLocked(sourceToken); + sourceRecord = mRootActivityContainer.isInAnyStack(sourceToken); if (sourceRecord == null) { throw new SecurityException("Called with bad activity token: " + sourceToken); } @@ -1798,7 +1802,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } final boolean translucentChanged = r.changeWindowTranslucency(true); if (translucentChanged) { - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); } mWindowManager.setAppFullscreen(token, true); return translucentChanged; @@ -1828,7 +1832,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (translucentChanged) { r.getStack().convertActivityToTranslucent(r); } - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); mWindowManager.setAppFullscreen(token, false); return translucentChanged; } @@ -1841,7 +1845,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void notifyActivityDrawn(IBinder token) { if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token); synchronized (mGlobalLock) { - ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token); + ActivityRecord r = mRootActivityContainer.isInAnyStack(token); if (r != null) { r.getStack().notifyActivityDrawnLocked(r); } @@ -1878,7 +1882,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { ActivityStack focusedStack = getTopDisplayFocusedStack(); if (focusedStack != null) { - return mStackSupervisor.getStackInfo(focusedStack.mStackId); + return mRootActivityContainer.getStackInfo(focusedStack.mStackId); } return null; } @@ -1894,14 +1898,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final ActivityStack stack = mStackSupervisor.getStack(stackId); + final ActivityStack stack = mRootActivityContainer.getStack(stackId); if (stack == null) { Slog.w(TAG, "setFocusedStack: No stack with id=" + stackId); return; } final ActivityRecord r = stack.topRunningActivityLocked(); if (r != null && r.moveFocusableActivityToTop("setFocusedStack")) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } } finally { @@ -1916,14 +1920,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task == null) { return; } final ActivityRecord r = task.topRunningActivityLocked(); if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } } finally { @@ -2008,7 +2012,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long origId = Binder.clearCallingIdentity(); try { int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot); - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId); if (task != null) { return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId); } @@ -2026,7 +2030,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Rect rect = new Rect(); try { synchronized (mGlobalLock) { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (task == null) { Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found"); @@ -2057,7 +2061,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { enforceCallerIsRecentsOrHasPermission( MANAGE_ACTIVITY_STACKS, "getTaskDescription()"); - final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id, + final TaskRecord tr = mRootActivityContainer.anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr != null) { return tr.lastTaskDescription; @@ -2077,7 +2081,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task == null) { Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId); @@ -2166,7 +2170,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } final long origId = Binder.clearCallingIdentity(); try { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId); if (task == null) { Slog.d(TAG, "Could not find task for id: "+ taskId); SafeActivityOptions.abort(options); @@ -2283,7 +2287,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(), callingUid); - mStackSupervisor.getRunningTasks(maxNum, list, ignoreActivityType, + mRootActivityContainer.getRunningTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, callingUid, allowed); } @@ -2319,7 +2323,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId); if (task == null) { Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId); return; @@ -2328,7 +2332,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId + " to stackId=" + stackId + " toTop=" + toTop); - final ActivityStack stack = mStackSupervisor.getStack(stackId); + final ActivityStack stack = mRootActivityContainer.getStack(stackId); if (stack == null) { throw new IllegalStateException( "moveTaskToStack: No stack for stackId=" + stackId); @@ -2358,7 +2362,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { synchronized (mGlobalLock) { if (animate) { - final PinnedActivityStack stack = mStackSupervisor.getStack(stackId); + final PinnedActivityStack stack = mRootActivityContainer.getStack(stackId); if (stack == null) { Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); return; @@ -2370,12 +2374,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, animationDuration, false /* fromFullscreen */); } else { - final ActivityStack stack = mStackSupervisor.getStack(stackId); + final ActivityStack stack = mRootActivityContainer.getStack(stackId); if (stack == null) { Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); return; } - mStackSupervisor.resizeStackLocked(stack, destBounds, + mRootActivityContainer.resizeStack(stack, destBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, preserveWindows, allowResizeInDockedMode, !DEFER_RESUME); } @@ -2409,7 +2413,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task == null) { Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId); @@ -2451,7 +2455,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - mStackSupervisor.removeStacksInWindowingModes(windowingModes); + mRootActivityContainer.removeStacksInWindowingModes(windowingModes); } finally { Binder.restoreCallingIdentity(ident); } @@ -2466,7 +2470,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - mStackSupervisor.removeStacksWithActivityTypes(activityTypes); + mRootActivityContainer.removeStacksWithActivityTypes(activityTypes); } finally { Binder.restoreCallingIdentity(ident); } @@ -2497,7 +2501,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - return mStackSupervisor.getAllStackInfosLocked(); + return mRootActivityContainer.getAllStackInfos(); } } finally { Binder.restoreCallingIdentity(ident); @@ -2510,7 +2514,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - return mStackSupervisor.getStackInfo(windowingMode, activityType); + return mRootActivityContainer.getStackInfo(windowingMode, activityType); } } finally { Binder.restoreCallingIdentity(ident); @@ -2552,7 +2556,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task == null) { return; @@ -2594,7 +2598,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } - final ActivityStack stack = mStackSupervisor.getTopDisplayFocusedStack(); + final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack(); if (stack == null || task != stack.topTask()) { throw new IllegalArgumentException("Invalid task, not in foreground"); } @@ -2609,7 +2613,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { // When a task is locked, dismiss the pinned stack if it exists - mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED); + mRootActivityContainer.removeStacksInWindowingModes(WINDOWING_MODE_PINNED); getLockTaskController().startLockTaskMode(task, isSystemCaller, callingUid); } finally { @@ -2711,7 +2715,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { // TODO: VI Consider treating local voice interactions and voice tasks // differently here - mStackSupervisor.finishVoiceTask(session); + mRootActivityContainer.finishVoiceTask(session); } finally { Binder.restoreCallingIdentity(origId); } @@ -2901,7 +2905,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setTaskResizeable(int taskId, int resizeableMode) { synchronized (mGlobalLock) { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked( + final TaskRecord task = mRootActivityContainer.anyTaskForId( taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (task == null) { Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found"); @@ -2917,7 +2921,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task == null) { Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found"); @@ -2982,7 +2986,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long origId = Binder.clearCallingIdentity(); try { final WindowProcessController app = getProcessController(appInt); - mStackSupervisor.releaseSomeActivitiesLocked(app, "low-mem"); + mRootActivityContainer.releaseSomeActivitiesLocked(app, "low-mem"); } finally { Binder.restoreCallingIdentity(origId); } @@ -3076,7 +3080,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - final ActivityStack stack = mStackSupervisor.getStack(stackId); + final ActivityStack stack = mRootActivityContainer.getStack(stackId); if (stack == null) { Slog.w(TAG, "removeStack: No stack with id=" + stackId); return; @@ -3101,7 +3105,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId + " to displayId=" + displayId); - mStackSupervisor.moveStackToDisplayLocked(stackId, displayId, ON_TOP); + mRootActivityContainer.moveStackToDisplay(stackId, displayId, ON_TOP); } finally { Binder.restoreCallingIdentity(ident); } @@ -3563,13 +3567,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { if (DEBUG_STACK) Slog.d(TAG_STACK, "positionTaskInStack: positioning task=" + taskId + " in stackId=" + stackId + " at position=" + position); - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId); if (task == null) { throw new IllegalArgumentException("positionTaskInStack: no task for id=" + taskId); } - final ActivityStack stack = mStackSupervisor.getStack(stackId); + final ActivityStack stack = mRootActivityContainer.getStack(stackId); if (stack == null) { throw new IllegalArgumentException("positionTaskInStack: no stack for id=" @@ -3624,7 +3628,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { synchronized (mGlobalLock) { final ActivityStack stack = - mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); + mRootActivityContainer.getDefaultDisplay().getSplitScreenPrimaryStack(); if (stack == null) { Slog.w(TAG, "dismissSplitScreenMode: primary split-screen stack not found."); return; @@ -3634,7 +3638,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Caller wants the current split-screen primary stack to be the top stack after // it goes fullscreen, so move it to the front. stack.moveToFront("dismissSplitScreenMode"); - } else if (mStackSupervisor.isTopDisplayFocusedStack(stack)) { + } else if (mRootActivityContainer.isTopDisplayFocusedStack(stack)) { // In this case the current split-screen primary stack shouldn't be the top // stack after it goes fullscreen, but it current has focus, so we move the // focus to the top-most split-screen secondary stack next to it. @@ -3665,7 +3669,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { synchronized (mGlobalLock) { final PinnedActivityStack stack = - mStackSupervisor.getDefaultDisplay().getPinnedStack(); + mRootActivityContainer.getDefaultDisplay().getPinnedStack(); if (stack == null) { Slog.w(TAG, "dismissPip: pinned stack not found."); return; @@ -3707,7 +3711,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long origId = Binder.clearCallingIdentity(); try { - final ActivityStack stack = mStackSupervisor.getStack(fromStackId); + final ActivityStack stack = mRootActivityContainer.getStack(fromStackId); if (stack != null){ if (!stack.isActivityTypeStandardOrUndefined()) { throw new IllegalArgumentException( @@ -3742,7 +3746,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { - return mStackSupervisor.moveTopStackActivityToPinnedStackLocked(stackId, bounds); + return mRootActivityContainer.moveTopStackActivityToPinnedStack(stackId); } finally { Binder.restoreCallingIdentity(ident); } @@ -3820,7 +3824,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Adjust the source bounds by the insets for the transition down final Rect sourceBounds = new Rect( r.pictureInPictureArgs.getSourceRectHint()); - mStackSupervisor.moveActivityToPinnedStackLocked( + mRootActivityContainer.moveActivityToPinnedStack( r, sourceBounds, aspectRatio, "enterPictureInPictureMode"); final PinnedActivityStack stack = r.getStack(); stack.setPictureInPictureAspectRatio(aspectRatio); @@ -4099,7 +4103,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { // Check if display is initialized in AM. - if (!mStackSupervisor.isDisplayAdded(displayId)) { + if (!mRootActivityContainer.isDisplayAdded(displayId)) { // Call might come when display is not yet added or has already been removed. if (DEBUG_CONFIGURATION) { Slog.w(TAG, "Trying to update display configuration for non-existing displayId=" @@ -4189,7 +4193,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, + final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task == null) { Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found"); @@ -4209,7 +4213,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { final TaskRecord task; synchronized (mGlobalLock) { - task = mStackSupervisor.anyTaskForIdLocked(taskId, + task = mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (task == null) { Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found"); @@ -4429,7 +4433,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r.requestedVrComponent != null && r.getDisplayId() != DEFAULT_DISPLAY) { Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId() + " to main stack for VR"); - final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getOrCreateStack( + final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().getOrCreateStack( WINDOWING_MODE_FULLSCREEN, r.getActivityType(), true /* toTop */); moveTaskToStack(r.getTask().taskId, stack.mStackId, true /* toTop */); } @@ -4443,7 +4447,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (disableNonVrUi) { // If we are in a VR mode where Picture-in-Picture mode is unsupported, // then remove the pinned stack. - mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED); + mRootActivityContainer.removeStacksInWindowingModes(WINDOWING_MODE_PINNED); } } }); @@ -4495,7 +4499,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } ActivityStack getTopDisplayFocusedStack() { - return mStackSupervisor.getTopDisplayFocusedStack(); + return mRootActivityContainer.getTopDisplayFocusedStack(); } /** Pokes the task persister. */ @@ -4556,12 +4560,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { int opti, boolean dumpAll, boolean dumpClient, String dumpPackage, String header) { pw.println(header); - boolean printedAnything = mStackSupervisor.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, + boolean printedAnything = mRootActivityContainer.dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage); boolean needSep = printedAnything; boolean printed = ActivityStackSupervisor.printThisActivity(pw, - mStackSupervisor.getTopResumedActivity(), dumpPackage, needSep, + mRootActivityContainer.getTopResumedActivity(), dumpPackage, needSep, " ResumedActivity: "); if (printed) { printedAnything = true; @@ -4583,7 +4587,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { void dumpActivityContainersLocked(PrintWriter pw) { pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)"); - mStackSupervisor.dumpChildrenNames(pw, " "); + mRootActivityContainer.dumpChildrenNames(pw, " "); pw.println(" "); } @@ -4607,7 +4611,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ArrayList<ActivityRecord> activities; synchronized (mGlobalLock) { - activities = mStackSupervisor.getDumpActivitiesLocked(name, dumpVisibleStacksOnly, + activities = mRootActivityContainer.getDumpActivities(name, dumpVisibleStacksOnly, dumpFocusedStackOnly); } @@ -4682,7 +4686,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } void writeSleepStateToProto(ProtoOutputStream proto) { - for (ActivityTaskManagerInternal.SleepToken st : mStackSupervisor.mSleepTokens) { + for (ActivityTaskManagerInternal.SleepToken st : mRootActivityContainer.mSleepTokens) { proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEP_TOKENS, st.toString()); } @@ -4727,7 +4731,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * also corresponds to the merged configuration of the default display. */ Configuration getGlobalConfiguration() { - return mStackSupervisor.getConfiguration(); + return mRootActivityContainer.getConfiguration(); } boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, @@ -4859,7 +4863,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mTempConfig.seq = increaseConfigurationSeqLocked(); // Update stored global config and notify everyone about the change. - mStackSupervisor.onConfigurationChanged(mTempConfig); + mRootActivityContainer.onConfigurationChanged(mTempConfig); Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig); // TODO(multi-display): Update UsageEvents#Event to include displayId. @@ -4906,7 +4910,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Override configuration of the default display duplicates global config, so we need to // update it also. This will also notify WindowManager about changes. - performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume, + performDisplayOverrideConfigUpdate(mRootActivityContainer.getConfiguration(), deferResume, DEFAULT_DISPLAY); return changes; @@ -4960,12 +4964,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume, int displayId) { - mTempConfig.setTo(mStackSupervisor.getDisplayOverrideConfiguration(displayId)); + mTempConfig.setTo(mRootActivityContainer.getDisplayOverrideConfiguration(displayId)); final int changes = mTempConfig.updateFrom(values); if (changes != 0) { Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " " + mTempConfig + " for displayId=" + displayId); - mStackSupervisor.setDisplayOverrideConfiguration(mTempConfig, displayId); + mRootActivityContainer.setDisplayOverrideConfiguration(mTempConfig, displayId); final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0; if (isDensityChange && displayId == DEFAULT_DISPLAY) { @@ -5095,7 +5099,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mCurAppTimeTracker.stop(); mH.obtainMessage( REPORT_TIME_TRACKER_MSG, mCurAppTimeTracker).sendToTarget(); - mStackSupervisor.clearOtherAppTimeTrackers(r.appTimeTracker); + mRootActivityContainer.clearOtherAppTimeTrackers(r.appTimeTracker); mCurAppTimeTracker = null; } if (r.appTimeTracker != null) { @@ -5156,14 +5160,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ActivityTaskManagerInternal.SleepToken acquireSleepToken(String tag, int displayId) { synchronized (mGlobalLock) { - final ActivityTaskManagerInternal.SleepToken token = mStackSupervisor.createSleepTokenLocked(tag, displayId); + final ActivityTaskManagerInternal.SleepToken token = + mRootActivityContainer.createSleepToken(tag, displayId); updateSleepIfNeededLocked(); return token; } } void updateSleepIfNeededLocked() { - final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay(); + final boolean shouldSleep = !mRootActivityContainer.hasAwakeDisplay(); final boolean wasSleeping = mSleeping; boolean updateOomAdj = false; @@ -5179,7 +5184,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mTopProcessState = ActivityManager.PROCESS_STATE_TOP; mStackSupervisor.comeOutOfSleepIfNeededLocked(); } - mStackSupervisor.applySleepTokensLocked(true /* applyToStacks */); + mRootActivityContainer.applySleepTokens(true /* applyToStacks */); if (wasSleeping) { updateOomAdj = true; } @@ -5355,7 +5360,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // TODO(b/111541062): Update app time tracking to make it aware of multiple resumed activities private void startTimeTrackingFocusedActivityLocked() { - final ActivityRecord resumedActivity = mStackSupervisor.getTopResumedActivity(); + final ActivityRecord resumedActivity = mRootActivityContainer.getTopResumedActivity(); if (!mSleeping && mCurAppTimeTracker != null && resumedActivity != null) { mCurAppTimeTracker.start(resumedActivity.packageName); } @@ -5380,7 +5385,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Applies latest configuration and/or visibility updates if needed. */ private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { boolean kept = true; - final ActivityStack mainStack = mStackSupervisor.getTopDisplayFocusedStack(); + final ActivityStack mainStack = mRootActivityContainer.getTopDisplayFocusedStack(); // mainStack is null during startup. if (mainStack != null) { if (changes != 0 && starting == null) { @@ -5395,7 +5400,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { false /* preserveWindow */); // And we need to make sure at this point that all other activities // are made visible with the correct configuration. - mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes, + mRootActivityContainer.ensureActivitiesVisible(starting, changes, !PRESERVE_WINDOWS); } } @@ -5611,8 +5616,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public ComponentName getHomeActivityForUser(int userId) { synchronized (mGlobalLock) { - ActivityRecord homeActivity = - mStackSupervisor.getDefaultDisplayHomeActivityForUser(userId); + final ActivityRecord homeActivity = + mRootActivityContainer.getDefaultDisplayHomeActivityForUser(userId); return homeActivity == null ? null : homeActivity.realActivity; } } @@ -5650,14 +5655,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public List<IBinder> getTopVisibleActivities() { synchronized (mGlobalLock) { - return mStackSupervisor.getTopVisibleActivities(); + return mRootActivityContainer.getTopVisibleActivities(); } } @Override public void notifyDockedStackMinimizedChanged(boolean minimized) { synchronized (mGlobalLock) { - mStackSupervisor.setDockedStackMinimized(minimized); + mRootActivityContainer.setDockedStackMinimized(minimized); } } @@ -5738,7 +5743,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // We might change the visibilities here, so prepare an empty app transition which // might be overridden later if we actually change visibilities. final ActivityDisplay activityDisplay = - mStackSupervisor.getActivityDisplay(displayId); + mRootActivityContainer.getActivityDisplay(displayId); if (activityDisplay == null) { return; } @@ -5747,7 +5752,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (!wasTransitionSet) { dwc.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */); } - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); // If there was a transition set already we don't want to interfere with it as we // might be starting it too early. @@ -5764,7 +5769,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void notifyKeyguardTrustedChanged() { synchronized (mGlobalLock) { if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) { - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); } } } @@ -5791,7 +5796,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "setFocusedActivity: No activity record matching token=" + token); } if (r.moveFocusableActivityToTop("setFocusedActivity")) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); } } } @@ -5942,7 +5947,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public boolean shuttingDown(boolean booted, int timeout) { synchronized (mGlobalLock) { mShuttingDown = true; - mStackSupervisor.prepareForShutdownLocked(); + mRootActivityContainer.prepareForShutdown(); updateEventDispatchingLocked(booted); notifyTaskPersisterLocked(null, true); return mStackSupervisor.shutdownLocked(timeout); @@ -6049,7 +6054,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void onPackageReplaced(ApplicationInfo aInfo) { synchronized (mGlobalLock) { - mStackSupervisor.updateActivityApplicationInfoLocked(aInfo); + mRootActivityContainer.updateActivityApplicationInfo(aInfo); } } @@ -6079,7 +6084,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mH.post(() -> { synchronized (mGlobalLock) { final ActivityDisplay activityDisplay = - mStackSupervisor.getActivityDisplay(displayId); + mRootActivityContainer.getActivityDisplay(displayId); if (activityDisplay == null) { // Call might come when display is not yet added or has been removed. if (DEBUG_CONFIGURATION) { @@ -6162,14 +6167,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean startHomeActivity(int userId, String reason) { synchronized (mGlobalLock) { - return mStackSupervisor.startHomeOnDisplay(userId, reason, DEFAULT_DISPLAY); + return mRootActivityContainer.startHomeOnDisplay(userId, reason, DEFAULT_DISPLAY); } } @Override public boolean startHomeOnAllDisplays(int userId, String reason) { synchronized (mGlobalLock) { - return mStackSupervisor.startHomeOnAllDisplays(userId, reason); + return mRootActivityContainer.startHomeOnAllDisplays(userId, reason); } } @@ -6233,7 +6238,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Runnable finishInstrumentationCallback) { synchronized (mGlobalLock) { // Remove this application's activities from active lists. - boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(wpc); + boolean hasVisibleActivities = mRootActivityContainer.handleAppDied(wpc); wpc.clearRecentTasks(); wpc.clearActivities(); @@ -6245,12 +6250,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mWindowManager.deferSurfaceLayout(); try { if (!restarting && hasVisibleActivities - && !mStackSupervisor.resumeFocusedStacksTopActivitiesLocked()) { + && !mRootActivityContainer.resumeFocusedStacksTopActivities()) { // If there was nothing to resume, and we are not already restarting this // process, but there is a visible activity that is hosted by the process... // then make sure all visible activities are running, taking care of // restarting this process. - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); } } finally { mWindowManager.continueSurfaceLayout(); @@ -6279,7 +6284,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } mWindowManager.closeSystemDialogs(reason); - mStackSupervisor.closeSystemDialogsLocked(); + mRootActivityContainer.closeSystemDialogs(); } // Call into AM outside the synchronized block. mAmInternal.broadcastCloseSystemDialogs(reason); @@ -6293,9 +6298,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { String packageName, Set<String> disabledClasses, int userId, boolean booted) { synchronized (mGlobalLock) { // Clean-up disabled activities. - if (mStackSupervisor.finishDisabledPackageActivitiesLocked( + if (mRootActivityContainer.finishDisabledPackageActivities( packageName, disabledClasses, true, false, userId) && booted) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); mStackSupervisor.scheduleIdleLocked(); } @@ -6312,7 +6317,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { boolean didSomething = getActivityStartController().clearPendingActivityLaunches(packageName); - didSomething |= mStackSupervisor.finishDisabledPackageActivitiesLocked(packageName, + didSomething |= mRootActivityContainer.finishDisabledPackageActivities(packageName, null, doit, evenPersistent, userId); return didSomething; } @@ -6321,7 +6326,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void resumeTopActivities(boolean scheduleIdle) { synchronized (mGlobalLock) { - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mRootActivityContainer.resumeFocusedStacksTopActivities(); if (scheduleIdle) { mStackSupervisor.scheduleIdleLocked(); } @@ -6338,7 +6343,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean attachApplication(WindowProcessController wpc) throws RemoteException { synchronized (mGlobalLock) { - return mStackSupervisor.attachApplicationLocked(wpc); + return mRootActivityContainer.attachApplication(wpc); } } @@ -6360,7 +6365,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Showing launcher to avoid user entering credential twice. startHomeActivity(currentUserId, "notifyLockedProfile"); } - mStackSupervisor.lockAllProfileTasks(userId); + mRootActivityContainer.lockAllProfileTasks(userId); } } finally { Binder.restoreCallingIdentity(ident); @@ -6381,7 +6386,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ActivityOptions activityOptions = options != null ? new ActivityOptions(options) : ActivityOptions.makeBasic(); final ActivityRecord homeActivity = - mStackSupervisor.getDefaultDisplayHomeActivity(); + mRootActivityContainer.getDefaultDisplayHomeActivity(); if (homeActivity != null) { activityOptions.setLaunchTaskId(homeActivity.getTask().taskId); } @@ -6398,7 +6403,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { // The output proto of "activity --proto activities" // is ActivityManagerServiceDumpActivitiesProto - mStackSupervisor.writeToProto(proto, + mRootActivityContainer.writeToProto(proto, ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR); } } @@ -6493,7 +6498,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } if (dumpPackage == null) { pw.println(" mGlobalConfiguration: " + getGlobalConfiguration()); - mStackSupervisor.dumpDisplayConfigs(pw, " "); + mRootActivityContainer.dumpDisplayConfigs(pw, " "); } if (dumpAll) { if (dumpPackage == null) { @@ -6521,7 +6526,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (dumpPackage == null) { pw.println(" mWakefulness=" + PowerManagerInternal.wakefulnessToString(wakefulness)); - pw.println(" mSleepTokens=" + mStackSupervisor.mSleepTokens); + pw.println(" mSleepTokens=" + mRootActivityContainer.mSleepTokens); if (mRunningVoice != null) { pw.println(" mRunningVoice=" + mRunningVoice); pw.println(" mVoiceWakeLock" + mVoiceWakeLock); @@ -6648,14 +6653,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean canGcNow() { synchronized (mGlobalLock) { - return isSleeping() || mStackSupervisor.allResumedActivitiesIdle(); + return isSleeping() || mRootActivityContainer.allResumedActivitiesIdle(); } } @Override public WindowProcessController getTopApp() { synchronized (mGlobalLock) { - final ActivityRecord top = mStackSupervisor.getTopResumedActivity(); + final ActivityRecord top = mRootActivityContainer.getTopResumedActivity(); return top != null ? top.app : null; } } @@ -6663,8 +6668,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void rankTaskLayersIfNeeded() { synchronized (mGlobalLock) { - if (mStackSupervisor != null) { - mStackSupervisor.rankTaskLayersIfNeeded(); + if (mRootActivityContainer != null) { + mRootActivityContainer.rankTaskLayersIfNeeded(); } } } @@ -6672,35 +6677,35 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void scheduleDestroyAllActivities(String reason) { synchronized (mGlobalLock) { - mStackSupervisor.scheduleDestroyAllActivities(null, reason); + mRootActivityContainer.scheduleDestroyAllActivities(null, reason); } } @Override public void removeUser(int userId) { synchronized (mGlobalLock) { - mStackSupervisor.removeUserLocked(userId); + mRootActivityContainer.removeUser(userId); } } @Override public boolean switchUser(int userId, UserState userState) { synchronized (mGlobalLock) { - return mStackSupervisor.switchUserLocked(userId, userState); + return mRootActivityContainer.switchUser(userId, userState); } } @Override public void onHandleAppCrash(WindowProcessController wpc) { synchronized (mGlobalLock) { - mStackSupervisor.handleAppCrashLocked(wpc); + mRootActivityContainer.handleAppCrash(wpc); } } @Override public int finishTopCrashedActivities(WindowProcessController crashedApp, String reason) { synchronized (mGlobalLock) { - return mStackSupervisor.finishTopCrashedActivitiesLocked(crashedApp, reason); + return mRootActivityContainer.finishTopCrashedActivities(crashedApp, reason); } } @@ -6871,4 +6876,4 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java index 04fef02cd3b4..441c5935a507 100644 --- a/services/core/java/com/android/server/wm/AppTaskImpl.java +++ b/services/core/java/com/android/server/wm/AppTaskImpl.java @@ -16,8 +16,8 @@ package com.android.server.wm; -import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; import android.app.ActivityManager; import android.app.IAppTask; @@ -77,7 +77,7 @@ class AppTaskImpl extends IAppTask.Stub { synchronized (mService.mGlobalLock) { long origId = Binder.clearCallingIdentity(); try { - TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId, + TaskRecord tr = mService.mRootActivityContainer.anyTaskForId(mTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr == null) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); @@ -115,7 +115,7 @@ class AppTaskImpl extends IAppTask.Stub { TaskRecord tr; IApplicationThread appThread; synchronized (mService.mGlobalLock) { - tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId, + tr = mService.mRootActivityContainer.anyTaskForId(mTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr == null) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); @@ -143,7 +143,7 @@ class AppTaskImpl extends IAppTask.Stub { synchronized (mService.mGlobalLock) { long origId = Binder.clearCallingIdentity(); try { - TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId, + TaskRecord tr = mService.mRootActivityContainer.anyTaskForId(mTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr == null) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index bd1460ae4566..7fdea10e3e2c 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -41,8 +41,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityOptions; -import android.content.Intent; import android.content.ComponentName; +import android.content.Intent; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.GraphicBuffer; @@ -846,7 +846,6 @@ public class AppWindowContainerController final IAppTransitionAnimationSpecsFuture specsFuture = pendingOptions.getSpecsFuture(); if (specsFuture != null) { - // TODO(multidisplay): Shouldn't be really used anymore from next CL. displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture( specsFuture, pendingOptions.getOnAnimationStartListener(), animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); @@ -875,7 +874,6 @@ public class AppWindowContainerController .overridePendingAppTransitionStartCrossProfileApps(); break; case ANIM_REMOTE_ANIMATION: - // TODO(multidisplay): Will pass displayId and adjust dependencies from next CL. displayContent.mAppTransition.overridePendingAppTransitionRemote( pendingOptions.getRemoteAnimationAdapter()); break; diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 92944a02f77a..6d402f291fcb 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -304,7 +304,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mActivityComponent = activityComponent; mVoiceInteraction = voiceInteraction; mFillsParent = fillsParent; - mInputApplicationHandle = new InputApplicationHandle(this); + mInputApplicationHandle = new InputApplicationHandle(appToken.asBinder()); } void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { @@ -1081,8 +1081,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree super.onDisplayChanged(dc); if (prevDc != null && prevDc.mFocusedApp == this) { prevDc.setFocusedApp(null); - if (dc.getTopStack().getTopChild().getTopChild() == this) { - dc.setFocusedApp(this); + final TaskStack stack = dc.getTopStack(); + if (stack != null) { + final Task task = stack.getTopChild(); + if (task != null && task.getTopChild() == this) { + dc.setFocusedApp(this); + } } } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 886b2ff1ce54..478340d85d01 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -352,6 +352,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo int pendingLayoutChanges; int mDeferredRotationPauseCount; + /** + * Used to gate application window layout until we have sent the complete configuration. + * TODO: There are still scenarios where we may be out of sync with the client. Ideally + * we want to replace this flag with a mechanism that will confirm the configuration + * applied by the client is the one expected by the system server. + */ + boolean mWaitingForConfig; + // TODO(multi-display): remove some of the usages. @VisibleForTesting boolean isDefaultDisplay; @@ -1284,7 +1292,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation); if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) { - mService.mWaitingForConfig = true; + mWaitingForConfig = true; } mRotation = rotation; @@ -2392,8 +2400,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mDisplayReady = false; mRemovingDisplay = false; } + mDisplayPolicy.onDisplayRemoved(); - mInputMonitor.onRemoved(); mService.mWindowPlacerLocked.requestTraversal(); } @@ -3675,6 +3683,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } mTmpWindow = w; w.setDisplayLayoutNeeded(); + w.finishSeamlessRotation(true /* timeout */); mService.markForSeamlessRotation(w, false); }, true /* traverseTopToBottom */); diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index 7ed078a93375..e3ddadc7f70e 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -74,8 +74,15 @@ class DragDropController { return mDragState != null; } - InputWindowHandle getInputWindowHandleLocked() { - return mDragState.getInputWindowHandle(); + void showInputSurface(SurfaceControl.Transaction t, int displayId) { + mDragState.showInputSurface(t, displayId); + } + + void hideInputSurface(SurfaceControl.Transaction t, int displayId) { + if (mDragState != null) { + // TODO: Are we guaranteed to get here? + mDragState.hideInputSurface(t, displayId); + } } void registerCallback(IDragDropCallback callback) { diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index a379266fe533..7279fe018055 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -32,9 +32,11 @@ import android.annotation.Nullable; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; +import android.graphics.Rect; import android.graphics.Point; import android.hardware.input.InputManager; import android.os.Build; +import android.os.Binder; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; @@ -118,6 +120,11 @@ class DragState { private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f); private Point mDisplaySize = new Point(); + // A surface used to catch input events for the drag-and-drop operation. + SurfaceControl mInputSurface; + + private final Rect mTmpClipRect = new Rect(); + DragState(WindowManagerService service, DragDropController controller, IBinder token, SurfaceControl surface, int flags, IBinder localWin) { mService = service; @@ -127,6 +134,42 @@ class DragState { mFlags = flags; mLocalWin = localWin; mNotifiedWindows = new ArrayList<WindowState>(); + + } + + void hideInputSurface(SurfaceControl.Transaction t, int displayId) { + if (displayId != mDisplayContent.getDisplayId()) { + return; + } + + if (mInputSurface != null) { + t.hide(mInputSurface); + } + } + + void showInputSurface(SurfaceControl.Transaction t, int displayId) { + if (displayId != mDisplayContent.getDisplayId()) { + return; + } + + if (mInputSurface == null) { + mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId) + .getSession()).setContainerLayer(true) + .setName("Drag and Drop Input Consumer").setSize(1, 1).build(); + } + final InputWindowHandle h = getInputWindowHandle(); + if (h == null) { + Slog.w(TAG_WM, "Drag is in progress but there is no " + + "drag window handle."); + return; + } + + t.show(mInputSurface); + t.setInputWindowInfo(mInputSurface, h); + t.setLayer(mInputSurface, Integer.MAX_VALUE); + + mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); + t.setWindowCrop(mInputSurface, mTmpClipRect); } /** @@ -218,7 +261,7 @@ class DragState { mInputEventReceiver = new DragInputEventReceiver(mClientChannel, mService.mH.getLooper(), mDragDropController); - mDragApplicationHandle = new InputApplicationHandle(null); + mDragApplicationHandle = new InputApplicationHandle(new Binder()); mDragApplicationHandle.name = "drag"; mDragApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; @@ -226,7 +269,7 @@ class DragState { mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, display.getDisplayId()); mDragWindowHandle.name = "drag"; - mDragWindowHandle.inputChannel = mServerChannel; + mDragWindowHandle.token = mServerChannel.getToken(); mDragWindowHandle.layer = getDragLayerLocked(); mDragWindowHandle.layoutParamsFlags = 0; mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 49bedc97a38a..8140820871da 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import android.graphics.Rect; +import android.os.Binder; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; @@ -25,6 +27,8 @@ import android.view.WindowManager; import android.view.InputApplicationHandle; import android.view.InputWindowHandle; +import android.view.SurfaceControl; +import android.util.Slog; import java.io.PrintWriter; @@ -39,6 +43,9 @@ class InputConsumerImpl implements IBinder.DeathRecipient { final int mClientPid; final UserHandle mClientUser; + final SurfaceControl mInputSurface; + Rect mTmpClipRect = new Rect(); + InputConsumerImpl(WindowManagerService service, IBinder token, String name, InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId) { mService = service; @@ -58,14 +65,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient { } mService.mInputManager.registerInputChannel(mServerChannel, null); - mApplicationHandle = new InputApplicationHandle(null); + mApplicationHandle = new InputApplicationHandle(new Binder()); mApplicationHandle.name = name; mApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; mWindowHandle = new InputWindowHandle(mApplicationHandle, null, displayId); mWindowHandle.name = name; - mWindowHandle.inputChannel = mServerChannel; + mWindowHandle.token = mServerChannel.getToken(); mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; mWindowHandle.layer = getLayerLw(mWindowHandle.layoutParamsType); mWindowHandle.layoutParamsFlags = 0; @@ -80,6 +87,11 @@ class InputConsumerImpl implements IBinder.DeathRecipient { mWindowHandle.ownerUid = Process.myUid(); mWindowHandle.inputFeatures = 0; mWindowHandle.scaleFactor = 1.0f; + + mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId) + .getSession()).setContainerLayer(true).setName("Input Consumer " + name) + .setSize(1, 1) + .build(); } void linkToDeathRecipient() { @@ -102,12 +114,33 @@ class InputConsumerImpl implements IBinder.DeathRecipient { mToken.unlinkToDeath(this, 0); } - void layout(int dw, int dh) { - mWindowHandle.touchableRegion.set(0, 0, dw, dh); - mWindowHandle.frameLeft = 0; - mWindowHandle.frameTop = 0; - mWindowHandle.frameRight = dw; - mWindowHandle.frameBottom = dh; + void layout(SurfaceControl.Transaction t, int dw, int dh) { + t.setPosition(mInputSurface, 0, 0); + + mTmpClipRect.set(0, 0, dw, dh); + t.setWindowCrop(mInputSurface, mTmpClipRect); + } + + void layout(SurfaceControl.Transaction t, Rect r) { + t.setPosition(mInputSurface, r.left, r.top); + mTmpClipRect.set(0, 0, r.width(), r.height()); + t.setWindowCrop(mInputSurface, mTmpClipRect); + } + + void hide(SurfaceControl.Transaction t) { + t.hide(mInputSurface); + } + + void show(SurfaceControl.Transaction t, WindowState w) { + t.show(mInputSurface); + t.setInputWindowInfo(mInputSurface, mWindowHandle); + t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1); + } + + void show(SurfaceControl.Transaction t, int layer) { + t.show(mInputSurface); + t.setInputWindowInfo(mInputSurface, mWindowHandle); + t.setLayer(mInputSurface, layer); } private int getLayerLw(int windowType) { diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 92ea1a90735c..94355395b38e 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -72,8 +72,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal * Called by the InputManager. */ @Override - public long notifyANR(InputApplicationHandle inputApplicationHandle, - IBinder token, String reason) { + public long notifyANR(IBinder token, String reason) { AppWindowToken appWindowToken = null; WindowState windowState = null; boolean aboveSystem = false; @@ -84,9 +83,6 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal appWindowToken = windowState.mAppToken; } } - if (appWindowToken == null && inputApplicationHandle != null) { - appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowToken; - } if (windowState != null) { Slog.i(TAG_WM, "Input event dispatching timed out " diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 83d32c8ad289..88b22cb5e01e 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -44,6 +44,7 @@ import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputEventReceiver; import android.view.InputWindowHandle; +import android.view.SurfaceControl; import com.android.server.policy.WindowManagerPolicy; @@ -61,9 +62,8 @@ final class InputMonitor { // When true, need to call updateInputWindowsLw(). private boolean mUpdateInputWindowsNeeded = true; - // Array of window handles to provide to the input dispatcher. - private InputWindowHandle[] mInputWindowHandles; - private int mInputWindowHandleCount; + // Currently focused input window handle. + private InputWindowHandle mFocusedInputWindowHandle; private boolean mDisableWallpaperTouchEvents; private final Rect mTmpRect = new Rect(); @@ -72,6 +72,8 @@ final class InputMonitor { private int mDisplayId; + SurfaceControl.Transaction mInputTransaction = new SurfaceControl.Transaction(); + /** * The set of input consumer added to the window manager by name, which consumes input events * for the windows below it. @@ -126,6 +128,7 @@ final class InputMonitor { private boolean disposeInputConsumer(InputConsumerImpl consumer) { if (consumer != null) { consumer.disposeChannelsLw(); + consumer.hide(mInputTransaction); return true; } return false; @@ -137,7 +140,16 @@ final class InputMonitor { void layoutInputConsumers(int dw, int dh) { for (int i = mInputConsumers.size() - 1; i >= 0; i--) { - mInputConsumers.valueAt(i).layout(dw, dh); + mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh); + } + } + + // The visibility of the input consumers is recomputed each time we + // update the input windows. We use a model where consumers begin invisible + // (set so by this function) and must meet some condition for visibility on each update. + void resetInputConsumers(SurfaceControl.Transaction t) { + for (int i = mInputConsumers.size() - 1; i >= 0; i--) { + mInputConsumers.valueAt(i).hide(t); } } @@ -177,18 +189,7 @@ final class InputMonitor { } - private void addInputWindowHandle(final InputWindowHandle windowHandle) { - if (mInputWindowHandles == null) { - mInputWindowHandles = new InputWindowHandle[16]; - } - if (mInputWindowHandleCount >= mInputWindowHandles.length) { - mInputWindowHandles = Arrays.copyOf(mInputWindowHandles, - mInputWindowHandleCount * 2); - } - mInputWindowHandles[mInputWindowHandleCount++] = windowHandle; - } - - void addInputWindowHandle(final InputWindowHandle inputWindowHandle, + void populateInputWindowHandle(final InputWindowHandle inputWindowHandle, final WindowState child, int flags, final int type, final boolean isVisible, final boolean hasFocus, final boolean hasWallpaper) { // Add a window to our list of input windows. @@ -214,6 +215,11 @@ final class InputMonitor { inputWindowHandle.frameRight = frame.right; inputWindowHandle.frameBottom = frame.bottom; + // Surface insets are hardcoded to be the same in all directions + // and we could probably deprecate the "left/right/top/bottom" concept. + // we avoid reintroducing this concept by just choosing one of them here. + inputWindowHandle.surfaceInset = child.getAttrs().surfaceInsets.left; + if (child.mGlobalScale != 1) { // If we are scaling the window, input coordinates need // to be inversely scaled to map from what is on screen @@ -227,12 +233,9 @@ final class InputMonitor { Slog.d(TAG_WM, "addInputWindowHandle: " + child + ", " + inputWindowHandle); } - addInputWindowHandle(inputWindowHandle); - } - private void clearInputWindowHandlesLw() { - while (mInputWindowHandleCount != 0) { - mInputWindowHandles[--mInputWindowHandleCount] = null; + if (hasFocus) { + mFocusedInputWindowHandle = inputWindowHandle; } } @@ -261,14 +264,9 @@ final class InputMonitor { if (DEBUG_DRAG) { Log.d(TAG_WM, "Inserting drag window"); } - final InputWindowHandle dragWindowHandle = - mService.mDragDropController.getInputWindowHandleLocked(); - if (dragWindowHandle == null) { - Slog.w(TAG_WM, "Drag is in progress but there is no " - + "drag window handle."); - } else if (dragWindowHandle.displayId == mDisplayId) { - addInputWindowHandle(dragWindowHandle); - } + mService.mDragDropController.showInputSurface(mInputTransaction, mDisplayId); + } else { + mService.mDragDropController.hideInputSurface(mInputTransaction, mDisplayId); } final boolean inPositioning = mService.mTaskPositioningController.isPositioningLocked(); @@ -276,14 +274,9 @@ final class InputMonitor { if (DEBUG_TASK_POSITIONING) { Log.d(TAG_WM, "Inserting window handle for repositioning"); } - final InputWindowHandle dragWindowHandle = - mService.mTaskPositioningController.getDragWindowHandleLocked(); - if (dragWindowHandle == null) { - Slog.e(TAG_WM, - "Repositioning is in progress but there is no drag window handle."); - } else if (dragWindowHandle.displayId == mDisplayId) { - addInputWindowHandle(dragWindowHandle); - } + mService.mTaskPositioningController.showInputSurface(mInputTransaction, mDisplayId); + } else { + mService.mTaskPositioningController.hideInputSurface(mInputTransaction, mDisplayId); } // Add all windows on the default display. @@ -362,12 +355,6 @@ final class InputMonitor { } } - void onRemoved() { - // If DisplayContent removed, we need find a way to remove window handles of this display - // from InputDispatcher, so pass an empty InputWindowHandles to remove them. - mService.mInputManager.setInputWindows(mInputWindowHandles, mDisplayId); - } - private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> { InputConsumerImpl navInputConsumer; InputConsumerImpl pipInputConsumer; @@ -401,16 +388,16 @@ final class InputMonitor { final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId); wallpaperController = dc.mWallpaperController; - dc.forAllWindows(this, true /* traverseTopToBottom */); + resetInputConsumers(mInputTransaction); + + dc.forAllWindows(this, + true /* traverseTopToBottom */); + if (mAddWallpaperInputConsumerHandle) { - // No visible wallpaper found, add the wallpaper input consumer at the end. - addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); + wallpaperInputConsumer.show(mInputTransaction, 0); } - // Send windows to native code. - mService.mInputManager.setInputWindows(mInputWindowHandles, mDisplayId); - - clearInputWindowHandlesLw(); + mInputTransaction.apply(); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } @@ -420,7 +407,7 @@ final class InputMonitor { final InputChannel inputChannel = w.mInputChannel; final InputWindowHandle inputWindowHandle = w.mInputWindowHandle; if (inputChannel == null || inputWindowHandle == null || w.mRemoved - || w.canReceiveTouchInput()) { + || w.cantReceiveTouchInput()) { // Skip this window because it cannot possibly receive input. return; } @@ -438,41 +425,36 @@ final class InputMonitor { && recentsAnimationController.shouldApplyInputConsumer(w.mAppToken)) { if (recentsAnimationController.updateInputConsumerForApp( recentsAnimationInputConsumer.mWindowHandle, hasFocus)) { - addInputWindowHandle(recentsAnimationInputConsumer.mWindowHandle); + recentsAnimationInputConsumer.show(mInputTransaction, w); mAddRecentsAnimationInputConsumerHandle = false; } - // If the target app window does not yet exist, then we don't add the input - // consumer window, but also don't add the app window below. - return; } } if (w.inPinnedWindowingMode()) { - if (mAddPipInputConsumerHandle - && (inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer)) { + if (mAddPipInputConsumerHandle) { // Update the bounds of the Pip input consumer to match the window bounds. w.getBounds(mTmpRect); + pipInputConsumer.layout(mInputTransaction, mTmpRect); + + // The touchable region is relative to the surface top-left + mTmpRect.offsetTo(0, 0); pipInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect); - addInputWindowHandle(pipInputConsumer.mWindowHandle); + pipInputConsumer.show(mInputTransaction, w); mAddPipInputConsumerHandle = false; } - // TODO: Fix w.canReceiveTouchInput() to handle this case - if (!hasFocus) { - // Skip this pinned stack window if it does not have focus - return; - } } if (mAddInputConsumerHandle && inputWindowHandle.layer <= navInputConsumer.mWindowHandle.layer) { - addInputWindowHandle(navInputConsumer.mWindowHandle); + navInputConsumer.show(mInputTransaction, w); mAddInputConsumerHandle = false; } if (mAddWallpaperInputConsumerHandle) { if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisibleLw()) { // Add the wallpaper input consumer above the first visible wallpaper. - addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); + wallpaperInputConsumer.show(mInputTransaction, w); mAddWallpaperInputConsumerHandle = false; } } @@ -490,8 +472,13 @@ final class InputMonitor { mService.mDragDropController.sendDragStartedIfNeededLocked(w); } - addInputWindowHandle( + populateInputWindowHandle( inputWindowHandle, w, flags, type, isVisible, hasFocus, hasWallpaper); + + if (w.mWinAnimator.hasSurface()) { + mInputTransaction.setInputWindowInfo( + w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle); + } } } } diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index c91af73dc6dd..4ef351390c16 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -72,6 +72,7 @@ class KeyguardController { private int mVisibilityTransactionDepth; private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>(); private final ActivityTaskManagerService mService; + private RootActivityContainer mRootActivityContainer; KeyguardController(ActivityTaskManagerService service, ActivityStackSupervisor stackSupervisor) { @@ -81,6 +82,7 @@ class KeyguardController { void setWindowManager(WindowManagerService windowManager) { mWindowManager = windowManager; + mRootActivityContainer = mService.mRootActivityContainer; } /** @@ -146,7 +148,7 @@ class KeyguardController { mDismissalRequested = false; } } - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); updateKeyguardSleepToken(); } @@ -172,16 +174,17 @@ class KeyguardController { mWindowManager.deferSurfaceLayout(); try { setKeyguardGoingAway(true); - mStackSupervisor.getDefaultDisplay().getWindowContainerController() + mRootActivityContainer.getDefaultDisplay().getWindowContainerController() .prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */, convertTransitFlags(flags), false /* forceOverride */); updateKeyguardSleepToken(); // Some stack visibility might change (e.g. docked stack) - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); - mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */); + mRootActivityContainer.resumeFocusedStacksTopActivities(); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.addStartingWindowsForVisibleActivities( + true /* taskSwitch */); mWindowManager.executeAppTransition(); } finally { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout"); @@ -277,8 +280,9 @@ class KeyguardController { private void visibilitiesUpdated() { boolean requestDismissKeyguard = false; - for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) { - final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx); + for (int displayNdx = mRootActivityContainer.getChildCount() - 1; + displayNdx >= 0; displayNdx--) { + final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx); final KeyguardDisplayState state = getDisplay(display.mDisplayId); state.visibilitiesUpdated(this, display); requestDismissKeyguard |= state.mRequestDismissKeyguard; @@ -298,12 +302,12 @@ class KeyguardController { if (isKeyguardLocked()) { mWindowManager.deferSurfaceLayout(); try { - mStackSupervisor.getDefaultDisplay().getWindowContainerController() + mRootActivityContainer.getDefaultDisplay().getWindowContainerController() .prepareAppTransition(resolveOccludeTransit(), false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */); updateKeyguardSleepToken(); - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); mWindowManager.executeAppTransition(); } finally { mWindowManager.continueSurfaceLayout(); @@ -319,21 +323,23 @@ class KeyguardController { // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded. - if (mWindowManager.isKeyguardSecure()) { - mWindowManager.dismissKeyguard(null /* callback */, null /* message */); - mDismissalRequested = true; - - // If we are about to unocclude the Keyguard, but we can dismiss it without security, - // we immediately dismiss the Keyguard so the activity gets shown without a flicker. - final DisplayWindowController dwc = - mStackSupervisor.getDefaultDisplay().getWindowContainerController(); - if (mKeyguardShowing && canDismissKeyguard() - && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) { - dwc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */, - 0 /* flags */, true /* forceOverride */); - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); - mWindowManager.executeAppTransition(); - } + if (!mWindowManager.isKeyguardSecure()) { + return; + } + + mWindowManager.dismissKeyguard(null /* callback */, null /* message */); + mDismissalRequested = true; + + // If we are about to unocclude the Keyguard, but we can dismiss it without security, + // we immediately dismiss the Keyguard so the activity gets shown without a flicker. + final DisplayWindowController dwc = + mRootActivityContainer.getDefaultDisplay().getWindowContainerController(); + if (mKeyguardShowing && canDismissKeyguard() + && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) { + dwc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */, + 0 /* flags */, true /* forceOverride */); + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); + mWindowManager.executeAppTransition(); } } @@ -350,7 +356,7 @@ class KeyguardController { private int resolveOccludeTransit() { final DisplayWindowController dwc = - mStackSupervisor.getDefaultDisplay().getWindowContainerController(); + mRootActivityContainer.getDefaultDisplay().getWindowContainerController(); if (mBeforeUnoccludeTransit != TRANSIT_UNSET && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE // TODO(b/113840485): Handle app transition for individual display. @@ -377,7 +383,8 @@ class KeyguardController { // show on top of the lock screen. In this can we want to dismiss the docked // stack since it will be complicated/risky to try to put the activity on top // of the lock screen in the right fullscreen configuration. - final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); + final ActivityStack stack = + mRootActivityContainer.getDefaultDisplay().getSplitScreenPrimaryStack(); if (stack == null) { return; } @@ -387,8 +394,9 @@ class KeyguardController { } private void updateKeyguardSleepToken() { - for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) { - final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx); + for (int displayNdx = mRootActivityContainer.getChildCount() - 1; + displayNdx >= 0; displayNdx--) { + final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx); final KeyguardDisplayState state = getDisplay(display.mDisplayId); if (isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken == null) { state.acquiredSleepToken(); diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java index 72d51439d9f7..da9a5071b100 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java +++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java @@ -223,7 +223,8 @@ class LaunchParamsPersister { private boolean saveTaskToLaunchParam(TaskRecord task, PersistableLaunchParams params) { final ActivityStack<?> stack = task.getStack(); final int displayId = stack.mDisplayId; - final ActivityDisplay display = mSupervisor.getActivityDisplay(displayId); + final ActivityDisplay display = + mSupervisor.mRootActivityContainer.getActivityDisplay(displayId); final DisplayInfo info = new DisplayInfo(); display.mDisplay.getDisplayInfo(info); @@ -259,7 +260,7 @@ class LaunchParamsPersister { return; } - final ActivityDisplay display = mSupervisor.getActivityDisplay( + final ActivityDisplay display = mSupervisor.mRootActivityContainer.getActivityDisplay( persistableParams.mDisplayUniqueId); if (display != null) { outParams.mPreferredDisplayId = display.mDisplayId; diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 41d0777d1c78..80dc2458d7f5 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -447,7 +447,7 @@ public class LockTaskController { return; } task.performClearTaskLocked(); - mSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mSupervisor.mRootActivityContainer.resumeFocusedStacksTopActivities(); } /** @@ -579,7 +579,7 @@ public class LockTaskController { if (andResume) { mSupervisor.findTaskToMoveToFront(task, 0, null, reason, lockTaskModeState != LOCK_TASK_MODE_NONE); - mSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mSupervisor.mRootActivityContainer.resumeFocusedStacksTopActivities(); final ActivityStack stack = task.getStack(); if (stack != null) { stack.getDisplay().getWindowContainerController().executeAppTransition(); @@ -641,11 +641,12 @@ public class LockTaskController { taskChanged = true; } - for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) { - mSupervisor.getChildAt(displayNdx).onLockTaskPackagesUpdated(); + for (int displayNdx = mSupervisor.mRootActivityContainer.getChildCount() - 1; + displayNdx >= 0; --displayNdx) { + mSupervisor.mRootActivityContainer.getChildAt(displayNdx).onLockTaskPackagesUpdated(); } - final ActivityRecord r = mSupervisor.topRunningActivityLocked(); + final ActivityRecord r = mSupervisor.mRootActivityContainer.topRunningActivity(); final TaskRecord task = (r != null) ? r.getTask() : null; if (mLockTaskModeTasks.isEmpty() && task!= null && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) { @@ -657,7 +658,7 @@ public class LockTaskController { } if (taskChanged) { - mSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mSupervisor.mRootActivityContainer.resumeFocusedStacksTopActivities(); } } diff --git a/services/core/java/com/android/server/wm/PinnedActivityStack.java b/services/core/java/com/android/server/wm/PinnedActivityStack.java index 3ef42e7be8d7..1c7ebd63dfb3 100644 --- a/services/core/java/com/android/server/wm/PinnedActivityStack.java +++ b/services/core/java/com/android/server/wm/PinnedActivityStack.java @@ -41,7 +41,7 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController> PinnedStackWindowController createStackWindowController(int displayId, boolean onTop, Rect outBounds) { return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds, - mStackSupervisor.mWindowManager); + mRootActivityContainer.mWindowManager); } Rect getDefaultPictureInPictureBounds(float aspectRatio) { diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 476c1f972fa9..24c5228ce0ec 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -79,7 +79,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, int callingPid) { mService = atm; mStackSupervisor = stackSupervisor; - mDefaultDisplay = stackSupervisor.getDefaultDisplay(); + mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay(); mActivityStartController = activityStartController; mWindowManager = wm; mCallingPid = callingPid; @@ -94,7 +94,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // TODO(multi-display) currently only support recents animation in default display. final DisplayWindowController dwc = - mStackSupervisor.getDefaultDisplay().getWindowContainerController(); + mService.mRootActivityContainer.getDefaultDisplay().getWindowContainerController(); if (!mWindowManager.canStartRecentsAnimation()) { notifyAnimationCancelBeforeStart(recentsAnimationRunner); if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition=" @@ -124,8 +124,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Send launch hint if we are actually launching the target. If it's already visible // (shouldn't happen in general) we don't need to send it. if (targetActivity == null || !targetActivity.visible) { - mStackSupervisor.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, - targetActivity); + mService.mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded( + true /* forceSend */, targetActivity); } mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent); @@ -192,7 +192,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // If we updated the launch-behind state, update the visibility of the activities after // we fetch the visible tasks to be controlled by the animation - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); + mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT, targetActivity); @@ -215,7 +215,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, @Deprecated IAssistDataReceiver assistDataReceiver, int userId) { final AppOpsManager appOpsManager = (AppOpsManager) mService.mContext.getSystemService(Context.APP_OPS_SERVICE); - final List<IBinder> topActivities = mStackSupervisor.getTopVisibleActivities(); + final List<IBinder> topActivities = + mService.mRootActivityContainer.getTopVisibleActivities(); final AssistDataRequester.AssistDataRequesterCallbacks assistDataCallbacks; if (assistDataReceiver != null) { assistDataCallbacks = new AssistDataReceiverProxy(assistDataReceiver, @@ -283,7 +284,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Just to be sure end the launch hint in case the target activity was never launched. // However, if we're keeping the activity and making it visible, we can leave it on. if (reorderMode != REORDER_KEEP_IN_PLACE) { - mStackSupervisor.sendPowerHintForLaunchEndIfNeeded(); + mService.mRootActivityContainer.sendPowerHintForLaunchEndIfNeeded(); } mService.mH.post( @@ -343,8 +344,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } mWindowManager.prepareAppTransition(TRANSIT_NONE, false); - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, false); - mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, false); + mService.mRootActivityContainer.resumeFocusedStacksTopActivities(); // No reason to wait for the pausing activity in this case, as the hiding of // surfaces needs to be done immediately. diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java new file mode 100644 index 000000000000..bdfbc1495b30 --- /dev/null +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -0,0 +1,2295 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import static android.app.ActivityTaskManager.INVALID_STACK_ID; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.app.WindowConfiguration.activityTypeToString; +import static android.app.WindowConfiguration.windowingModeToString; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; +import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; + +import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; +import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS; +import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID; +import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT; +import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; +import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES; +import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; +import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; +import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList; +import static com.android.server.wm.ActivityStackSupervisor.printThisActivity; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; +import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; +import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; + +import static java.lang.Integer.MAX_VALUE; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.app.AppGlobals; +import android.app.WindowConfiguration; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ResolveInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Rect; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManagerInternal; +import android.hardware.power.V1_0.PowerHint; +import android.os.Build; +import android.os.FactoryTest; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.Trace; +import android.os.UserHandle; +import android.service.voice.IVoiceInteractionSession; +import android.util.ArraySet; +import android.util.DisplayMetrics; +import android.util.IntArray; +import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; +import android.view.Display; +import android.view.DisplayInfo; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; +import com.android.server.am.ActivityManagerService; +import com.android.server.am.AppTimeTracker; +import com.android.server.am.UserState; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Root node for activity containers. + * TODO: This class is mostly temporary to separate things out of ActivityStackSupervisor.java. The + * intention is to have this merged with RootWindowContainer.java as part of unifying the hierarchy. + */ +class RootActivityContainer extends ConfigurationContainer implements + DisplayManager.DisplayListener, RootWindowContainerListener { + + private static final String TAG = TAG_WITH_CLASS_NAME ? "RootActivityContainer" : TAG_ATM; + static final String TAG_TASKS = TAG + POSTFIX_TASKS; + private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE; + static final String TAG_STATES = TAG + POSTFIX_STATES; + private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; + + /** + * The modes which affect which tasks are returned when calling + * {@link RootActivityContainer#anyTaskForId(int)}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + MATCH_TASK_IN_STACKS_ONLY, + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE + }) + public @interface AnyTaskForIdMatchTaskMode {} + // Match only tasks in the current stacks + static final int MATCH_TASK_IN_STACKS_ONLY = 0; + // Match either tasks in the current stacks, or in the recent tasks if not found in the stacks + static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS = 1; + // Match either tasks in the current stacks, or in the recent tasks, restoring it to the + // provided stack id + static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE = 2; + + ActivityTaskManagerService mService; + ActivityStackSupervisor mStackSupervisor; + WindowManagerService mWindowManager; + DisplayManager mDisplayManager; + private DisplayManagerInternal mDisplayManagerInternal; + private RootWindowContainerController mWindowContainerController; + + /** + * List of displays which contain activities, sorted by z-order. + * The last entry in the list is the topmost. + */ + private final ArrayList<ActivityDisplay> mActivityDisplays = new ArrayList<>(); + + /** Reference to default display so we can quickly look it up. */ + private ActivityDisplay mDefaultDisplay; + private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>(); + + /** The current user */ + int mCurrentUser; + /** Stack id of the front stack when user switched, indexed by userId. */ + SparseIntArray mUserStackInFront = new SparseIntArray(2); + + /** + * A list of tokens that cause the top activity to be put to sleep. + * They are used by components that may hide and block interaction with underlying + * activities. + */ + final ArrayList<ActivityTaskManagerInternal.SleepToken> mSleepTokens = new ArrayList<>(); + + /** Is dock currently minimized. */ + boolean mIsDockMinimized; + + /** Set when a power hint has started, but not ended. */ + private boolean mPowerHintSent; + + // The default minimal size that will be used if the activity doesn't specify its minimal size. + // It will be calculated when the default display gets added. + int mDefaultMinSizeOfResizeableTaskDp = -1; + + // Whether tasks have moved and we need to rank the tasks before next OOM scoring + private boolean mTaskLayersChanged = true; + + private final ArrayList<ActivityRecord> mTmpActivityList = new ArrayList<>(); + + private final FindTaskResult mTmpFindTaskResult = new FindTaskResult(); + static class FindTaskResult { + ActivityRecord mRecord; + boolean mIdealMatch; + + void clear() { + mRecord = null; + mIdealMatch = false; + } + + void setTo(FindTaskResult result) { + mRecord = result.mRecord; + mIdealMatch = result.mIdealMatch; + } + } + + RootActivityContainer(ActivityTaskManagerService service) { + mService = service; + mStackSupervisor = service.mStackSupervisor; + mStackSupervisor.mRootActivityContainer = this; + } + + @VisibleForTesting + void setWindowContainerController(RootWindowContainerController controller) { + mWindowContainerController = controller; + } + + void setWindowManager(WindowManagerService wm) { + mWindowManager = wm; + setWindowContainerController(new RootWindowContainerController(this)); + mDisplayManager = mService.mContext.getSystemService(DisplayManager.class); + mDisplayManager.registerDisplayListener(this, mService.mH); + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); + + final Display[] displays = mDisplayManager.getDisplays(); + for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) { + final Display display = displays[displayNdx]; + final ActivityDisplay activityDisplay = new ActivityDisplay(this, display); + if (activityDisplay.mDisplayId == DEFAULT_DISPLAY) { + mDefaultDisplay = activityDisplay; + } + addChild(activityDisplay, ActivityDisplay.POSITION_TOP); + } + calculateDefaultMinimalSizeOfResizeableTasks(); + + final ActivityDisplay defaultDisplay = getDefaultDisplay(); + + defaultDisplay.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + positionChildAt(defaultDisplay, ActivityDisplay.POSITION_TOP); + } + + // TODO(multi-display): Look at all callpoints to make sure they make sense in multi-display. + ActivityDisplay getDefaultDisplay() { + return mDefaultDisplay; + } + + /** + * Get an existing instance of {@link ActivityDisplay} that has the given uniqueId. Unique ID is + * defined in {@link DisplayInfo#uniqueId}. + * + * @param uniqueId the unique ID of the display + * @return the {@link ActivityDisplay} or {@code null} if nothing is found. + */ + ActivityDisplay getActivityDisplay(String uniqueId) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityDisplay display = mActivityDisplays.get(i); + final boolean isValid = display.mDisplay.isValid(); + if (isValid && display.mDisplay.getUniqueId().equals(uniqueId)) { + return display; + } + } + + return null; + } + + // TODO: Look into consolidating with getActivityDisplayOrCreate() + ActivityDisplay getActivityDisplay(int displayId) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(i); + if (activityDisplay.mDisplayId == displayId) { + return activityDisplay; + } + } + return null; + } + + /** + * Get an existing instance of {@link ActivityDisplay} or create new if there is a + * corresponding record in display manager. + */ + // TODO: Look into consolidating with getActivityDisplay() + ActivityDisplay getActivityDisplayOrCreate(int displayId) { + ActivityDisplay activityDisplay = getActivityDisplay(displayId); + if (activityDisplay != null) { + return activityDisplay; + } + if (mDisplayManager == null) { + // The system isn't fully initialized yet. + return null; + } + final Display display = mDisplayManager.getDisplay(displayId); + if (display == null) { + // The display is not registered in DisplayManager. + return null; + } + // The display hasn't been added to ActivityManager yet, create a new record now. + activityDisplay = new ActivityDisplay(this, display); + addChild(activityDisplay, ActivityDisplay.POSITION_BOTTOM); + return activityDisplay; + } + + /** Check if display with specified id is added to the list. */ + boolean isDisplayAdded(int displayId) { + return getActivityDisplayOrCreate(displayId) != null; + } + + ActivityRecord getDefaultDisplayHomeActivity() { + return getDefaultDisplayHomeActivityForUser(mCurrentUser); + } + + ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) { + return getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId); + } + + boolean startHomeOnAllDisplays(int userId, String reason) { + boolean homeStarted = false; + for (int i = mActivityDisplays.size() - 1; i >= 0; i--) { + final int displayId = mActivityDisplays.get(i).mDisplayId; + homeStarted |= startHomeOnDisplay(userId, reason, displayId); + } + return homeStarted; + } + + /** + * This starts home activity on displays that can have system decorations and only if the + * home activity can have multiple instances. + */ + boolean startHomeOnDisplay(int userId, String reason, int displayId) { + final Intent homeIntent = mService.getHomeIntent(); + final ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent); + if (aInfo == null) { + return false; + } + + if (!canStartHomeOnDisplay(aInfo, displayId, + false /* allowInstrumenting */)) { + return false; + } + + // Update the reason for ANR debugging to verify if the user activity is the one that + // actually launched. + final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId( + aInfo.applicationInfo.uid); + mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, + displayId); + return true; + } + + /** + * This resolves the home activity info and updates the home component of the given intent. + * @return the home activity info if any. + */ + private ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) { + final int flags = ActivityManagerService.STOCK_PM_FLAGS; + final ComponentName comp = homeIntent.getComponent(); + ActivityInfo aInfo = null; + try { + if (comp != null) { + // Factory test. + aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId); + } else { + final String resolvedType = + homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver()); + final ResolveInfo info = AppGlobals.getPackageManager() + .resolveIntent(homeIntent, resolvedType, flags, userId); + if (info != null) { + aInfo = info.activityInfo; + } + } + } catch (RemoteException e) { + // ignore + } + + if (aInfo == null) { + Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable()); + return null; + } + + homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); + aInfo = new ActivityInfo(aInfo); + aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId); + homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK); + return aInfo; + } + + boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) { + if (!mService.isBooting() && !mService.isBooted()) { + // Not ready yet! + return false; + } + + if (displayId == INVALID_DISPLAY) { + displayId = DEFAULT_DISPLAY; + } + + final ActivityRecord r = getActivityDisplay(displayId).getHomeActivity(); + final String myReason = reason + " resumeHomeActivity"; + + // Only resume home activity if isn't finishing. + if (r != null && !r.finishing) { + r.moveFocusableActivityToTop(myReason); + return resumeFocusedStacksTopActivities(r.getStack(), prev, null); + } + return startHomeOnDisplay(mCurrentUser, myReason, displayId); + } + + /** + * Check if home activity start should be allowed on a display. + * @param homeInfo {@code ActivityInfo} of the home activity that is going to be launched. + * @param displayId The id of the target display. + * @param allowInstrumenting Whether launching home should be allowed if being instrumented. + * @return {@code true} if allow to launch, {@code false} otherwise. + */ + boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId, + boolean allowInstrumenting) { + if (mService.mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL + && mService.mTopAction == null) { + // We are running in factory test mode, but unable to find the factory test app, so + // just sit around displaying the error message and don't try to start anything. + return false; + } + + final WindowProcessController app = + mService.getProcessController(homeInfo.processName, homeInfo.applicationInfo.uid); + if (!allowInstrumenting && app != null && app.isInstrumenting()) { + // Don't do this if the home app is currently being instrumented. + return false; + } + + if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY + && displayId == mService.mVr2dDisplayId)) { + // No restrictions to default display or vr 2d display. + return true; + } + + final ActivityDisplay display = getActivityDisplay(displayId); + if (display == null || display.isRemoved() || !display.supportsSystemDecorations()) { + // Can't launch home on display that doesn't support system decorations. + return false; + } + + final boolean supportMultipleInstance = homeInfo.launchMode != LAUNCH_SINGLE_TASK + && homeInfo.launchMode != LAUNCH_SINGLE_INSTANCE + && homeInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q; + if (!supportMultipleInstance) { + // Can't launch home on other displays if it requested to be single instance. Also we + // don't allow home applications that target before Q to have multiple home activity + // instances because they may not be expected to have multiple home scenario and + // haven't explicitly request for single instance. + return false; + } + + return true; + } + + /** + * Ensure all activities visibility, update orientation and configuration. + * + * @param starting The currently starting activity or {@code null} if there is none. + * @param displayId The id of the display where operation is executed. + * @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to + * {@code true} if config changed. + * @param deferResume Whether to defer resume while updating config. + * @return 'true' if starting activity was kept or wasn't provided, 'false' if it was relaunched + * because of configuration update. + */ + boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId, + boolean markFrozenIfConfigChanged, boolean deferResume) { + // First ensure visibility without updating the config just yet. We need this to know what + // activities are affecting configuration now. + // Passing null here for 'starting' param value, so that visibility of actual starting + // activity will be properly updated. + ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + false /* preserveWindows */, false /* notifyClients */); + + if (displayId == INVALID_DISPLAY) { + // The caller didn't provide a valid display id, skip updating config. + return true; + } + + // Force-update the orientation from the WindowManager, since we need the true configuration + // to send to the client now. + final Configuration config = mWindowManager.updateOrientationFromAppTokens( + getDisplayOverrideConfiguration(displayId), + starting != null && starting.mayFreezeScreenLocked(starting.app) + ? starting.appToken : null, + displayId, true /* forceUpdate */); + if (starting != null && markFrozenIfConfigChanged && config != null) { + starting.frozenBeforeDestroy = true; + } + + // Update the configuration of the activities on the display. + return mService.updateDisplayOverrideConfigurationLocked(config, starting, deferResume, + displayId); + } + + /** + * @return a list of activities which are the top ones in each visible stack. The first + * entry will be the focused activity. + */ + List<IBinder> getTopVisibleActivities() { + final ArrayList<IBinder> topActivityTokens = new ArrayList<>(); + final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); + // Traverse all displays. + for (int i = mActivityDisplays.size() - 1; i >= 0; i--) { + final ActivityDisplay display = mActivityDisplays.get(i); + // Traverse all stacks on a display. + for (int j = display.getChildCount() - 1; j >= 0; --j) { + final ActivityStack stack = display.getChildAt(j); + // Get top activity from a visible stack and add it to the list. + if (stack.shouldBeVisible(null /* starting */)) { + final ActivityRecord top = stack.getTopActivity(); + if (top != null) { + if (stack == topFocusedStack) { + topActivityTokens.add(0, top.appToken); + } else { + topActivityTokens.add(top.appToken); + } + } + } + } + } + return topActivityTokens; + } + + ActivityStack getTopDisplayFocusedStack() { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityStack focusedStack = mActivityDisplays.get(i).getFocusedStack(); + if (focusedStack != null) { + return focusedStack; + } + } + return null; + } + + ActivityRecord getTopResumedActivity() { + final ActivityStack focusedStack = getTopDisplayFocusedStack(); + if (focusedStack == null) { + return null; + } + final ActivityRecord resumedActivity = focusedStack.getResumedActivity(); + if (resumedActivity != null && resumedActivity.app != null) { + return resumedActivity; + } + // The top focused stack might not have a resumed activity yet - look on all displays in + // focus order. + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityDisplay display = mActivityDisplays.get(i); + final ActivityRecord resumedActivityOnDisplay = display.getResumedActivity(); + if (resumedActivityOnDisplay != null) { + return resumedActivityOnDisplay; + } + } + return null; + } + + boolean isFocusable(ConfigurationContainer container, boolean alwaysFocusable) { + if (container.inSplitScreenPrimaryWindowingMode() && mIsDockMinimized) { + return false; + } + + return container.getWindowConfiguration().canReceiveKeys() || alwaysFocusable; + } + + boolean isTopDisplayFocusedStack(ActivityStack stack) { + return stack != null && stack == getTopDisplayFocusedStack(); + } + + void updatePreviousProcess(ActivityRecord r) { + // Now that this process has stopped, we may want to consider it to be the previous app to + // try to keep around in case the user wants to return to it. + + // First, found out what is currently the foreground app, so that we don't blow away the + // previous app if this activity is being hosted by the process that is actually still the + // foreground. + WindowProcessController fgApp = null; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + if (isTopDisplayFocusedStack(stack)) { + final ActivityRecord resumedActivity = stack.getResumedActivity(); + if (resumedActivity != null) { + fgApp = resumedActivity.app; + } else if (stack.mPausingActivity != null) { + fgApp = stack.mPausingActivity.app; + } + break; + } + } + } + + // Now set this one as the previous process, only if that really makes sense to. + if (r.hasProcess() && fgApp != null && r.app != fgApp + && r.lastVisibleTime > mService.mPreviousProcessVisibleTime + && r.app != mService.mHomeProcess) { + mService.mPreviousProcess = r.app; + mService.mPreviousProcessVisibleTime = r.lastVisibleTime; + } + } + + boolean attachApplication(WindowProcessController app) throws RemoteException { + final String processName = app.mName; + boolean didSomething = false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + final ActivityStack stack = display.getFocusedStack(); + if (stack != null) { + stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList); + final ActivityRecord top = stack.topRunningActivityLocked(); + final int size = mTmpActivityList.size(); + for (int i = 0; i < size; i++) { + final ActivityRecord activity = mTmpActivityList.get(i); + if (activity.app == null && app.mUid == activity.info.applicationInfo.uid + && processName.equals(activity.processName)) { + try { + if (mStackSupervisor.realStartActivityLocked(activity, app, + top == activity /* andResume */, true /* checkConfig */)) { + didSomething = true; + } + } catch (RemoteException e) { + Slog.w(TAG, "Exception in new application when starting activity " + + top.intent.getComponent().flattenToShortString(), e); + throw e; + } + } + } + } + } + if (!didSomething) { + ensureActivitiesVisible(null, 0, false /* preserve_windows */); + } + return didSomething; + } + + /** + * Make sure that all activities that need to be visible in the system actually are and update + * their configuration. + */ + void ensureActivitiesVisible(ActivityRecord starting, int configChanges, + boolean preserveWindows) { + ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */); + } + + /** + * @see #ensureActivitiesVisible(ActivityRecord, int, boolean) + */ + void ensureActivitiesVisible(ActivityRecord starting, int configChanges, + boolean preserveWindows, boolean notifyClients) { + mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate(); + try { + // First the front stacks. In case any are not fullscreen and are in front of home. + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows, + notifyClients); + } + } + } finally { + mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate(); + } + } + + boolean switchUser(int userId, UserState uss) { + final int focusStackId = getTopDisplayFocusedStack().getStackId(); + // We dismiss the docked stack whenever we switch users. + final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenPrimaryStack(); + if (dockedStack != null) { + mStackSupervisor.moveTasksToFullscreenStackLocked( + dockedStack, dockedStack.isFocusedStackOnDisplay()); + } + // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will + // also cause all tasks to be moved to the fullscreen stack at a position that is + // appropriate. + removeStacksInWindowingModes(WINDOWING_MODE_PINNED); + + mUserStackInFront.put(mCurrentUser, focusStackId); + final int restoreStackId = + mUserStackInFront.get(userId, getDefaultDisplay().getHomeStack().mStackId); + mCurrentUser = userId; + + mStackSupervisor.mStartingUsers.add(uss); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.switchUserLocked(userId); + TaskRecord task = stack.topTask(); + if (task != null) { + stack.positionChildWindowContainerAtTop(task); + } + } + } + + ActivityStack stack = getStack(restoreStackId); + if (stack == null) { + stack = getDefaultDisplay().getHomeStack(); + } + final boolean homeInFront = stack.isActivityTypeHome(); + if (stack.isOnHomeDisplay()) { + stack.moveToFront("switchUserOnHomeDisplay"); + } else { + // Stack was moved to another display while user was swapped out. + resumeHomeActivity(null, "switchUserOnOtherDisplay", DEFAULT_DISPLAY); + } + return homeInFront; + } + + void removeUser(int userId) { + mUserStackInFront.delete(userId); + } + + /** + * Update the last used stack id for non-current user (current user's last + * used stack is the focused stack) + */ + void updateUserStack(int userId, ActivityStack stack) { + if (userId != mCurrentUser) { + mUserStackInFront.put(userId, stack != null ? stack.getStackId() + : getDefaultDisplay().getHomeStack().mStackId); + } + } + + void resizeStack(ActivityStack stack, Rect bounds, Rect tempTaskBounds, + Rect tempTaskInsetBounds, boolean preserveWindows, boolean allowResizeInDockedMode, + boolean deferResume) { + + if (stack.inSplitScreenPrimaryWindowingMode()) { + mStackSupervisor.resizeDockedStackLocked(bounds, tempTaskBounds, + tempTaskInsetBounds, null, null, preserveWindows, deferResume); + return; + } + + final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenPrimaryStack(); + if (!allowResizeInDockedMode + && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) { + // If the docked stack exists, don't resize non-floating stacks independently of the + // size computed from the docked stack size (otherwise they will be out of sync) + return; + } + + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stack.mStackId); + mWindowManager.deferSurfaceLayout(); + try { + if (stack.affectedBySplitScreenResize()) { + if (bounds == null && stack.inSplitScreenWindowingMode()) { + // null bounds = fullscreen windowing mode...at least for now. + stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + } else if (splitScreenActive) { + // If we are in split-screen mode and this stack support split-screen, then + // it should be split-screen secondary mode. i.e. adjacent to the docked stack. + stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + } + } + stack.resize(bounds, tempTaskBounds, tempTaskInsetBounds); + if (!deferResume) { + stack.ensureVisibleActivitiesConfigurationLocked( + stack.topRunningActivityLocked(), preserveWindows); + } + } finally { + mWindowManager.continueSurfaceLayout(); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + } + + /** + * Move stack with all its existing content to specified display. + * @param stackId Id of stack to move. + * @param displayId Id of display to move stack to. + * @param onTop Indicates whether container should be place on top or on bottom. + */ + void moveStackToDisplay(int stackId, int displayId, boolean onTop) { + final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId=" + + displayId); + } + final ActivityStack stack = getStack(stackId); + if (stack == null) { + throw new IllegalArgumentException("moveStackToDisplay: Unknown stackId=" + + stackId); + } + + final ActivityDisplay currentDisplay = stack.getDisplay(); + if (currentDisplay == null) { + throw new IllegalStateException("moveStackToDisplay: Stack with stack=" + stack + + " is not attached to any display."); + } + + if (currentDisplay.mDisplayId == displayId) { + throw new IllegalArgumentException("Trying to move stack=" + stack + + " to its current displayId=" + displayId); + } + + stack.reparent(activityDisplay, onTop, false /* displayRemoved */); + // TODO(multi-display): resize stacks properly if moved from split-screen. + } + + boolean moveTopStackActivityToPinnedStack(int stackId) { + final ActivityStack stack = getStack(stackId); + if (stack == null) { + throw new IllegalArgumentException( + "moveTopStackActivityToPinnedStack: Unknown stackId=" + stackId); + } + + final ActivityRecord r = stack.topRunningActivityLocked(); + if (r == null) { + Slog.w(TAG, "moveTopStackActivityToPinnedStack: No top running activity" + + " in stack=" + stack); + return false; + } + + if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) { + Slog.w(TAG, "moveTopStackActivityToPinnedStack: Picture-In-Picture not supported for " + + " r=" + r); + return false; + } + + moveActivityToPinnedStack(r, null /* sourceBounds */, 0f /* aspectRatio */, + "moveTopActivityToPinnedStack"); + return true; + } + + void moveActivityToPinnedStack(ActivityRecord r, Rect sourceHintBounds, float aspectRatio, + String reason) { + + mWindowManager.deferSurfaceLayout(); + + final ActivityDisplay display = r.getStack().getDisplay(); + PinnedActivityStack stack = display.getPinnedStack(); + + // This will clear the pinned stack by moving an existing task to the full screen stack, + // ensuring only one task is present. + if (stack != null) { + mStackSupervisor.moveTasksToFullscreenStackLocked(stack, !ON_TOP); + } + + // Need to make sure the pinned stack exist so we can resize it below... + stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP); + + // Calculate the target bounds here before the task is reparented back into pinned windowing + // mode (which will reset the saved bounds) + final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio); + + try { + final TaskRecord task = r.getTask(); + // Resize the pinned stack to match the current size of the task the activity we are + // going to be moving is currently contained in. We do this to have the right starting + // animation bounds for the pinned stack to the desired bounds the caller wants. + resizeStack(stack, task.getOverrideBounds(), null /* tempTaskBounds */, + null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, + true /* allowResizeInDockedMode */, !DEFER_RESUME); + + if (task.mActivities.size() == 1) { + // Defer resume until below, and do not schedule PiP changes until we animate below + task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, DEFER_RESUME, + false /* schedulePictureInPictureModeChange */, reason); + } else { + // There are multiple activities in the task and moving the top activity should + // reveal/leave the other activities in their original task. + + // Currently, we don't support reparenting activities across tasks in two different + // stacks, so instead, just create a new task in the same stack, reparent the + // activity into that task, and then reparent the whole task to the new stack. This + // ensures that all the necessary work to migrate states in the old and new stacks + // is also done. + final TaskRecord newTask = task.getStack().createTaskRecord( + mStackSupervisor.getNextTaskIdForUserLocked(r.userId), r.info, + r.intent, null, null, true); + r.reparent(newTask, MAX_VALUE, "moveActivityToStack"); + + // Defer resume until below, and do not schedule PiP changes until we animate below + newTask.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, + DEFER_RESUME, false /* schedulePictureInPictureModeChange */, reason); + } + + // Reset the state that indicates it can enter PiP while pausing after we've moved it + // to the pinned stack + r.supportsEnterPipOnTaskSwitch = false; + } finally { + mWindowManager.continueSurfaceLayout(); + } + + stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */, + true /* fromFullscreen */); + + // Update the visibility of all activities after the they have been reparented to the new + // stack. This MUST run after the animation above is scheduled to ensure that the windows + // drawn signal is scheduled after the bounds animation start call on the bounds animator + // thread. + ensureActivitiesVisible(null, 0, false /* preserveWindows */); + resumeFocusedStacksTopActivities(); + + mService.getTaskChangeNotificationController().notifyActivityPinned(r); + } + + void executeAppTransitionForAllDisplay() { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + display.getWindowContainerController().executeAppTransition(); + } + } + + void setDockedStackMinimized(boolean minimized) { + // Get currently focused stack before setting mIsDockMinimized. We do this because if + // split-screen is active, primary stack will not be focusable (see #isFocusable) while + // still occluding other stacks. This will cause getTopDisplayFocusedStack() to return null. + final ActivityStack current = getTopDisplayFocusedStack(); + mIsDockMinimized = minimized; + if (mIsDockMinimized) { + if (current.inSplitScreenPrimaryWindowingMode()) { + // The primary split-screen stack can't be focused while it is minimize, so move + // focus to something else. + current.adjustFocusToNextFocusableStack("setDockedStackMinimized"); + } + } + } + + ActivityRecord findTask(ActivityRecord r, int preferredDisplayId) { + if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r); + mTmpFindTaskResult.clear(); + + // Looking up task on preferred display first + final ActivityDisplay preferredDisplay = getActivityDisplay(preferredDisplayId); + if (preferredDisplay != null) { + preferredDisplay.findTaskLocked(r, true /* isPreferredDisplay */, mTmpFindTaskResult); + if (mTmpFindTaskResult.mIdealMatch) { + return mTmpFindTaskResult.mRecord; + } + } + + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + if (display.mDisplayId == preferredDisplayId) { + continue; + } + + display.findTaskLocked(r, false /* isPreferredDisplay */, mTmpFindTaskResult); + if (mTmpFindTaskResult.mIdealMatch) { + return mTmpFindTaskResult.mRecord; + } + } + + if (DEBUG_TASKS && mTmpFindTaskResult.mRecord == null) Slog.d(TAG_TASKS, "No task found"); + return mTmpFindTaskResult.mRecord; + } + + /** + * Finish the topmost activities in all stacks that belong to the crashed app. + * @param app The app that crashed. + * @param reason Reason to perform this action. + * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished. + */ + int finishTopCrashedActivities(WindowProcessController app, String reason) { + TaskRecord finishedTask = null; + ActivityStack focusedStack = getTopDisplayFocusedStack(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + // It is possible that request to finish activity might also remove its task and stack, + // so we need to be careful with indexes in the loop and check child count every time. + for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason); + if (stack == focusedStack || finishedTask == null) { + finishedTask = t; + } + } + } + return finishedTask != null ? finishedTask.taskId : INVALID_TASK_ID; + } + + boolean resumeFocusedStacksTopActivities() { + return resumeFocusedStacksTopActivities(null, null, null); + } + + boolean resumeFocusedStacksTopActivities( + ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { + + if (!mStackSupervisor.readyToResume()) { + return false; + } + + if (targetStack != null && (targetStack.isTopStackOnDisplay() + || getTopDisplayFocusedStack() == targetStack)) { + return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); + } + + // Resume all top activities in focused stacks on all displays. + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + final ActivityStack focusedStack = display.getFocusedStack(); + if (focusedStack == null) { + continue; + } + final ActivityRecord r = focusedStack.topRunningActivityLocked(); + if (r == null || !r.isState(RESUMED)) { + focusedStack.resumeTopActivityUncheckedLocked(null, null); + } else if (r.isState(RESUMED)) { + // Kick off any lingering app transitions form the MoveTaskToFront operation. + focusedStack.executeAppTransition(targetOptions); + } + } + + return false; + } + + void applySleepTokens(boolean applyToStacks) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + // Set the sleeping state of the display. + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + final boolean displayShouldSleep = display.shouldSleep(); + if (displayShouldSleep == display.isSleeping()) { + continue; + } + display.setIsSleeping(displayShouldSleep); + + if (!applyToStacks) { + continue; + } + + // Set the sleeping state of the stacks on the display. + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + if (displayShouldSleep) { + stack.goToSleepIfPossible(false /* shuttingDown */); + } else { + stack.awakeFromSleepingLocked(); + if (stack.isFocusedStackOnDisplay() + && !mStackSupervisor.getKeyguardController() + .isKeyguardOrAodShowing(display.mDisplayId)) { + // If the keyguard is unlocked - resume immediately. + // It is possible that the display will not be awake at the time we + // process the keyguard going away, which can happen before the sleep token + // is released. As a result, it is important we resume the activity here. + resumeFocusedStacksTopActivities(); + } + } + } + + if (displayShouldSleep || mStackSupervisor.mGoingToSleepActivities.isEmpty()) { + continue; + } + // The display is awake now, so clean up the going to sleep list. + for (Iterator<ActivityRecord> it = + mStackSupervisor.mGoingToSleepActivities.iterator(); it.hasNext(); ) { + final ActivityRecord r = it.next(); + if (r.getDisplayId() == display.mDisplayId) { + it.remove(); + } + } + } + } + + protected <T extends ActivityStack> T getStack(int stackId) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final T stack = mActivityDisplays.get(i).getStack(stackId); + if (stack != null) { + return stack; + } + } + return null; + } + + /** @see ActivityDisplay#getStack(int, int) */ + private <T extends ActivityStack> T getStack(int windowingMode, int activityType) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final T stack = mActivityDisplays.get(i).getStack(windowingMode, activityType); + if (stack != null) { + return stack; + } + } + return null; + } + + private ActivityManager.StackInfo getStackInfo(ActivityStack stack) { + final int displayId = stack.mDisplayId; + final ActivityDisplay display = getActivityDisplay(displayId); + ActivityManager.StackInfo info = new ActivityManager.StackInfo(); + stack.getWindowContainerBounds(info.bounds); + info.displayId = displayId; + info.stackId = stack.mStackId; + info.userId = stack.mCurrentUser; + info.visible = stack.shouldBeVisible(null); + // A stack might be not attached to a display. + info.position = display != null ? display.getIndexOf(stack) : 0; + info.configuration.setTo(stack.getConfiguration()); + + ArrayList<TaskRecord> tasks = stack.getAllTasks(); + final int numTasks = tasks.size(); + int[] taskIds = new int[numTasks]; + String[] taskNames = new String[numTasks]; + Rect[] taskBounds = new Rect[numTasks]; + int[] taskUserIds = new int[numTasks]; + for (int i = 0; i < numTasks; ++i) { + final TaskRecord task = tasks.get(i); + taskIds[i] = task.taskId; + taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString() + : task.realActivity != null ? task.realActivity.flattenToString() + : task.getTopActivity() != null ? task.getTopActivity().packageName + : "unknown"; + taskBounds[i] = new Rect(); + task.getWindowContainerBounds(taskBounds[i]); + taskUserIds[i] = task.userId; + } + info.taskIds = taskIds; + info.taskNames = taskNames; + info.taskBounds = taskBounds; + info.taskUserIds = taskUserIds; + + final ActivityRecord top = stack.topRunningActivityLocked(); + info.topActivity = top != null ? top.intent.getComponent() : null; + return info; + } + + ActivityManager.StackInfo getStackInfo(int stackId) { + ActivityStack stack = getStack(stackId); + if (stack != null) { + return getStackInfo(stack); + } + return null; + } + + ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType) { + final ActivityStack stack = getStack(windowingMode, activityType); + return (stack != null) ? getStackInfo(stack) : null; + } + + ArrayList<ActivityManager.StackInfo> getAllStackInfos() { + ArrayList<ActivityManager.StackInfo> list = new ArrayList<>(); + for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + list.add(getStackInfo(stack)); + } + } + return list; + } + + void deferUpdateBounds(int activityType) { + final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); + if (stack != null) { + stack.deferUpdateBounds(); + } + } + + void continueUpdateBounds(int activityType) { + final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); + if (stack != null) { + stack.continueUpdateBounds(); + } + } + + @Override + public void onDisplayAdded(int displayId) { + if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId); + synchronized (mService.mGlobalLock) { + getActivityDisplayOrCreate(displayId); + // Do not start home before booting, or it may accidentally finish booting before it + // starts. Instead, we expect home activities to be launched when the system is ready + // (ActivityManagerService#systemReady). + if (mService.isBooted() || mService.isBooting()) { + startHomeOnDisplay(mCurrentUser, "displayAdded", displayId); + } + } + } + + @Override + public void onDisplayRemoved(int displayId) { + if (DEBUG_STACK) Slog.v(TAG, "Display removed displayId=" + displayId); + if (displayId == DEFAULT_DISPLAY) { + throw new IllegalArgumentException("Can't remove the primary display."); + } + + synchronized (mService.mGlobalLock) { + final ActivityDisplay activityDisplay = getActivityDisplay(displayId); + if (activityDisplay == null) { + return; + } + + activityDisplay.remove(); + } + } + + @Override + public void onDisplayChanged(int displayId) { + if (DEBUG_STACK) Slog.v(TAG, "Display changed displayId=" + displayId); + synchronized (mService.mGlobalLock) { + final ActivityDisplay activityDisplay = getActivityDisplay(displayId); + if (activityDisplay != null) { + activityDisplay.onDisplayChanged(); + } + } + } + + /** Update lists of UIDs that are present on displays and have access to them. */ + void updateUIDsPresentOnDisplay() { + mDisplayAccessUIDs.clear(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); + // Only bother calculating the whitelist for private displays + if (activityDisplay.isPrivate()) { + mDisplayAccessUIDs.append( + activityDisplay.mDisplayId, activityDisplay.getPresentUIDs()); + } + } + // Store updated lists in DisplayManager. Callers from outside of AM should get them there. + mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs); + } + + ActivityStack findStackBehind(ActivityStack stack) { + final ActivityDisplay display = getActivityDisplay(stack.mDisplayId); + if (display != null) { + for (int i = display.getChildCount() - 1; i >= 0; i--) { + if (display.getChildAt(i) == stack && i > 0) { + return display.getChildAt(i - 1); + } + } + } + throw new IllegalStateException("Failed to find a stack behind stack=" + stack + + " in=" + display); + } + + @Override + protected int getChildCount() { + return mActivityDisplays.size(); + } + + @Override + protected ActivityDisplay getChildAt(int index) { + return mActivityDisplays.get(index); + } + + @Override + protected ConfigurationContainer getParent() { + return null; + } + + @Override + public void onChildPositionChanged(DisplayWindowController childController, int position) { + // Assume AM lock is held from positionChildAt of controller in each hierarchy. + final ActivityDisplay display = getActivityDisplay(childController.getDisplayId()); + if (display != null) { + positionChildAt(display, position); + } + } + + /** Change the z-order of the given display. */ + private void positionChildAt(ActivityDisplay display, int position) { + if (position >= mActivityDisplays.size()) { + position = mActivityDisplays.size() - 1; + } else if (position < 0) { + position = 0; + } + + if (mActivityDisplays.isEmpty()) { + mActivityDisplays.add(display); + } else if (mActivityDisplays.get(position) != display) { + mActivityDisplays.remove(display); + mActivityDisplays.add(position, display); + } + } + + @VisibleForTesting + void addChild(ActivityDisplay activityDisplay, int position) { + positionChildAt(activityDisplay, position); + mWindowContainerController.positionChildAt( + activityDisplay.getWindowContainerController(), position); + } + + void removeChild(ActivityDisplay activityDisplay) { + // The caller must tell the controller of {@link ActivityDisplay} to release its container + // {@link DisplayContent}. That is done in {@link ActivityDisplay#releaseSelfIfNeeded}). + mActivityDisplays.remove(activityDisplay); + } + + Configuration getDisplayOverrideConfiguration(int displayId) { + final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException("No display found with id: " + displayId); + } + + return activityDisplay.getOverrideConfiguration(); + } + + void setDisplayOverrideConfiguration(Configuration overrideConfiguration, int displayId) { + final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException("No display found with id: " + displayId); + } + + activityDisplay.onOverrideConfigurationChanged(overrideConfiguration); + } + + void prepareForShutdown() { + for (int i = 0; i < mActivityDisplays.size(); i++) { + createSleepToken("shutdown", mActivityDisplays.get(i).mDisplayId); + } + } + + ActivityTaskManagerInternal.SleepToken createSleepToken(String tag, int displayId) { + final ActivityDisplay display = getActivityDisplay(displayId); + if (display == null) { + throw new IllegalArgumentException("Invalid display: " + displayId); + } + + final SleepTokenImpl token = new SleepTokenImpl(tag, displayId); + mSleepTokens.add(token); + display.mAllSleepTokens.add(token); + return token; + } + + private void removeSleepToken(SleepTokenImpl token) { + mSleepTokens.remove(token); + + final ActivityDisplay display = getActivityDisplay(token.mDisplayId); + if (display != null) { + display.mAllSleepTokens.remove(token); + if (display.mAllSleepTokens.isEmpty()) { + mService.updateSleepIfNeededLocked(); + } + } + } + + void addStartingWindowsForVisibleActivities(boolean taskSwitch) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.addStartingWindowsForVisibleActivities(taskSwitch); + } + } + } + + void invalidateTaskLayers() { + mTaskLayersChanged = true; + } + + void rankTaskLayersIfNeeded() { + if (!mTaskLayersChanged) { + return; + } + mTaskLayersChanged = false; + for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + int baseLayer = 0; + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + baseLayer += stack.rankTaskLayers(baseLayer); + } + } + } + + void clearOtherAppTimeTrackers(AppTimeTracker except) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.clearOtherAppTimeTrackers(except); + } + } + } + + void scheduleDestroyAllActivities(WindowProcessController app, String reason) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.scheduleDestroyActivities(app, reason); + } + } + } + + void releaseSomeActivitiesLocked(WindowProcessController app, String reason) { + // Tasks is non-null only if two or more tasks are found. + ArraySet<TaskRecord> tasks = app.getReleaseSomeActivitiesTasks(); + if (tasks == null) { + if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release"); + return; + } + // If we have activities in multiple tasks that are in a position to be destroyed, + // let's iterate through the tasks and release the oldest one. + final int numDisplays = mActivityDisplays.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + final int stackCount = display.getChildCount(); + // Step through all stacks starting from behind, to hit the oldest things first. + for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) { + final ActivityStack stack = display.getChildAt(stackNdx); + // Try to release activities in this stack; if we manage to, we are done. + if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) { + return; + } + } + } + } + + // Tries to put all activity stacks to sleep. Returns true if all stacks were + // successfully put to sleep. + boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) { + boolean allSleep = true; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + if (allowDelay) { + allSleep &= stack.goToSleepIfPossible(shuttingDown); + } else { + stack.goToSleep(); + } + } + } + return allSleep; + } + + void handleAppCrash(WindowProcessController app) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.handleAppCrash(app); + } + } + } + + ActivityRecord findActivity(Intent intent, ActivityInfo info, boolean compareIntentFilters) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityRecord ar = stack.findActivityLocked( + intent, info, compareIntentFilters); + if (ar != null) { + return ar; + } + } + } + return null; + } + + boolean hasAwakeDisplay() { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + if (!display.shouldSleep()) { + return true; + } + } + return false; + } + + <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, + @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) { + return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */); + } + + /** + * Returns the right stack to use for launching factoring in all the input parameters. + * + * @param r The activity we are trying to launch. Can be null. + * @param options The activity options used to the launch. Can be null. + * @param candidateTask The possible task the activity might be launched in. Can be null. + * @params launchParams The resolved launch params to use. + * + * @return The stack to use for the launch or INVALID_STACK_ID. + */ + <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, + @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop, + @Nullable LaunchParamsController.LaunchParams launchParams) { + int taskId = INVALID_TASK_ID; + int displayId = INVALID_DISPLAY; + //Rect bounds = null; + + // We give preference to the launch preference in activity options. + if (options != null) { + taskId = options.getLaunchTaskId(); + displayId = options.getLaunchDisplayId(); + } + + // First preference for stack goes to the task Id set in the activity options. Use the stack + // associated with that if possible. + if (taskId != INVALID_TASK_ID) { + // Temporarily set the task id to invalid in case in re-entry. + options.setLaunchTaskId(INVALID_TASK_ID); + final TaskRecord task = anyTaskForId(taskId, + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop); + options.setLaunchTaskId(taskId); + if (task != null) { + return task.getStack(); + } + } + + final int activityType = resolveActivityType(r, options, candidateTask); + T stack; + + // Next preference for stack goes to the display Id set the candidate display. + if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) { + displayId = launchParams.mPreferredDisplayId; + } + if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) { + if (r != null) { + stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options, + launchParams); + if (stack != null) { + return stack; + } + } + final ActivityDisplay display = getActivityDisplayOrCreate(displayId); + if (display != null) { + stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop); + if (stack != null) { + return stack; + } + } + } + + // Give preference to the stack and display of the input task and activity if they match the + // mode we want to launch into. + stack = null; + ActivityDisplay display = null; + if (candidateTask != null) { + stack = candidateTask.getStack(); + } + if (stack == null && r != null) { + stack = r.getStack(); + } + if (stack != null) { + display = stack.getDisplay(); + if (display != null && canLaunchOnDisplay(r, display.mDisplayId)) { + int windowingMode = launchParams != null ? launchParams.mWindowingMode + : WindowConfiguration.WINDOWING_MODE_UNDEFINED; + if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) { + windowingMode = display.resolveWindowingMode(r, options, candidateTask, + activityType); + } + if (stack.isCompatible(windowingMode, activityType)) { + return stack; + } + if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY + && display.getSplitScreenPrimaryStack() == stack + && candidateTask == stack.topTask()) { + // This is a special case when we try to launch an activity that is currently on + // top of split-screen primary stack, but is targeting split-screen secondary. + // In this case we don't want to move it to another stack. + // TODO(b/78788972): Remove after differentiating between preferred and required + // launch options. + return stack; + } + } + } + + if (display == null || !canLaunchOnDisplay(r, display.mDisplayId)) { + display = getDefaultDisplay(); + } + + return display.getOrCreateStack(r, options, candidateTask, activityType, onTop); + } + + /** @return true if activity record is null or can be launched on provided display. */ + private boolean canLaunchOnDisplay(ActivityRecord r, int displayId) { + if (r == null) { + return true; + } + return r.canBeLaunchedOnDisplay(displayId); + } + + /** + * Get a topmost stack on the display, that is a valid launch stack for specified activity. + * If there is no such stack, new dynamic stack can be created. + * @param displayId Target display. + * @param r Activity that should be launched there. + * @param candidateTask The possible task the activity might be put in. + * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null. + */ + private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r, + @Nullable TaskRecord candidateTask, @Nullable ActivityOptions options, + @Nullable LaunchParamsController.LaunchParams launchParams) { + final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException( + "Display with displayId=" + displayId + " not found."); + } + + if (!r.canBeLaunchedOnDisplay(displayId)) { + return null; + } + + // If {@code r} is already in target display and its task is the same as the candidate task, + // the intention should be getting a launch stack for the reusable activity, so we can use + // the existing stack. + if (r.getDisplayId() == displayId && r.getTask() == candidateTask) { + return candidateTask.getStack(); + } + + // Return the topmost valid stack on the display. + for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) { + final ActivityStack stack = activityDisplay.getChildAt(i); + if (isValidLaunchStack(stack, r)) { + return stack; + } + } + + // If there is no valid stack on the external display - check if new dynamic stack will do. + if (displayId != DEFAULT_DISPLAY) { + final int windowingMode; + if (launchParams != null) { + // When launch params is not null, we always defer to its windowing mode. Sometimes + // it could be unspecified, which indicates it should inherit windowing mode from + // display. + windowingMode = launchParams.mWindowingMode; + } else { + windowingMode = options != null ? options.getLaunchWindowingMode() + : r.getWindowingMode(); + } + final int activityType = + options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED + ? options.getLaunchActivityType() : r.getActivityType(); + return activityDisplay.createStack(windowingMode, activityType, true /*onTop*/); + } + + Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId); + return null; + } + + ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r, + @Nullable ActivityOptions options, + @Nullable LaunchParamsController.LaunchParams launchParams) { + return getValidLaunchStackOnDisplay(displayId, r, null /* candidateTask */, options, + launchParams); + } + + // TODO: Can probably be consolidated into getLaunchStack()... + private boolean isValidLaunchStack(ActivityStack stack, ActivityRecord r) { + switch (stack.getActivityType()) { + case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome(); + case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents(); + case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant(); + } + // There is a 1-to-1 relationship between stack and task when not in + // primary split-windowing mode. + if (stack.getWindowingMode() != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + return false; + } else { + return r.supportsSplitScreenWindowingMode(); + } + } + + int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + @Nullable TaskRecord task) { + // Preference is given to the activity type for the activity then the task since the type + // once set shouldn't change. + int activityType = r != null ? r.getActivityType() : ACTIVITY_TYPE_UNDEFINED; + if (activityType == ACTIVITY_TYPE_UNDEFINED && task != null) { + activityType = task.getActivityType(); + } + if (activityType != ACTIVITY_TYPE_UNDEFINED) { + return activityType; + } + if (options != null) { + activityType = options.getLaunchActivityType(); + } + return activityType != ACTIVITY_TYPE_UNDEFINED ? activityType : ACTIVITY_TYPE_STANDARD; + } + + /** + * Get next focusable stack in the system. This will search through the stack on the same + * display as the current focused stack, looking for a focusable and visible stack, different + * from the target stack. If no valid candidates will be found, it will then go through all + * displays and stacks in last-focused order. + * + * @param currentFocus The stack that previously had focus. + * @param ignoreCurrent If we should ignore {@param currentFocus} when searching for next + * candidate. + * @return Next focusable {@link ActivityStack}, {@code null} if not found. + */ + ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus, + boolean ignoreCurrent) { + // First look for next focusable stack on the same display + final ActivityDisplay preferredDisplay = currentFocus.getDisplay(); + final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack( + currentFocus, ignoreCurrent); + if (preferredFocusableStack != null) { + return preferredFocusableStack; + } + if (preferredDisplay.supportsSystemDecorations()) { + // Stop looking for focusable stack on other displays because the preferred display + // supports system decorations. Home activity would be launched on the same display if + // no focusable stack found. + return null; + } + + // Now look through all displays + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityDisplay display = mActivityDisplays.get(i); + if (display == preferredDisplay) { + // We've already checked this one + continue; + } + final ActivityStack nextFocusableStack = display.getNextFocusableStack(currentFocus, + ignoreCurrent); + if (nextFocusableStack != null) { + return nextFocusableStack; + } + } + + return null; + } + + /** + * Get next valid stack for launching provided activity in the system. This will search across + * displays and stacks in last-focused order for a focusable and visible stack, except those + * that are on a currently focused display. + * + * @param r The activity that is being launched. + * @param currentFocus The display that previously had focus and thus needs to be ignored when + * searching for the next candidate. + * @return Next valid {@link ActivityStack}, null if not found. + */ + ActivityStack getNextValidLaunchStack(@NonNull ActivityRecord r, int currentFocus) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityDisplay display = mActivityDisplays.get(i); + if (display.mDisplayId == currentFocus) { + continue; + } + final ActivityStack stack = getValidLaunchStackOnDisplay(display.mDisplayId, r, + null /* options */, null /* launchParams */); + if (stack != null) { + return stack; + } + } + return null; + } + + boolean handleAppDied(WindowProcessController app) { + boolean hasVisibleActivities = false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + hasVisibleActivities |= stack.handleAppDiedLocked(app); + } + } + return hasVisibleActivities; + } + + void closeSystemDialogs() { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.closeSystemDialogsLocked(); + } + } + } + + /** @return true if some activity was finished (or would have finished if doit were true). */ + boolean finishDisabledPackageActivities(String packageName, Set<String> filterByClasses, + boolean doit, boolean evenPersistent, int userId) { + boolean didSomething = false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + if (stack.finishDisabledPackageActivitiesLocked( + packageName, filterByClasses, doit, evenPersistent, userId)) { + didSomething = true; + } + } + } + return didSomething; + } + + void updateActivityApplicationInfo(ApplicationInfo aInfo) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.updateActivityApplicationInfoLocked(aInfo); + } + } + } + + void finishVoiceTask(IVoiceInteractionSession session) { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + final int numStacks = display.getChildCount(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.finishVoiceTask(session); + } + } + } + + /** + * Removes stacks in the input windowing modes from the system if they are of activity type + * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED + */ + void removeStacksInWindowingModes(int... windowingModes) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + mActivityDisplays.get(i).removeStacksInWindowingModes(windowingModes); + } + } + + void removeStacksWithActivityTypes(int... activityTypes) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + mActivityDisplays.get(i).removeStacksWithActivityTypes(activityTypes); + } + } + + ActivityRecord topRunningActivity() { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityRecord topActivity = mActivityDisplays.get(i).topRunningActivity(); + if (topActivity != null) { + return topActivity; + } + } + return null; + } + + boolean allResumedActivitiesIdle() { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + // TODO(b/117135575): Check resumed activities on all visible stacks. + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + if (display.isSleeping()) { + // No resumed activities while display is sleeping. + continue; + } + + // If the focused stack is not null or not empty, there should have some activities + // resuming or resumed. Make sure these activities are idle. + final ActivityStack stack = display.getFocusedStack(); + if (stack == null || stack.numActivities() == 0) { + continue; + } + final ActivityRecord resumedActivity = stack.getResumedActivity(); + if (resumedActivity == null || !resumedActivity.idle) { + if (DEBUG_STATES) { + Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack=" + + stack.mStackId + " " + resumedActivity + " not idle"); + } + return false; + } + } + // Send launch end powerhint when idle + sendPowerHintForLaunchEndIfNeeded(); + return true; + } + + boolean allResumedActivitiesVisible() { + boolean foundResumed = false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityRecord r = stack.getResumedActivity(); + if (r != null) { + if (!r.nowVisible + || mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) { + return false; + } + foundResumed = true; + } + } + } + return foundResumed; + } + + boolean allPausedActivitiesComplete() { + boolean pausing = true; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityRecord r = stack.mPausingActivity; + if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) { + if (DEBUG_STATES) { + Slog.d(TAG_STATES, + "allPausedActivitiesComplete: r=" + r + " state=" + r.getState()); + pausing = false; + } else { + return false; + } + } + } + } + return pausing; + } + + /** + * Find all visible task stacks containing {@param userId} and intercept them with an activity + * to block out the contents and possibly start a credential-confirming intent. + * + * @param userId user handle for the locked managed profile. + */ + void lockAllProfileTasks(@UserIdInt int userId) { + mWindowManager.deferSurfaceLayout(); + try { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final List<TaskRecord> tasks = stack.getAllTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) { + final TaskRecord task = tasks.get(taskNdx); + + // Check the task for a top activity belonging to userId, or returning a + // result to an activity belonging to userId. Example case: a document + // picker for personal files, opened by a work app, should still get locked. + if (taskTopActivityIsUser(task, userId)) { + mService.getTaskChangeNotificationController().notifyTaskProfileLocked( + task.taskId, userId); + } + } + } + } + } finally { + mWindowManager.continueSurfaceLayout(); + } + } + + /** + * Detects whether we should show a lock screen in front of this task for a locked user. + * <p> + * We'll do this if either of the following holds: + * <ul> + * <li>The top activity explicitly belongs to {@param userId}.</li> + * <li>The top activity returns a result to an activity belonging to {@param userId}.</li> + * </ul> + * + * @return {@code true} if the top activity looks like it belongs to {@param userId}. + */ + private boolean taskTopActivityIsUser(TaskRecord task, @UserIdInt int userId) { + // To handle the case that work app is in the task but just is not the top one. + final ActivityRecord activityRecord = task.getTopActivity(); + final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null); + + return (activityRecord != null && activityRecord.userId == userId) + || (resultTo != null && resultTo.userId == userId); + } + + void cancelInitializingActivities() { + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + stack.cancelInitializingActivities(); + } + } + } + + TaskRecord anyTaskForId(int id) { + return anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE); + } + + TaskRecord anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode) { + return anyTaskForId(id, matchMode, null, !ON_TOP); + } + + /** + * Returns a {@link TaskRecord} for the input id if available. {@code null} otherwise. + * @param id Id of the task we would like returned. + * @param matchMode The mode to match the given task id in. + * @param aOptions The activity options to use for restoration. Can be null. + * @param onTop If the stack for the task should be the topmost on the display. + */ + TaskRecord anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode, + @Nullable ActivityOptions aOptions, boolean onTop) { + // If options are set, ensure that we are attempting to actually restore a task + if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) { + throw new IllegalArgumentException("Should not specify activity options for non-restore" + + " lookup"); + } + + int numDisplays = mActivityDisplays.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final TaskRecord task = stack.taskForIdLocked(id); + if (task == null) { + continue; + } + if (aOptions != null) { + // Resolve the stack the task should be placed in now based on options + // and reparent if needed. + final ActivityStack launchStack = + getLaunchStack(null, aOptions, task, onTop); + if (launchStack != null && stack != launchStack) { + final int reparentMode = onTop + ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE; + task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME, + "anyTaskForId"); + } + } + return task; + } + } + + // If we are matching stack tasks only, return now + if (matchMode == MATCH_TASK_IN_STACKS_ONLY) { + return null; + } + + // Otherwise, check the recent tasks and return if we find it there and we are not restoring + // the task from recents + if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents"); + final TaskRecord task = mStackSupervisor.mRecentTasks.getTask(id); + + if (task == null) { + if (DEBUG_RECENTS) { + Slog.d(TAG_RECENTS, "\tDidn't find task id=" + id + " in recents"); + } + + return null; + } + + if (matchMode == MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) { + return task; + } + + // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE + if (!mStackSupervisor.restoreRecentTaskLocked(task, aOptions, onTop)) { + if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, + "Couldn't restore task id=" + id + " found in recents"); + return null; + } + if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents"); + return task; + } + + ActivityRecord isInAnyStack(IBinder token) { + int numDisplays = mActivityDisplays.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityRecord r = stack.isInStackLocked(token); + if (r != null) { + return r; + } + } + } + return null; + } + + @VisibleForTesting + void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list, + @WindowConfiguration.ActivityType int ignoreActivityType, + @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid, + boolean allowed) { + mStackSupervisor.mRunningTasks.getTasks(maxNum, list, ignoreActivityType, + ignoreWindowingMode, mActivityDisplays, callingUid, allowed); + } + + void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) { + boolean sendHint = forceSend; + + if (!sendHint) { + // Send power hint if we don't know what we're launching yet + sendHint = targetActivity == null || targetActivity.app == null; + } + + if (!sendHint) { // targetActivity != null + // Send power hint when the activity's process is different than the current resumed + // activity on all displays, or if there are no resumed activities in the system. + boolean noResumedActivities = true; + boolean allFocusedProcessesDiffer = true; + for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); + final ActivityRecord resumedActivity = activityDisplay.getResumedActivity(); + final WindowProcessController resumedActivityProcess = + resumedActivity == null ? null : resumedActivity.app; + + noResumedActivities &= resumedActivityProcess == null; + if (resumedActivityProcess != null) { + allFocusedProcessesDiffer &= !resumedActivityProcess.equals(targetActivity.app); + } + } + sendHint = noResumedActivities || allFocusedProcessesDiffer; + } + + if (sendHint && mService.mPowerManagerInternal != null) { + mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 1); + mPowerHintSent = true; + } + } + + void sendPowerHintForLaunchEndIfNeeded() { + // Trigger launch power hint if activity is launched + if (mPowerHintSent && mService.mPowerManagerInternal != null) { + mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 0); + mPowerHintSent = false; + } + } + + private void calculateDefaultMinimalSizeOfResizeableTasks() { + final Resources res = mService.mContext.getResources(); + final float minimalSize = res.getDimension( + com.android.internal.R.dimen.default_minimal_size_resizable_task); + final DisplayMetrics dm = res.getDisplayMetrics(); + + mDefaultMinSizeOfResizeableTaskDp = (int) (minimalSize / dm.density); + } + + /** + * Dumps the activities matching the given {@param name} in the either the focused stack + * or all visible stacks if {@param dumpVisibleStacks} is true. + */ + ArrayList<ActivityRecord> getDumpActivities(String name, boolean dumpVisibleStacksOnly, + boolean dumpFocusedStackOnly) { + if (dumpFocusedStackOnly) { + return getTopDisplayFocusedStack().getDumpActivitiesLocked(name); + } else { + ArrayList<ActivityRecord> activities = new ArrayList<>(); + int numDisplays = mActivityDisplays.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { + activities.addAll(stack.getDumpActivitiesLocked(name)); + } + } + } + return activities; + } + } + + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); + pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack()); + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityDisplay display = mActivityDisplays.get(i); + display.dump(pw, prefix); + } + } + + /** + * Dump all connected displays' configurations. + * @param prefix Prefix to apply to each line of the dump. + */ + void dumpDisplayConfigs(PrintWriter pw, String prefix) { + pw.print(prefix); pw.println("Display override configurations:"); + final int displayCount = mActivityDisplays.size(); + for (int i = 0; i < displayCount; i++) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(i); + pw.print(prefix); pw.print(" "); pw.print(activityDisplay.mDisplayId); pw.print(": "); + pw.println(activityDisplay.getOverrideConfiguration()); + } + } + + public void dumpDisplays(PrintWriter pw) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + final ActivityDisplay display = mActivityDisplays.get(i); + pw.print("[id:" + display.mDisplayId + " stacks:"); + display.dumpStacks(pw); + pw.print("]"); + } + } + + boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, + String dumpPackage) { + boolean printed = false; + boolean needSep = false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); + pw.print("Display #"); pw.print(activityDisplay.mDisplayId); + pw.println(" (activities from top to bottom):"); + final ActivityDisplay display = mActivityDisplays.get(displayNdx); + for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = display.getChildAt(stackNdx); + pw.println(); + pw.println(" Stack #" + stack.mStackId + + ": type=" + activityTypeToString(stack.getActivityType()) + + " mode=" + windowingModeToString(stack.getWindowingMode())); + pw.println(" isSleeping=" + stack.shouldSleepActivities()); + pw.println(" mBounds=" + stack.getOverrideBounds()); + + printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, + needSep); + + printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, + !dumpAll, false, dumpPackage, true, + " Running activities (most recent first):", null); + + needSep = printed; + boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, + " mPausingActivity: "); + if (pr) { + printed = true; + needSep = false; + } + pr = printThisActivity(pw, stack.getResumedActivity(), dumpPackage, needSep, + " mResumedActivity: "); + if (pr) { + printed = true; + needSep = false; + } + if (dumpAll) { + pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, + " mLastPausedActivity: "); + if (pr) { + printed = true; + needSep = true; + } + printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, + needSep, " mLastNoHistoryActivity: "); + } + needSep = printed; + } + printThisActivity(pw, activityDisplay.getResumedActivity(), dumpPackage, needSep, + " ResumedActivity:"); + } + + printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ", + "Fin", false, !dumpAll, + false, dumpPackage, true, " Activities waiting to finish:", null); + printed |= dumpHistoryList(fd, pw, mStackSupervisor.mStoppingActivities, " ", + "Stop", false, !dumpAll, + false, dumpPackage, true, " Activities waiting to stop:", null); + printed |= dumpHistoryList(fd, pw, + mStackSupervisor.mActivitiesWaitingForVisibleActivity, " ", "Wait", + false, !dumpAll, false, dumpPackage, true, + " Activities waiting for another to become visible:", null); + printed |= dumpHistoryList(fd, pw, mStackSupervisor.mGoingToSleepActivities, + " ", "Sleep", false, !dumpAll, + false, dumpPackage, true, " Activities waiting to sleep:", null); + + return printed; + } + + void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */); + for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx); + activityDisplay.writeToProto(proto, DISPLAYS); + } + mStackSupervisor.getKeyguardController().writeToProto(proto, KEYGUARD_CONTROLLER); + // TODO(b/111541062): Update tests to look for resumed activities on all displays + final ActivityStack focusedStack = getTopDisplayFocusedStack(); + if (focusedStack != null) { + proto.write(FOCUSED_STACK_ID, focusedStack.mStackId); + final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity(); + if (focusedActivity != null) { + focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); + } + } else { + proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); + } + proto.write(IS_HOME_RECENTS_COMPONENT, + mStackSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); + mService.getActivityStartController().writeToProto(proto, PENDING_ACTIVITIES); + proto.end(token); + } + + private final class SleepTokenImpl extends ActivityTaskManagerInternal.SleepToken { + private final String mTag; + private final long mAcquireTime; + private final int mDisplayId; + + public SleepTokenImpl(String tag, int displayId) { + mTag = tag; + mDisplayId = displayId; + mAcquireTime = SystemClock.uptimeMillis(); + } + + @Override + public void release() { + synchronized (mService.mGlobalLock) { + removeSleepToken(this); + } + } + + @Override + public String toString() { + return "{\"" + mTag + "\", display " + mDisplayId + + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}"; + } + } +} diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index b483fd3bc642..fd9120a6c12e 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -189,9 +189,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { mService.mH.sendMessage(msg); } }); - final WindowState topFocusedWindow = getTopFocusedDisplayContent().mCurrentFocus; - mService.mInputManager.setFocusedWindow( - topFocusedWindow != null ? topFocusedWindow.mInputWindowHandle : null); + return changed; } diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java index 95ca0a679ca2..05f556c0f98a 100644 --- a/services/core/java/com/android/server/wm/SeamlessRotator.java +++ b/services/core/java/com/android/server/wm/SeamlessRotator.java @@ -89,13 +89,16 @@ public class SeamlessRotator { * Removing the transform and the result of the {@link WindowState} layout are both tied to the * {@link WindowState} next frame, such that they apply at the same time the client draws the * window in the new orientation. + * + * In the case of a rotation timeout, we want to remove the transform immediately and not defer + * it. */ - public void finish(WindowState win) { + public void finish(WindowState win, boolean timeout) { mTransform.reset(); final Transaction t = win.getPendingTransaction(); t.setMatrix(win.mSurfaceControl, mTransform, mFloat9); t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y); - if (win.mWinAnimator.mSurfaceController != null) { + if (win.mWinAnimator.mSurfaceController != null && !timeout) { t.deferTransactionUntil(win.mSurfaceControl, win.mWinAnimator.mSurfaceController.getHandle(), win.getFrameNumber()); t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl, diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 117984af67e7..4ae2a79e2697 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -138,7 +138,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { // STEP 1: Determine the display to launch the activity/task. final int displayId = getPreferredLaunchDisplay(task, options, source, currentParams); outParams.mPreferredDisplayId = displayId; - ActivityDisplay display = mSupervisor.getActivityDisplay(displayId); + ActivityDisplay display = mSupervisor.mRootActivityContainer.getActivityDisplay(displayId); if (DEBUG) { appendLog("display-id=" + outParams.mPreferredDisplayId + " display-windowing-mode=" + display.getWindowingMode()); @@ -300,12 +300,14 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { displayId = stack.mDisplayId; } - if (displayId != INVALID_DISPLAY && mSupervisor.getActivityDisplay(displayId) == null) { + if (displayId != INVALID_DISPLAY + && mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) == null) { displayId = currentParams.mPreferredDisplayId; } displayId = (displayId == INVALID_DISPLAY) ? currentParams.mPreferredDisplayId : displayId; - return (displayId != INVALID_DISPLAY && mSupervisor.getActivityDisplay(displayId) != null) + return (displayId != INVALID_DISPLAY + && mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) != null) ? displayId : DEFAULT_DISPLAY; } @@ -606,7 +608,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { || displayBounds.height() < inOutBounds.height()) { // There is no way for us to fit the bounds in the display without changing width // or height. Just move the start to align with the display. - final int layoutDirection = mSupervisor.getConfiguration().getLayoutDirection(); + final int layoutDirection = + mSupervisor.mRootActivityContainer.getConfiguration().getLayoutDirection(); final int left = layoutDirection == View.LAYOUT_DIRECTION_RTL ? displayBounds.width() - inOutBounds.width() : 0; diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java index 8120dec7e48f..d50af385865e 100644 --- a/services/core/java/com/android/server/wm/TaskPersister.java +++ b/services/core/java/com/android/server/wm/TaskPersister.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; import android.annotation.NonNull; import android.graphics.Bitmap; @@ -330,7 +330,7 @@ public class TaskPersister implements PersisterQueue.Listener { // mWriteQueue.add(new TaskWriteQueueItem(task)); final int taskId = task.taskId; - if (mStackSupervisor.anyTaskForIdLocked(taskId, + if (mService.mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) { // Should not happen. Slog.wtf(TAG, "Existing task with taskId " + taskId + "found"); diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 7182ad6fccfe..b88e581d5783 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -33,6 +33,7 @@ import android.annotation.IntDef; import android.app.IActivityTaskManager; import android.graphics.Point; import android.graphics.Rect; +import android.os.Binder; import android.os.Looper; import android.os.Process; import android.os.RemoteException; @@ -261,7 +262,7 @@ class TaskPositioner { mClientChannel, mService.mAnimationHandler.getLooper(), mService.mAnimator.getChoreographer()); - mDragApplicationHandle = new InputApplicationHandle(null); + mDragApplicationHandle = new InputApplicationHandle(new Binder()); mDragApplicationHandle.name = TAG; mDragApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; @@ -269,7 +270,7 @@ class TaskPositioner { mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, display.getDisplayId()); mDragWindowHandle.name = TAG; - mDragWindowHandle.inputChannel = mServerChannel; + mDragWindowHandle.token = mServerChannel.getToken(); mDragWindowHandle.layer = mService.getDragLayerLocked(); mDragWindowHandle.layoutParamsFlags = 0; mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG; diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 51567a0d6ad0..28bc039d6ee4 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -21,10 +21,14 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.Nullable; import android.app.IActivityTaskManager; +import android.graphics.Point; +import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Slog; +import android.view.Display; +import android.view.SurfaceControl; import android.view.IWindow; import com.android.internal.annotations.GuardedBy; @@ -39,10 +43,14 @@ class TaskPositioningController { private final InputManagerService mInputManager; private final IActivityTaskManager mActivityManager; private final Handler mHandler; + private SurfaceControl mInputSurface; + private DisplayContent mPositioningDisplay; @GuardedBy("WindowManagerSerivce.mWindowMap") private @Nullable TaskPositioner mTaskPositioner; + private final Rect mTmpClipRect = new Rect(); + boolean isPositioningLocked() { return mTaskPositioner != null; } @@ -59,6 +67,43 @@ class TaskPositioningController { mHandler = new Handler(looper); } + void hideInputSurface(SurfaceControl.Transaction t, int displayId) { + if (mPositioningDisplay != null && mPositioningDisplay.getDisplayId() == displayId + && mInputSurface != null) { + t.hide(mInputSurface); + } + } + + void showInputSurface(SurfaceControl.Transaction t, int displayId) { + if (mPositioningDisplay == null || mPositioningDisplay.getDisplayId() != displayId) { + return; + } + final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); + if (mInputSurface == null) { + mInputSurface = mService.makeSurfaceBuilder(dc.getSession()) + .setContainerLayer(true) + .setName("Drag and Drop Input Consumer").setSize(1, 1).build(); + } + + final InputWindowHandle h = getDragWindowHandleLocked(); + if (h == null) { + Slog.w(TAG_WM, "Drag is in progress but there is no " + + "drag window handle."); + return; + } + + t.show(mInputSurface); + t.setInputWindowInfo(mInputSurface, h); + t.setLayer(mInputSurface, Integer.MAX_VALUE); + + final Display display = dc.getDisplay(); + final Point p = new Point(); + display.getRealSize(p); + + mTmpClipRect.set(0, 0, p.x, p.y); + t.setWindowCrop(mInputSurface, mTmpClipRect); + } + boolean startMovingTask(IWindow window, float startX, float startY) { WindowState win = null; synchronized (mService.mGlobalLock) { @@ -122,6 +167,7 @@ class TaskPositioningController { Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win); return false; } + mPositioningDisplay = displayContent; mTaskPositioner = TaskPositioner.create(mService); mTaskPositioner.register(displayContent); @@ -157,6 +203,7 @@ class TaskPositioningController { mTaskPositioner.unregister(); mTaskPositioner = null; } + mPositioningDisplay = null; } }); } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index eec10aba5df2..a28b8759fb5b 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -472,8 +472,8 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont } mResizeMode = resizeMode; mWindowContainerController.setResizeable(resizeMode); - mService.mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); - mService.mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); + mService.mRootActivityContainer.resumeFocusedStacksTopActivities(); } void setTaskDockedResizing(boolean resizing) { @@ -544,10 +544,9 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont // this won't cause tons of irrelevant windows being preserved because only // activities in this task may experience a bounds change. Configs for other // activities stay the same. - mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, - preserveWindow); + mService.mRootActivityContainer.ensureActivitiesVisible(r, 0, preserveWindow); if (!kept) { - mService.mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); + mService.mRootActivityContainer.resumeFocusedStacksTopActivities(); } } } @@ -623,6 +622,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason) { final ActivityStackSupervisor supervisor = mService.mStackSupervisor; + final RootActivityContainer root = mService.mRootActivityContainer; final WindowManagerService windowManager = mService.mWindowManager; final ActivityStack sourceStack = getStack(); final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack, @@ -655,7 +655,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont boolean kept = true; try { final ActivityRecord r = topRunningActivityLocked(); - final boolean wasFocused = r != null && supervisor.isTopDisplayFocusedStack(sourceStack) + final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack) && (topRunningActivityLocked() == r); final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r; final boolean wasPaused = r != null && sourceStack.mPausingActivity == r; @@ -748,8 +748,8 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont if (!deferResume) { // The task might have already been running and its visibility needs to be synchronized // with the visibility of the stack / windows. - supervisor.ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow); - supervisor.resumeFocusedStacksTopActivitiesLocked(); + root.ensureActivitiesVisible(null, 0, !mightReplaceWindow); + root.resumeFocusedStacksTopActivities(); } // TODO: Handle incorrect request to move before the actual move, not after. @@ -982,7 +982,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont @Override protected void onParentChanged() { super.onParentChanged(); - mService.mStackSupervisor.updateUIDsPresentOnDisplay(); + mService.mRootActivityContainer.updateUIDsPresentOnDisplay(); } // Close up recents linked list. @@ -1143,7 +1143,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont } boolean okToShowLocked() { - // NOTE: If {@link TaskRecord#topRunningActivityLocked} return is not null then it is + // NOTE: If {@link TaskRecord#topRunningActivity} return is not null then it is // okay to show the activity when locked. return mService.mStackSupervisor.isCurrentProfileLocked(userId) || topRunningActivityLocked() != null; @@ -1274,7 +1274,7 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont // Make sure the list of display UID whitelists is updated // now that this record is in a new task. - mService.mStackSupervisor.updateUIDsPresentOnDisplay(); + mService.mRootActivityContainer.updateUIDsPresentOnDisplay(); } /** @@ -1683,9 +1683,9 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont // to do this for the pinned stack as the bounds are controlled by the system. if (!inPinnedWindowingMode()) { final int defaultMinSizeDp = - mService.mStackSupervisor.mDefaultMinSizeOfResizeableTaskDp; + mService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp; final ActivityDisplay display = - mService.mStackSupervisor.getActivityDisplay(mStack.mDisplayId); + mService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId); final float density = (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT; final int defaultMinSize = (int) (defaultMinSizeDp * density); diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 449c4091f94c..b8a0739b9c83 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.view.Display.DEFAULT_DISPLAY; - import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -260,8 +258,7 @@ public class WindowAnimator { if (DEBUG_WINDOW_TRACE) { Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams) - + " mPendingLayoutChanges(DEFAULT_DISPLAY)=" - + Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY))); + + " hasPendingLayoutChanges=" + hasPendingLayoutChanges); } } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 39a8465a31b3..5df34517956a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -599,7 +599,6 @@ public class WindowManagerService extends IWindowManager.Stub long mDisplayFreezeTime = 0; int mLastDisplayFreezeDuration = 0; Object mLastFinishedFreezeSource = null; - boolean mWaitingForConfig = false; boolean mSwitchingUser = false; final static int WINDOWS_FREEZING_SCREENS_NONE = 0; @@ -1870,7 +1869,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); final int displayId; synchronized (mGlobalLock) { - WindowState win = windowForClientLocked(session, client, false); + final WindowState win = windowForClientLocked(session, client, false); if (win == null) { return 0; } @@ -1885,8 +1884,9 @@ public class WindowManagerService extends IWindowManager.Stub win.setFrameNumber(frameNumber); - if (!mWaitingForConfig) { - win.finishSeamlessRotation(); + final DisplayContent dc = win.getDisplayContent(); + if (!dc.mWaitingForConfig) { + win.finishSeamlessRotation(false /* timeout */); } int attrChanges = 0; @@ -2438,7 +2438,7 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent displayContent = mRoot.getDisplayContent(displayId); displayContent.computeScreenConfiguration(mTempConfiguration); if (currentConfig.diff(mTempConfiguration) != 0) { - mWaitingForConfig = true; + displayContent.mWaitingForConfig = true; displayContent.setLayoutNeeded(); int anim[] = new int[2]; displayContent.getDisplayPolicy().selectRotationAnimationLw(anim); @@ -2451,9 +2451,10 @@ public class WindowManagerService extends IWindowManager.Stub return config; } - void setNewDisplayOverrideConfiguration(Configuration overrideConfig, DisplayContent dc) { - if (mWaitingForConfig) { - mWaitingForConfig = false; + void setNewDisplayOverrideConfiguration(Configuration overrideConfig, + @NonNull DisplayContent dc) { + if (dc.mWaitingForConfig) { + dc.mWaitingForConfig = false; mLastFinishedFreezeSource = "new-config"; } @@ -2474,26 +2475,36 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void overridePendingAppTransitionMultiThumbFuture( IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback, - boolean scaleUp) { + boolean scaleUp, int displayId) { synchronized (mGlobalLock) { - // TODO(multi-display): sysui using this api only support default display. - mRoot.getDisplayContent(DEFAULT_DISPLAY) - .mAppTransition.overridePendingAppTransitionMultiThumbFuture(specsFuture, + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + Slog.w(TAG, "Attempted to call overridePendingAppTransitionMultiThumbFuture" + + " for the display " + displayId + " that does not exist."); + return; + } + displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(specsFuture, callback, scaleUp); } } @Override - public void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) { + public void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter, + int displayId) { if (!checkCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "overridePendingAppTransitionRemote()")) { throw new SecurityException( "Requires CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission"); } synchronized (mGlobalLock) { - // TODO(multi-display): sysui using this api only support default display. - mRoot.getDisplayContent(DEFAULT_DISPLAY) - .mAppTransition.overridePendingAppTransitionRemote(remoteAnimationAdapter); + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + Slog.w(TAG, "Attempted to call overridePendingAppTransitionRemote" + + " for the display " + displayId + " that does not exist."); + return; + } + displayContent.mAppTransition.overridePendingAppTransitionRemote( + remoteAnimationAdapter); } } @@ -4181,13 +4192,11 @@ public class WindowManagerService extends IWindowManager.Stub // placement to unfreeze the display since we froze it when the rotation was updated // in DisplayContent#updateRotationUnchecked. synchronized (mGlobalLock) { - if (mWaitingForConfig) { - mWaitingForConfig = false; + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc != null && dc.mWaitingForConfig) { + dc.mWaitingForConfig = false; mLastFinishedFreezeSource = "config-unchanged"; - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc != null) { - dc.setLayoutNeeded(); - } + dc.setLayoutNeeded(); mWindowPlacerLocked.performSurfacePlacement(); } } @@ -5136,7 +5145,7 @@ public class WindowManagerService extends IWindowManager.Stub configChanged |= currentDisplayConfig.diff(mTempConfiguration) != 0; if (configChanged) { - mWaitingForConfig = true; + displayContent.mWaitingForConfig = true; startFreezingDisplayLocked(0 /* exitAnim */, 0 /* enterAnim */, displayContent); displayContent.sendNewConfiguration(); @@ -5396,23 +5405,24 @@ public class WindowManagerService extends IWindowManager.Stub return; } - final DisplayContent dc = mRoot.getDisplayContent(mFrozenDisplayId); - if (mWaitingForConfig || mAppsFreezingScreen > 0 + final DisplayContent displayContent = mRoot.getDisplayContent(mFrozenDisplayId); + final boolean waitingForConfig = displayContent != null && displayContent.mWaitingForConfig; + final int numOpeningApps = displayContent != null ? displayContent.mOpeningApps.size() : 0; + if (waitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE - || mClientFreezingScreen || (dc != null && !dc.mOpeningApps.isEmpty())) { + || mClientFreezingScreen || numOpeningApps > 0) { if (DEBUG_ORIENTATION) Slog.d(TAG_WM, - "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig + "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + waitingForConfig + ", mAppsFreezingScreen=" + mAppsFreezingScreen + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen + ", mClientFreezingScreen=" + mClientFreezingScreen - + ", mOpeningApps.size()=" + (dc != null ? dc.mOpeningApps.size() : 0)); + + ", mOpeningApps.size()=" + numOpeningApps); return; } if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "stopFreezingDisplayLocked: Unfreezing now"); - final DisplayContent displayContent = mRoot.getDisplayContent(mFrozenDisplayId); // We must make a local copy of the displayId as it can be potentially overwritten later on // in this method. For example, {@link startFreezingDisplayLocked} may be called as a result @@ -5707,8 +5717,14 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public boolean hasNavigationBar() { - return mPolicy.hasNavigationBar(); + public boolean hasNavigationBar(int displayId) { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + return false; + } + return dc.getDisplayPolicy().hasNavigationBar(); + } } @Override @@ -6033,7 +6049,6 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" windows="); pw.print(mWindowsFreezingScreen); pw.print(" client="); pw.print(mClientFreezingScreen); pw.print(" apps="); pw.print(mAppsFreezingScreen); - pw.print(" waitingForConfig="); pw.println(mWaitingForConfig); final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked(); pw.print(" mRotation="); pw.print(defaultDisplayContent.getRotation()); pw.print(" mAltOrientation="); @@ -6042,6 +6057,9 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(defaultDisplayContent.getLastWindowForcedOrientation()); pw.print(" mLastOrientation="); pw.println(defaultDisplayContent.getLastOrientation()); + pw.print(" waitingForConfig="); + pw.println(defaultDisplayContent.mWaitingForConfig); + pw.print(" Animation settings: disabled="); pw.print(mAnimationsDisabled); pw.print(" window="); pw.print(mWindowAnimationScaleSetting); pw.print(" transition="); pw.print(mTransitionAnimationScaleSetting); diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 484bd8c30462..578af2eebe88 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -755,9 +755,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return; } final ActivityDisplay activityDisplay = - mAtm.mStackSupervisor.getActivityDisplay(mDisplayId); + mAtm.mRootActivityContainer.getActivityDisplay(mDisplayId); if (activityDisplay != null) { - mAtm.mStackSupervisor.getActivityDisplay( + mAtm.mRootActivityContainer.getActivityDisplay( mDisplayId).unregisterConfigurationChangeListener(this); } mDisplayId = INVALID_DISPLAY; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 567b5836bb9e..9efaefefb192 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -180,6 +180,7 @@ import android.view.InputChannel; import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InputWindowHandle; +import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; @@ -579,8 +580,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f; - void seamlesslyRotateIfAllowed(Transaction transaction, int oldRotation, int rotation, - boolean requested) { + void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation, + @Rotation int rotation, boolean requested) { // Invisible windows and the wallpaper do not participate in the seamless rotation animation if (!isVisibleNow() || mIsWallpaper) { return; @@ -597,9 +598,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - void finishSeamlessRotation() { + void finishSeamlessRotation(boolean timeout) { if (mPendingSeamlessRotate != null) { - mPendingSeamlessRotate.finish(this); + mPendingSeamlessRotate.finish(this, timeout); mFinishSeamlessRotateFrameNumber = getFrameNumber(); mPendingSeamlessRotate = null; mService.markForSeamlessRotation(this, false); @@ -2036,7 +2037,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); mInputChannel = inputChannels[0]; mClientChannel = inputChannels[1]; - mInputWindowHandle.inputChannel = inputChannels[0]; + mInputWindowHandle.token = mClient.asBinder(); if (outInputChannel != null) { mClientChannel.transferTo(outInputChannel); mClientChannel.dispose(); @@ -2067,7 +2068,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mClientChannel.dispose(); mClientChannel = null; } - mInputWindowHandle.inputChannel = null; + mInputWindowHandle.token = null; } /** Returns true if the replacement window was removed. */ @@ -2166,11 +2167,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mTmpRect.inset(-delta, -delta); } region.set(mTmpRect); - cropRegionToStackBoundsIfNeeded(region); + region.translate(-mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top); } else { // Not modal or full screen modal getTouchableRegion(region); } + + // The area containing the shadows is not touchable. + region.translate(mAttrs.surfaceInsets.left, mAttrs.surfaceInsets.top); + return flags; } @@ -2391,11 +2396,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && (mViewVisibility == View.VISIBLE) && !mRemoveOnExit && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0) && (mAppToken == null || mAppToken.windowsAreFocusable()) - && !canReceiveTouchInput(); + && !cantReceiveTouchInput(); } - /** @return true if this window desires touch events. */ - boolean canReceiveTouchInput() { + /** @return false if this window desires touch events. */ + boolean cantReceiveTouchInput() { return mAppToken != null && mAppToken.getTask() != null && mAppToken.getTask().mStack.shouldIgnoreInput(); } @@ -2802,25 +2807,32 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } void getTouchableRegion(Region outRegion) { + if (inPinnedWindowingMode() && !isFocused()) { + outRegion.setEmpty(); + return; + } + final Rect frame = mWindowFrames.mFrame; switch (mTouchableInsets) { default: case TOUCHABLE_INSETS_FRAME: outRegion.set(frame); + outRegion.translate(-frame.left, -frame.top); break; case TOUCHABLE_INSETS_CONTENT: applyInsets(outRegion, frame, mGivenContentInsets); + outRegion.translate(-frame.left, -frame.top); break; case TOUCHABLE_INSETS_VISIBLE: applyInsets(outRegion, frame, mGivenVisibleInsets); + outRegion.translate(-frame.left, -frame.top); break; case TOUCHABLE_INSETS_REGION: { outRegion.set(mGivenTouchableRegion); - outRegion.translate(frame.left, frame.top); break; } } - cropRegionToStackBoundsIfNeeded(outRegion); + outRegion.translate(mAttrs.surfaceInsets.left, mAttrs.surfaceInsets.top); } private void cropRegionToStackBoundsIfNeeded(Region region) { diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 7193dd7d7d9f..2ee58fe3f574 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -113,7 +113,9 @@ class WindowSurfacePlacer { return; } - if (mService.mWaitingForConfig) { + // TODO(multi-display): + final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked(); + if (defaultDisplay.mWaitingForConfig) { // Our configuration has changed (most likely rotation), but we // don't yet have the complete configuration to report to // applications. Don't do any window layout until we have it. diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index ee8a08b2fbdb..fcd9335874e1 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -86,6 +86,7 @@ static struct { jmethodID notifySwitch; jmethodID notifyInputChannelBroken; jmethodID notifyANR; + jmethodID notifyFocusChanged; jmethodID filterInputEvent; jmethodID interceptKeyBeforeQueueing; jmethodID interceptMotionBeforeQueueingNonInteractive; @@ -147,15 +148,6 @@ static inline const char* toString(bool value) { return value ? "true" : "false"; } -static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env, - const sp<InputApplicationHandle>& inputApplicationHandle) { - if (inputApplicationHandle == nullptr) { - return nullptr; - } - return static_cast<NativeInputApplicationHandle*>(inputApplicationHandle.get())-> - getInputApplicationHandleObjLocalRef(env); -} - static void loadSystemIconAsSpriteWithPointerIcon(JNIEnv* env, jobject contextObj, int32_t style, PointerIcon* outPointerIcon, SpriteIcon* outSpriteIcon) { status_t status = android_view_PointerIcon_loadSystemIcon(env, @@ -249,6 +241,7 @@ public: const sp<IBinder>& token, const std::string& reason); virtual void notifyInputChannelBroken(const sp<IBinder>& token); + virtual void notifyFocusChanged(const sp<IBinder>& token); virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags); virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); @@ -342,6 +335,8 @@ NativeInputManager::NativeInputManager(jobject contextObj, mInteractive = true; mInputManager = new InputManager(this, this); + defaultServiceManager()->addService(String16("inputflinger"), + mInputManager, false); } NativeInputManager::~NativeInputManager() { @@ -656,13 +651,11 @@ nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApp JNIEnv* env = jniEnv(); - jobject inputApplicationHandleObj = - getInputApplicationHandleObjLocalRef(env, inputApplicationHandle); jobject tokenObj = javaObjectForIBinder(env, token); jstring reasonObj = env->NewStringUTF(reason.c_str()); jlong newTimeout = env->CallLongMethod(mServiceObj, - gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj, + gServiceClassInfo.notifyANR, tokenObj, reasonObj); if (checkAndClearExceptionFromCallback(env, "notifyANR")) { newTimeout = 0; // abort dispatch @@ -671,7 +664,6 @@ nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApp } env->DeleteLocalRef(reasonObj); - env->DeleteLocalRef(inputApplicationHandleObj); return newTimeout; } @@ -691,6 +683,22 @@ void NativeInputManager::notifyInputChannelBroken(const sp<IBinder>& token) { } } +void NativeInputManager::notifyFocusChanged(const sp<IBinder>& token) { +#if DEBUG_INPUT_DISPATCHER_POLICY + ALOGD("notifyFocusChanged"); +#endif + ATRACE_CALL(); + + JNIEnv* env = jniEnv(); + + jobject tokenObj = javaObjectForIBinder(env, token); + if (tokenObj) { + env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged, + tokenObj); + checkAndClearExceptionFromCallback(env, "notifyFocusChanged"); + } +} + void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { ATRACE_CALL(); JNIEnv* env = jniEnv(); @@ -1715,10 +1723,13 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.notifyInputChannelBroken, clazz, "notifyInputChannelBroken", "(Landroid/os/IBinder;)V"); + + GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz, + "notifyFocusChanged", "(Landroid/os/IBinder;)V"); GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz, "notifyANR", - "(Landroid/view/InputApplicationHandle;Landroid/os/IBinder;Ljava/lang/String;)J"); + "(Landroid/os/IBinder;Ljava/lang/String;)J"); GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz, "filterInputEvent", "(Landroid/view/InputEvent;I)Z"); diff --git a/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java b/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java index 57e954f10fa7..08fbf5549a87 100644 --- a/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java +++ b/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java @@ -24,11 +24,14 @@ import android.service.intelligence.InteractionContext; import android.service.intelligence.InteractionSessionId; import android.service.intelligence.SnapshotData; import android.util.Slog; +import android.view.autofill.AutofillId; +import android.view.autofill.IAutoFillManagerClient; import android.view.intelligence.ContentCaptureEvent; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.server.AbstractRemoteService; +import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback; import com.android.server.intelligence.RemoteIntelligenceService.RemoteIntelligenceServiceCallbacks; import java.io.PrintWriter; @@ -39,12 +42,12 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks private static final String TAG = "ContentCaptureSession"; private final Object mLock; - private final IBinder mActivityToken; - + final IBinder mActivityToken; private final IntelligencePerUserService mService; private final RemoteIntelligenceService mRemoteService; private final InteractionContext mInterationContext; private final InteractionSessionId mId; + private AugmentedAutofillCallback mAutofillCallback; ContentCaptureSession(@NonNull Context context, int userId, @NonNull Object lock, @NonNull IBinder activityToken, @NonNull IntelligencePerUserService service, @@ -92,6 +95,18 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks } /** + * Requests the service to autofill the given field. + */ + public AugmentedAutofillCallback requestAutofillLocked(@NonNull IAutoFillManagerClient client, + int autofillSessionId, @NonNull AutofillId focusedId) { + mRemoteService.onRequestAutofillLocked(mId, client, autofillSessionId, focusedId); + if (mAutofillCallback == null) { + mAutofillCallback = () -> mRemoteService.onDestroyAutofillWindowsRequest(mId); + } + return mAutofillCallback; + } + + /** * Cleans up the session and removes it from the service. * * @param notifyRemoteService whether it should trigger a {@link @@ -119,6 +134,11 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks if (mService.isVerbose()) { Slog.v(TAG, "destroyLocked(notifyRemoteService=" + notifyRemoteService + ")"); } + if (mAutofillCallback != null) { + mAutofillCallback.destroy(); + mAutofillCallback = null; + } + // TODO(b/111276913): must call client to set session as FINISHED_BY_SERVER if (notifyRemoteService) { mRemoteService.onSessionLifecycleRequest(/* context= */ null, mId); @@ -152,6 +172,8 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks pw.print(prefix); pw.print("id: "); mId.dump(pw); pw.println(); pw.print(prefix); pw.print("context: "); mInterationContext.dump(pw); pw.println(); pw.print(prefix); pw.print("activity token: "); pw.println(mActivityToken); + pw.print(prefix); pw.print("has autofill callback: "); + pw.println(mAutofillCallback != null); } @Override diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java index a7f45ee4c9bf..9fd797d1e549 100644 --- a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java +++ b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java @@ -19,6 +19,7 @@ package com.android.server.intelligence; import static android.content.Context.INTELLIGENCE_MANAGER_SERVICE; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.content.ComponentName; @@ -27,6 +28,8 @@ import android.os.Bundle; import android.os.IBinder; import android.os.UserManager; import android.service.intelligence.InteractionSessionId; +import android.view.autofill.AutofillId; +import android.view.autofill.IAutoFillManagerClient; import android.view.intelligence.ContentCaptureEvent; import android.view.intelligence.IIntelligenceManager; @@ -86,20 +89,6 @@ public final class IntelligenceManagerService extends service.destroyLocked(); } - /** - * Notifies the intelligence service of new assist data for the given activity. - * - * @return {@code false} if there was no service set for the given user - */ - private boolean sendActivityAssistDataLocked(@UserIdInt int userId, - @NonNull IBinder activityToken, @NonNull Bundle data) { - final IntelligencePerUserService service = peekServiceForUserLocked(userId); - if (service != null) { - return service.sendActivityAssistDataLocked(activityToken, data); - } - return false; - } - private ActivityManagerInternal getAmInternal() { synchronized (mLock) { if (mAm == null) { @@ -112,7 +101,7 @@ public final class IntelligenceManagerService extends final class IntelligenceManagerServiceStub extends IIntelligenceManager.Stub { @Override - public void startSession(int userId, @NonNull IBinder activityToken, + public void startSession(@UserIdInt int userId, @NonNull IBinder activityToken, @NonNull ComponentName componentName, @NonNull InteractionSessionId sessionId, int flags, @NonNull IResultReceiver result) { Preconditions.checkNotNull(activityToken); @@ -134,7 +123,7 @@ public final class IntelligenceManagerService extends } @Override - public void sendEvents(int userId, @NonNull InteractionSessionId sessionId, + public void sendEvents(@UserIdInt int userId, @NonNull InteractionSessionId sessionId, @NonNull List<ContentCaptureEvent> events) { Preconditions.checkNotNull(sessionId); Preconditions.checkNotNull(events); @@ -146,12 +135,13 @@ public final class IntelligenceManagerService extends } @Override - public void finishSession(int userId, @NonNull InteractionSessionId sessionId) { + public void finishSession(@UserIdInt int userId, @NonNull InteractionSessionId sessionId, + @Nullable List<ContentCaptureEvent> events) { Preconditions.checkNotNull(sessionId); synchronized (mLock) { final IntelligencePerUserService service = getServiceForUserLocked(userId); - service.finishSessionLocked(sessionId); + service.finishSessionLocked(sessionId, events); } } @@ -168,14 +158,13 @@ public final class IntelligenceManagerService extends private final class LocalService extends IntelligenceManagerInternal { @Override - public boolean isIntelligenceServiceForUser(int uid, int userId) { + public boolean isIntelligenceServiceForUser(int uid, @UserIdInt int userId) { synchronized (mLock) { final IntelligencePerUserService service = peekServiceForUserLocked(userId); if (service != null) { return service.isIntelligenceServiceForUserLocked(uid); } } - return false; } @@ -183,8 +172,26 @@ public final class IntelligenceManagerService extends public boolean sendActivityAssistData(@UserIdInt int userId, @NonNull IBinder activityToken, @NonNull Bundle data) { synchronized (mLock) { - return sendActivityAssistDataLocked(userId, activityToken, data); + final IntelligencePerUserService service = peekServiceForUserLocked(userId); + if (service != null) { + return service.sendActivityAssistDataLocked(activityToken, data); + } + } + return false; + } + + @Override + public AugmentedAutofillCallback requestAutofill(@UserIdInt int userId, + @NonNull IAutoFillManagerClient client, @NonNull IBinder activityToken, + int autofillSessionId, @NonNull AutofillId focusedId) { + synchronized (mLock) { + final IntelligencePerUserService service = peekServiceForUserLocked(userId); + if (service != null) { + return service.requestAutofill(client, activityToken, autofillSessionId, + focusedId); + } } + return null; } } } diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java index 9694ab968e71..9ab7e58feb9b 100644 --- a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java +++ b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java @@ -22,6 +22,8 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUC import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.AppGlobals; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; @@ -36,12 +38,15 @@ import android.service.intelligence.InteractionSessionId; import android.service.intelligence.SnapshotData; import android.util.ArrayMap; import android.util.Slog; +import android.view.autofill.AutofillId; +import android.view.autofill.IAutoFillManagerClient; import android.view.intelligence.ContentCaptureEvent; import android.view.intelligence.IntelligenceManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.server.AbstractPerUserSystemService; +import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback; import java.io.PrintWriter; import java.util.List; @@ -62,7 +67,7 @@ final class IntelligencePerUserService // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's protected IntelligencePerUserService( - IntelligenceManagerService master, Object lock, int userId) { + IntelligenceManagerService master, Object lock, @UserIdInt int userId) { super(master, lock, userId); } @@ -142,7 +147,8 @@ final class IntelligencePerUserService // TODO(b/111276913): log metrics @GuardedBy("mLock") - public void finishSessionLocked(@NonNull InteractionSessionId sessionId) { + public void finishSessionLocked(@NonNull InteractionSessionId sessionId, + @Nullable List<ContentCaptureEvent> events) { if (!isEnabledLocked()) { return; } @@ -154,8 +160,18 @@ final class IntelligencePerUserService } return; } + if (events != null && !events.isEmpty()) { + // TODO(b/111276913): for now we're sending the events and the onDestroy() in 2 separate + // calls because it's not clear yet whether we'll change the manager to send events + // to the service directly (i.e., without passing through system server). Once we + // decide, we might need to split IIntelligenceService.onSessionLifecycle() in 2 + // methods, one for start and another for finish (and passing the events to finish), + // otherwise the service might receive the 2 calls out of order. + session.sendEventsLocked(events); + } if (mMaster.verbose) { - Slog.v(TAG, "finishSession(): " + session); + Slog.v(TAG, "finishSession(" + (events == null ? 0 : events.size()) + " events): " + + session); } session.removeSelfLocked(true); } @@ -210,6 +226,17 @@ final class IntelligencePerUserService return uid == getServiceUidLocked(); } + @GuardedBy("mLock") + private ContentCaptureSession getSession(@NonNull IBinder activityToken) { + for (int i = 0; i < mSessions.size(); i++) { + final ContentCaptureSession session = mSessions.valueAt(i); + if (session.mActivityToken.equals(activityToken)) { + return session; + } + } + return null; + } + /** * Destroys the service and all state associated with it. * @@ -226,6 +253,22 @@ final class IntelligencePerUserService mSessions.clear(); } + public AugmentedAutofillCallback requestAutofill(@NonNull IAutoFillManagerClient client, + @NonNull IBinder activityToken, int autofillSessionId, @NonNull AutofillId focusedId) { + synchronized (mLock) { + final ContentCaptureSession session = getSession(activityToken); + if (session != null) { + // TODO(b/111330312): log metrics + if (mMaster.verbose) Slog.v(TAG, "requestAugmentedAutofill()"); + return session.requestAutofillLocked(client, autofillSessionId, focusedId); + } + if (mMaster.debug) { + Slog.d(TAG, "requestAutofill(): no session for " + activityToken); + } + return null; + } + } + @Override protected void dumpLocked(String prefix, PrintWriter pw) { super.dumpLocked(prefix, pw); diff --git a/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java b/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java index a27c1cf98a9a..00c5b6a1d67b 100644 --- a/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java +++ b/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; +import android.os.Bundle; import android.os.IBinder; import android.os.IInterface; import android.os.RemoteException; @@ -28,8 +29,12 @@ import android.service.intelligence.InteractionSessionId; import android.service.intelligence.SnapshotData; import android.text.format.DateUtils; import android.util.Slog; +import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; +import android.view.autofill.IAutoFillManagerClient; import android.view.intelligence.ContentCaptureEvent; +import com.android.internal.os.IResultReceiver; import com.android.server.AbstractRemoteService; import java.util.List; @@ -39,7 +44,7 @@ final class RemoteIntelligenceService extends AbstractRemoteService { private static final String TAG = "RemoteIntelligenceService"; private static final long TIMEOUT_IDLE_BIND_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS; - private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS; + private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS; private final RemoteIntelligenceServiceCallbacks mCallbacks; private IIntelligenceService mService; @@ -101,6 +106,25 @@ final class RemoteIntelligenceService extends AbstractRemoteService { scheduleRequest(new PendingOnActivitySnapshotRequest(this, sessionId, snapshotData)); } + /** + * Called by {@link ContentCaptureSession} to request augmented autofill. + */ + public void onRequestAutofillLocked(@NonNull InteractionSessionId sessionId, + @NonNull IAutoFillManagerClient client, int autofillSessionId, + @NonNull AutofillId focusedId) { + cancelScheduledUnbind(); + scheduleRequest(new PendingAutofillRequest(this, sessionId, client, autofillSessionId, + focusedId)); + } + + /** + * Called by {@link ContentCaptureSession} when it's time to destroy all augmented autofill + * requests. + */ + public void onDestroyAutofillWindowsRequest(@NonNull InteractionSessionId sessionId) { + cancelScheduledUnbind(); + scheduleRequest(new PendingDestroyAutofillWindowsRequest(this, sessionId)); + } private abstract static class MyPendingRequest extends PendingRequest<RemoteIntelligenceService> { @@ -124,8 +148,9 @@ final class RemoteIntelligenceService extends AbstractRemoteService { final RemoteIntelligenceService remoteService = getService(); if (remoteService != null) { try { - myRun(remoteService); // We don't expect the service to call us back, so we finish right away. + myRun(remoteService); + // TODO(b/111330312): not true anymore!! finish(); } catch (RemoteException e) { Slog.w(TAG, "exception handling " + getClass().getSimpleName() + " for " @@ -191,6 +216,53 @@ final class RemoteIntelligenceService extends AbstractRemoteService { } } + private static final class PendingAutofillRequest extends MyPendingRequest { + private final @NonNull AutofillId mFocusedId; + private final @NonNull IAutoFillManagerClient mClient; + private final int mAutofillSessionId; + + protected PendingAutofillRequest(@NonNull RemoteIntelligenceService service, + @NonNull InteractionSessionId sessionId, @NonNull IAutoFillManagerClient client, + int autofillSessionId, @NonNull AutofillId focusedId) { + super(service, sessionId); + mClient = client; + mAutofillSessionId = autofillSessionId; + mFocusedId = focusedId; + } + + @Override // from MyPendingRequest + public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException { + final IResultReceiver receiver = new IResultReceiver.Stub() { + + @Override + public void send(int resultCode, Bundle resultData) throws RemoteException { + final IBinder realClient = resultData + .getBinder(AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT); + remoteService.mService.onAutofillRequest(mSessionId, realClient, + mAutofillSessionId, mFocusedId); + } + }; + + // TODO(b/111330312): set cancellation signal, timeout (from both mClient and service), + // cache IAugmentedAutofillManagerClient reference, etc... + mClient.getAugmentedAutofillClient(receiver); + } + } + + private static final class PendingDestroyAutofillWindowsRequest extends MyPendingRequest { + + protected PendingDestroyAutofillWindowsRequest(@NonNull RemoteIntelligenceService service, + @NonNull InteractionSessionId sessionId) { + super(service, sessionId); + } + + @Override + protected void myRun(@NonNull RemoteIntelligenceService service) throws RemoteException { + service.mService.onDestroyAutofillWindowsRequest(mSessionId); + // TODO(b/111330312): implement timeout + } + } + public interface RemoteIntelligenceServiceCallbacks extends VultureCallback { // To keep it simple, we use the same callback for all failures / timeouts. void onFailureOrTimeout(boolean timedOut); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 56f7cff565af..d6e62087f277 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -177,7 +177,7 @@ public final class SystemServer { * them from the build system somehow. */ private static final String BACKUP_MANAGER_SERVICE_CLASS = - "com.android.server.backup.BackupManagerService$Lifecycle"; + "com.android.server.backup.GlobalBackupManagerService$Lifecycle"; private static final String APPWIDGET_SERVICE_CLASS = "com.android.server.appwidget.AppWidgetService"; private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS = diff --git a/services/robotests/src/com/android/server/backup/GlobalBackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/GlobalBackupManagerServiceTest.java new file mode 100644 index 000000000000..3108c804b6f4 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/GlobalBackupManagerServiceTest.java @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.backup; + +import static com.android.server.backup.testing.TransportData.backupTransport; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.app.Application; +import android.app.backup.IBackupManagerMonitor; +import android.app.backup.IBackupObserver; +import android.app.backup.IFullBackupRestoreObserver; +import android.app.backup.ISelectBackupTransportCallback; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.platform.test.annotations.Presubmit; + +import com.android.server.backup.testing.BackupManagerServiceTestUtils; +import com.android.server.backup.testing.TransportData; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** Tests for the user-aware backup/restore system service {@link GlobalBackupManagerService}. */ +@RunWith(RobolectricTestRunner.class) +@Presubmit +public class GlobalBackupManagerServiceTest { + private static final String TEST_PACKAGE = "package"; + private static final String TEST_TRANSPORT = "transport"; + + @Mock private UserBackupManagerService mUserBackupManagerService; + @Mock private TransportManager mTransportManager; + private GlobalBackupManagerService mGlobalBackupManagerService; + private Context mContext; + + /** Initialize {@link GlobalBackupManagerService}. */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + Application application = RuntimeEnvironment.application; + mContext = application; + mGlobalBackupManagerService = + new GlobalBackupManagerService( + application, + new Trampoline(application), + BackupManagerServiceTestUtils.startBackupThread(null), + new File(application.getCacheDir(), "base_state"), + new File(application.getCacheDir(), "data"), + mTransportManager); + mGlobalBackupManagerService.setUserBackupManagerService(mUserBackupManagerService); + } + + /** + * Test verifying that {@link GlobalBackupManagerService#MORE_DEBUG} is set to {@code false}. + * This is specifically to prevent overloading the logs in production. + */ + @Test + public void testMoreDebug_isFalse() throws Exception { + boolean moreDebug = GlobalBackupManagerService.MORE_DEBUG; + + assertThat(moreDebug).isFalse(); + } + + // TODO(b/118520567): Change the following tests to use the per-user instance of + // UserBackupManagerService once it's implemented. Currently these tests only test the straight + // forward redirection. + + // --------------------------------------------- + // Backup agent tests + // --------------------------------------------- + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testDataChanged_callsDataChangedForUser() throws Exception { + mGlobalBackupManagerService.dataChanged(TEST_PACKAGE); + + verify(mUserBackupManagerService).dataChanged(TEST_PACKAGE); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testAgentConnected_callsAgentConnectedForUser() throws Exception { + IBinder agentBinder = mock(IBinder.class); + + mGlobalBackupManagerService.agentConnected(TEST_PACKAGE, agentBinder); + + verify(mUserBackupManagerService).agentConnected(TEST_PACKAGE, agentBinder); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testAgentDisconnected_callsAgentDisconnectedForUser() throws Exception { + mGlobalBackupManagerService.agentDisconnected(TEST_PACKAGE); + + verify(mUserBackupManagerService).agentDisconnected(TEST_PACKAGE); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testOpComplete_callsOpCompleteForUser() throws Exception { + mGlobalBackupManagerService.opComplete(/* token */ 0, /* result */ 0L); + + verify(mUserBackupManagerService).opComplete(/* token */ 0, /* result */ 0L); + } + + // --------------------------------------------- + // Transport tests + // --------------------------------------------- + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testInitializeTransports_callsInitializeTransportsForUser() throws Exception { + String[] transports = {TEST_TRANSPORT}; + + mGlobalBackupManagerService.initializeTransports(transports, /* observer */ null); + + verify(mUserBackupManagerService).initializeTransports(transports, /* observer */ null); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testClearBackupData_callsClearBackupDataForUser() throws Exception { + mGlobalBackupManagerService.clearBackupData(TEST_TRANSPORT, TEST_PACKAGE); + + verify(mUserBackupManagerService).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetCurrentTransport_callsGetCurrentTransportForUser() throws Exception { + mGlobalBackupManagerService.getCurrentTransport(); + + verify(mUserBackupManagerService).getCurrentTransport(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetCurrentTransportComponent_callsGetCurrentTransportComponentForUser() + throws Exception { + mGlobalBackupManagerService.getCurrentTransportComponent(); + + verify(mUserBackupManagerService).getCurrentTransportComponent(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testListAllTransports_callsListAllTransportsForUser() throws Exception { + mGlobalBackupManagerService.listAllTransports(); + + verify(mUserBackupManagerService).listAllTransports(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testListAllTransportComponents_callsListAllTransportComponentsForUser() + throws Exception { + mGlobalBackupManagerService.listAllTransportComponents(); + + verify(mUserBackupManagerService).listAllTransportComponents(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetTransportWhitelist_callsGetTransportWhitelistForUser() throws Exception { + mGlobalBackupManagerService.getTransportWhitelist(); + + verify(mUserBackupManagerService).getTransportWhitelist(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testUpdateTransportAttributes_callsUpdateTransportAttributesForUser() + throws Exception { + TransportData transport = backupTransport(); + Intent configurationIntent = new Intent(); + Intent dataManagementIntent = new Intent(); + + mGlobalBackupManagerService.updateTransportAttributes( + transport.getTransportComponent(), + transport.transportName, + configurationIntent, + "currentDestinationString", + dataManagementIntent, + "dataManagementLabel"); + + verify(mUserBackupManagerService) + .updateTransportAttributes( + transport.getTransportComponent(), + transport.transportName, + configurationIntent, + "currentDestinationString", + dataManagementIntent, + "dataManagementLabel"); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testSelectBackupTransport_callsSelectBackupTransportForUser() throws Exception { + mGlobalBackupManagerService.selectBackupTransport(TEST_TRANSPORT); + + verify(mUserBackupManagerService).selectBackupTransport(TEST_TRANSPORT); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testSelectTransportAsync_callsSelectTransportAsyncForUser() throws Exception { + TransportData transport = backupTransport(); + ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class); + + mGlobalBackupManagerService.selectBackupTransportAsync( + transport.getTransportComponent(), callback); + + verify(mUserBackupManagerService) + .selectBackupTransportAsync(transport.getTransportComponent(), callback); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetConfigurationIntent_callsGetConfigurationIntentForUser() throws Exception { + mGlobalBackupManagerService.getConfigurationIntent(TEST_TRANSPORT); + + verify(mUserBackupManagerService).getConfigurationIntent(TEST_TRANSPORT); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetDestinationString_callsGetDestinationStringForUser() throws Exception { + mGlobalBackupManagerService.getDestinationString(TEST_TRANSPORT); + + verify(mUserBackupManagerService).getDestinationString(TEST_TRANSPORT); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetDataManagementIntent_callsGetDataManagementIntentForUser() throws Exception { + mGlobalBackupManagerService.getDataManagementIntent(TEST_TRANSPORT); + + verify(mUserBackupManagerService).getDataManagementIntent(TEST_TRANSPORT); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetDataManagementLabel_callsGetDataManagementLabelForUser() throws Exception { + mGlobalBackupManagerService.getDataManagementLabel(TEST_TRANSPORT); + + verify(mUserBackupManagerService).getDataManagementLabel(TEST_TRANSPORT); + } + + // --------------------------------------------- + // Settings tests + // --------------------------------------------- + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void setBackupEnabled_callsSetBackupEnabledForUser() throws Exception { + mGlobalBackupManagerService.setBackupEnabled(true); + + verify(mUserBackupManagerService).setBackupEnabled(true); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void setAutoRestore_callsSetAutoRestoreForUser() throws Exception { + mGlobalBackupManagerService.setAutoRestore(true); + + verify(mUserBackupManagerService).setAutoRestore(true); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testSetBackupProvisioned_callsSetBackupProvisionedForUser() throws Exception { + mGlobalBackupManagerService.setBackupProvisioned(true); + + verify(mUserBackupManagerService).setBackupProvisioned(true); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testIsBackupEnabled_callsIsBackupEnabledForUser() throws Exception { + mGlobalBackupManagerService.isBackupEnabled(); + + verify(mUserBackupManagerService).isBackupEnabled(); + } + + // --------------------------------------------- + // Backup tests + // --------------------------------------------- + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testIsAppEligibleForBackup_callsIsAppEligibleForBackupForUser() throws Exception { + mGlobalBackupManagerService.isAppEligibleForBackup(TEST_PACKAGE); + + verify(mUserBackupManagerService).isAppEligibleForBackup(TEST_PACKAGE); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testFilterAppsEligibleForBackup_callsFilterAppsEligibleForBackupForUser() + throws Exception { + String[] packages = {TEST_PACKAGE}; + + mGlobalBackupManagerService.filterAppsEligibleForBackup(packages); + + verify(mUserBackupManagerService).filterAppsEligibleForBackup(packages); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testBackupNow_callsBackupNowForUser() throws Exception { + mGlobalBackupManagerService.backupNow(); + + verify(mUserBackupManagerService).backupNow(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testRequestBackup_callsRequestBackupForUser() throws Exception { + String[] packages = {TEST_PACKAGE}; + IBackupObserver observer = mock(IBackupObserver.class); + IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class); + + mGlobalBackupManagerService.requestBackup(packages, observer, monitor, /* flags */ 0); + + verify(mUserBackupManagerService).requestBackup(packages, observer, monitor, /* flags */ 0); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testCancelBackups_callsCancelBackupsForUser() throws Exception { + mGlobalBackupManagerService.cancelBackups(); + + verify(mUserBackupManagerService).cancelBackups(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testBeginFullBackup_callsBeginFullBackupForUser() throws Exception { + FullBackupJob job = new FullBackupJob(); + + mGlobalBackupManagerService.beginFullBackup(job); + + verify(mUserBackupManagerService).beginFullBackup(job); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testEndFullBackup_callsEndFullBackupForUser() throws Exception { + mGlobalBackupManagerService.endFullBackup(); + + verify(mUserBackupManagerService).endFullBackup(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testFullTransportBackup_callsFullTransportBackupForUser() throws Exception { + String[] packages = {TEST_PACKAGE}; + + mGlobalBackupManagerService.fullTransportBackup(packages); + + verify(mUserBackupManagerService).fullTransportBackup(packages); + } + + // --------------------------------------------- + // Restore tests + // --------------------------------------------- + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testRestoreAtInstall_callsRestoreAtInstallForUser() throws Exception { + mGlobalBackupManagerService.restoreAtInstall(TEST_PACKAGE, /* token */ 0); + + verify(mUserBackupManagerService).restoreAtInstall(TEST_PACKAGE, /* token */ 0); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testBeginRestoreSession_callsBeginRestoreSessionForUser() throws Exception { + mGlobalBackupManagerService.beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT); + + verify(mUserBackupManagerService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testGetAvailableRestoreToken_callsGetAvailableRestoreTokenForUser() + throws Exception { + mGlobalBackupManagerService.getAvailableRestoreToken(TEST_PACKAGE); + + verify(mUserBackupManagerService).getAvailableRestoreToken(TEST_PACKAGE); + } + + // --------------------------------------------- + // Adb backup/restore tests + // --------------------------------------------- + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testSetBackupPassword_callsSetBackupPasswordForUser() throws Exception { + mGlobalBackupManagerService.setBackupPassword("currentPassword", "newPassword"); + + verify(mUserBackupManagerService).setBackupPassword("currentPassword", "newPassword"); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testHasBackupPassword_callsHasBackupPasswordForUser() throws Exception { + mGlobalBackupManagerService.hasBackupPassword(); + + verify(mUserBackupManagerService).hasBackupPassword(); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testAdbBackup_callsAdbBackupForUser() throws Exception { + File testFile = new File(mContext.getFilesDir(), "test"); + testFile.createNewFile(); + ParcelFileDescriptor parcelFileDescriptor = + ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE); + String[] packages = {TEST_PACKAGE}; + + mGlobalBackupManagerService.adbBackup( + parcelFileDescriptor, + /* includeApks */ true, + /* includeObbs */ true, + /* includeShared */ true, + /* doWidgets */ true, + /* doAllApps */ true, + /* includeSystem */ true, + /* doCompress */ true, + /* doKeyValue */ true, + packages); + + verify(mUserBackupManagerService) + .adbBackup( + parcelFileDescriptor, + /* includeApks */ true, + /* includeObbs */ true, + /* includeShared */ true, + /* doWidgets */ true, + /* doAllApps */ true, + /* includeSystem */ true, + /* doCompress */ true, + /* doKeyValue */ true, + packages); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testAdbRestore_callsAdbRestoreForUser() throws Exception { + File testFile = new File(mContext.getFilesDir(), "test"); + testFile.createNewFile(); + ParcelFileDescriptor parcelFileDescriptor = + ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE); + + mGlobalBackupManagerService.adbRestore(parcelFileDescriptor); + + verify(mUserBackupManagerService).adbRestore(parcelFileDescriptor); + } + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testAcknowledgeAdbBackupOrRestore_callsAcknowledgeAdbBackupOrRestoreForUser() + throws Exception { + IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class); + + mGlobalBackupManagerService.acknowledgeAdbBackupOrRestore( + /* token */ 0, /* allow */ true, "currentPassword", "encryptionPassword", observer); + + verify(mUserBackupManagerService) + .acknowledgeAdbBackupOrRestore( + /* token */ 0, + /* allow */ true, + "currentPassword", + "encryptionPassword", + observer); + } + + // --------------------------------------------- + // Service tests + // --------------------------------------------- + + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testDump_callsDumpForUser() throws Exception { + File testFile = new File(mContext.getFilesDir(), "test"); + testFile.createNewFile(); + FileDescriptor fileDescriptor = new FileDescriptor(); + PrintWriter printWriter = new PrintWriter(testFile); + String[] args = {"1", "2"}; + + mGlobalBackupManagerService.dump(fileDescriptor, printWriter, args); + + verify(mUserBackupManagerService).dump(fileDescriptor, printWriter, args); + } +} diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/UserBackupManagerServiceTest.java index f7bb68c61a42..9d4381914608 100644 --- a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java +++ b/services/robotests/src/com/android/server/backup/UserBackupManagerServiceTest.java @@ -76,11 +76,14 @@ import org.robolectric.shadows.ShadowSettings; import java.io.File; import java.util.List; -/** Tests for the system service {@link BackupManagerService} that performs backup/restore. */ +/** + * Tests for the per-user instance of the backup/restore system service {@link + * UserBackupManagerService} that performs operations for its target user. + */ @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowAppBackupUtils.class}) @Presubmit -public class BackupManagerServiceTest { +public class UserBackupManagerServiceTest { private static final String TAG = "BMSTest"; private static final String PACKAGE_1 = "some.package.1"; private static final String PACKAGE_2 = "some.package.2"; @@ -97,8 +100,9 @@ public class BackupManagerServiceTest { private ShadowPackageManager mShadowPackageManager; /** - * Initialize state that {@link BackupManagerService} operations interact with. This includes - * setting up the transport, starting the backup thread, and creating backup data directories. + * Initialize state that {@link UserBackupManagerService} operations interact with. This + * includes setting up the transport, starting the backup thread, and creating backup data + * directories. */ @Before public void setUp() throws Exception { @@ -126,7 +130,7 @@ public class BackupManagerServiceTest { } /** - * Clean up and reset state that was created for testing {@link BackupManagerService} + * Clean up and reset state that was created for testing {@link UserBackupManagerService} * operations. */ @After @@ -136,18 +140,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is - * specifically to prevent overloading the logs in production. - */ - @Test - public void testMoreDebug_isFalse() { - boolean moreDebug = BackupManagerService.MORE_DEBUG; - - assertThat(moreDebug).isFalse(); - } - - /** - * Test verifying that {@link BackupManagerService#getDestinationString(String)} returns the + * Test verifying that {@link UserBackupManagerService#getDestinationString(String)} returns the * current destination string of inputted transport if the transport is registered. */ @Test @@ -155,7 +148,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName))) .thenReturn("destinationString"); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); String destination = backupManagerService.getDestinationString(mTransportName); @@ -163,15 +156,15 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#getDestinationString(String)} returns {@code - * null} if the inputted transport is not registered. + * Test verifying that {@link UserBackupManagerService#getDestinationString(String)} returns + * {@code null} if the inputted transport is not registered. */ @Test public void testDestinationString_whenTransportNotRegistered() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName))) .thenThrow(TransportNotRegisteredException.class); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); String destination = backupManagerService.getDestinationString(mTransportName); @@ -179,15 +172,15 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#getDestinationString(String)} throws a {@link - * SecurityException} if the caller does not have backup permission. + * Test verifying that {@link UserBackupManagerService#getDestinationString(String)} throws a + * {@link SecurityException} if the caller does not have backup permission. */ @Test public void testDestinationString_withoutPermission() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName))) .thenThrow(TransportNotRegisteredException.class); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, @@ -195,14 +188,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#isAppEligibleForBackup(String)} returns + * Test verifying that {@link UserBackupManagerService#isAppEligibleForBackup(String)} returns * {@code false} when the given app is not eligible for backup. */ @Test public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1); @@ -210,7 +203,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#isAppEligibleForBackup(String)} returns + * Test verifying that {@link UserBackupManagerService#isAppEligibleForBackup(String)} returns * {@code true} when the given app is eligible for backup. */ @Test @@ -218,7 +211,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport()); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1); @@ -228,7 +221,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#isAppEligibleForBackup(String)} throws a + * Test verifying that {@link UserBackupManagerService#isAppEligibleForBackup(String)} throws a * {@link SecurityException} if the caller does not have backup permission. */ @Test @@ -236,7 +229,7 @@ public class BackupManagerServiceTest { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, @@ -244,7 +237,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#filterAppsEligibleForBackup(String[])} + * Test verifying that {@link UserBackupManagerService#filterAppsEligibleForBackup(String[])} * returns an {@code array} of only apps that are eligible for backup from an {@array} of * inputted apps. */ @@ -253,7 +246,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); String[] filtered = backupManagerService.filterAppsEligibleForBackup( @@ -265,13 +258,13 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#filterAppsEligibleForBackup(String[])} + * Test verifying that {@link UserBackupManagerService#filterAppsEligibleForBackup(String[])} * returns an empty {@code array} if no inputted apps are eligible for backup. */ @Test public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); String[] filtered = backupManagerService.filterAppsEligibleForBackup( @@ -281,14 +274,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#filterAppsEligibleForBackup(String[])} throws - * a {@link SecurityException} if the caller does not have backup permission. + * Test verifying that {@link UserBackupManagerService#filterAppsEligibleForBackup(String[])} + * throws a {@link SecurityException} if the caller does not have backup permission. */ @Test public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, @@ -318,15 +311,15 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#selectBackupTransport(String)} successfully - * switches the current transport to the inputted transport, returns the name of the old - * transport, and disposes of the transport client after the operation. + * Test verifying that {@link UserBackupManagerService#selectBackupTransport(String)} + * successfully switches the current transport to the inputted transport, returns the name of + * the old transport, and disposes of the transport client after the operation. */ @Test public void testSelectBackupTransport() throws Exception { setUpForSelectTransport(); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); String oldTransport = backupManagerService.selectBackupTransport(mNewTransport.transportName); @@ -338,14 +331,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#selectBackupTransport(String)} throws a + * Test verifying that {@link UserBackupManagerService#selectBackupTransport(String)} throws a * {@link SecurityException} if the caller does not have backup permission. */ @Test public void testSelectBackupTransport_withoutPermission() throws Exception { setUpForSelectTransport(); mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, @@ -353,7 +346,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#selectBackupTransportAsync(ComponentName, + * Test verifying that {@link UserBackupManagerService#selectBackupTransportAsync(ComponentName, * ISelectBackupTransportCallback)} successfully switches the current transport to the inputted * transport and disposes of the transport client after the operation. */ @@ -363,7 +356,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent))) .thenReturn(BackupManager.SUCCESS); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class); backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback); @@ -376,7 +369,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#selectBackupTransportAsync(ComponentName, + * Test verifying that {@link UserBackupManagerService#selectBackupTransportAsync(ComponentName, * ISelectBackupTransportCallback)} does not switch the current transport to the inputted * transport and notifies the inputted callback of failure when it fails to register the * transport. @@ -387,7 +380,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent))) .thenReturn(BackupManager.ERROR_TRANSPORT_UNAVAILABLE); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class); backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback); @@ -398,7 +391,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#selectBackupTransportAsync(ComponentName, + * Test verifying that {@link UserBackupManagerService#selectBackupTransportAsync(ComponentName, * ISelectBackupTransportCallback)} does not switch the current transport to the inputted * transport and notifies the inputted callback of failure when the transport gets unregistered. */ @@ -409,7 +402,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.registerAndSelectTransport(eq(newTransportComponent))) .thenReturn(BackupManager.SUCCESS); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class); backupManagerService.selectBackupTransportAsync(newTransportComponent, callback); @@ -420,7 +413,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#selectBackupTransportAsync(ComponentName, + * Test verifying that {@link UserBackupManagerService#selectBackupTransportAsync(ComponentName, * ISelectBackupTransportCallback)} throws a {@link SecurityException} if the caller does not * have backup permission. */ @@ -428,7 +421,7 @@ public class BackupManagerServiceTest { public void testSelectBackupTransportAsync_withoutPermission() throws Exception { setUpForSelectTransport(); mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); ComponentName newTransportComponent = mNewTransport.getTransportComponent(); expectThrows( @@ -444,15 +437,15 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#getCurrentTransportComponent()} returns the - * {@link ComponentName} of the currently selected transport. + * Test verifying that {@link UserBackupManagerService#getCurrentTransportComponent()} returns + * the {@link ComponentName} of the currently selected transport. */ @Test public void testGetCurrentTransportComponent() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.getCurrentTransportComponent()) .thenReturn(mTransport.getTransportComponent()); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); ComponentName transportComponent = backupManagerService.getCurrentTransportComponent(); @@ -460,14 +453,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#getCurrentTransportComponent()} returns + * Test verifying that {@link UserBackupManagerService#getCurrentTransportComponent()} returns * {@code null} if there is no currently selected transport. */ @Test public void testGetCurrentTransportComponent_whenNoTransportSelected() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.getCurrentTransportComponent()).thenReturn(null); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); ComponentName transportComponent = backupManagerService.getCurrentTransportComponent(); @@ -475,7 +468,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#getCurrentTransportComponent()} returns + * Test verifying that {@link UserBackupManagerService#getCurrentTransportComponent()} returns * {@code null} if the currently selected transport is not registered. */ @Test @@ -483,7 +476,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); when(mTransportManager.getCurrentTransportComponent()) .thenThrow(TransportNotRegisteredException.class); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); ComponentName transportComponent = backupManagerService.getCurrentTransportComponent(); @@ -491,13 +484,13 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#getCurrentTransportComponent()} throws a + * Test verifying that {@link UserBackupManagerService#getCurrentTransportComponent()} throws a * {@link SecurityException} if the caller does not have backup permission. */ @Test public void testGetCurrentTransportComponent_withoutPermission() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows(SecurityException.class, backupManagerService::getCurrentTransportComponent); } @@ -520,9 +513,9 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} succeeds if the uid of the transport is same as the - * uid of the caller. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} succeeds if the uid of the transport + * is same as the uid of the caller. */ @Test public void @@ -532,7 +525,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); Intent configurationIntent = new Intent(); Intent dataManagementIntent = new Intent(); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.updateTransportAttributes( mTransportUid, @@ -554,16 +547,16 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} throws a {@link SecurityException} if the uid of the - * transport is not equal to the uid of the caller. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} throws a {@link SecurityException} if + * the uid of the transport is not equal to the uid of the caller. */ @Test public void testUpdateTransportAttributes_whenTransportUidNotEqualToCallingUid_throwsException() throws Exception { setUpForUpdateTransportAttributes(); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, @@ -579,16 +572,16 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} throws a {@link RuntimeException} if given a {@code - * null} transport component. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} throws a {@link RuntimeException} if + * given a {@code null} transport component. */ @Test public void testUpdateTransportAttributes_whenTransportComponentNull_throwsException() throws Exception { setUpForUpdateTransportAttributes(); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( RuntimeException.class, @@ -604,15 +597,15 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} throws a {@link RuntimeException} if given a {@code - * null} transport name. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} throws a {@link RuntimeException} if + * given a {@code null} transport name. */ @Test public void testUpdateTransportAttributes_whenNameNull_throwsException() throws Exception { setUpForUpdateTransportAttributes(); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( RuntimeException.class, @@ -628,16 +621,16 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} throws a {@link RuntimeException} if given a {@code - * null} destination string. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} throws a {@link RuntimeException} if + * given a {@code null} destination string. */ @Test public void testUpdateTransportAttributes_whenCurrentDestinationStringNull_throwsException() throws Exception { setUpForUpdateTransportAttributes(); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( RuntimeException.class, @@ -653,9 +646,10 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} throws a {@link RuntimeException} if given either a - * {@code null} data management label or {@code null} data management intent, but not both. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} throws a {@link RuntimeException} if + * given either a {@code null} data management label or {@code null} data management intent, but + * not both. */ @Test public void @@ -663,7 +657,7 @@ public class BackupManagerServiceTest { throws Exception { setUpForUpdateTransportAttributes(); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( RuntimeException.class, @@ -691,8 +685,9 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} succeeds if the caller has backup permission. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} succeeds if the caller has backup + * permission. */ @Test public void testUpdateTransportAttributes_whenPermissionGranted_callsThroughToTransportManager() @@ -701,7 +696,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); Intent configurationIntent = new Intent(); Intent dataManagementIntent = new Intent(); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.updateTransportAttributes( mTransportUid, @@ -723,16 +718,16 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#updateTransportAttributes(int, ComponentName, - * String, Intent, String, Intent, String)} throws a {@link SecurityException} if the caller - * does not have backup permission. + * Test verifying that {@link UserBackupManagerService#updateTransportAttributes(int, + * ComponentName, String, Intent, String, Intent, String)} throws a {@link SecurityException} if + * the caller does not have backup permission. */ @Test public void testUpdateTransportAttributes_whenPermissionDenied_throwsSecurityException() throws Exception { setUpForUpdateTransportAttributes(); mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, @@ -765,13 +760,13 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} throws a {@link SecurityException} if the caller does not have backup permission. */ @Test public void testRequestBackup_whenPermissionDenied() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, @@ -779,13 +774,13 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} throws an {@link IllegalArgumentException} if passed {@null} for packages. */ @Test public void testRequestBackup_whenPackagesNull() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( IllegalArgumentException.class, @@ -794,14 +789,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} throws an {@link IllegalArgumentException} if passed an empty {@code array} for * packages. */ @Test public void testRequestBackup_whenPackagesEmpty() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( IllegalArgumentException.class, @@ -810,13 +805,13 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} returns {@link BackupManager#ERROR_BACKUP_NOT_ALLOWED} if backup is disabled. */ @Test public void testRequestBackup_whenBackupDisabled() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(false); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); @@ -826,14 +821,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} returns {@link BackupManager#ERROR_BACKUP_NOT_ALLOWED} if the system user hasn't gone * through SUW. */ @Test public void testRequestBackup_whenNotProvisioned() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setProvisioned(false); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); @@ -843,7 +838,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} returns {@link BackupManager#ERROR_TRANSPORT_ABORTED} if the current transport is not * registered. */ @@ -851,7 +846,7 @@ public class BackupManagerServiceTest { public void testRequestBackup_whenTransportNotRegistered() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport.unregistered()); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); @@ -862,7 +857,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} returns {@link BackupManager#SUCCESS} and notifies the observer of {@link * BackupManager#ERROR_BACKUP_NOT_ALLOWED} if the specified app is not eligible for backup. */ @@ -871,7 +866,7 @@ public class BackupManagerServiceTest { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowPackageManager.addPackage(PACKAGE_1); setUpCurrentTransport(mTransportManager, mTransport); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); // Haven't set PACKAGE_1 as eligible @@ -885,7 +880,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} returns {@link BackupManager#SUCCESS} and updates bookkeeping if backup for a key value * package succeeds. */ @@ -893,7 +888,8 @@ public class BackupManagerServiceTest { @Config(shadows = ShadowKeyValueBackupTask.class) public void testRequestBackup_whenPackageIsKeyValue() throws Exception { setUpForRequestBackup(PACKAGE_1); - BackupManagerService backupManagerService = createBackupManagerServiceForRequestBackup(); + UserBackupManagerService backupManagerService = + createBackupManagerServiceForRequestBackup(); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); @@ -907,7 +903,7 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#requestBackup(String[], IBackupObserver, + * Test verifying that {@link UserBackupManagerService#requestBackup(String[], IBackupObserver, * int)} returns {@link BackupManager#SUCCESS} and updates bookkeeping if backup for a full * backup package succeeds. */ @@ -916,7 +912,8 @@ public class BackupManagerServiceTest { public void testRequestBackup_whenPackageIsFullBackup() throws Exception { setUpForRequestBackup(PACKAGE_1); ShadowAppBackupUtils.setAppGetsFullBackup(PACKAGE_1); - BackupManagerService backupManagerService = createBackupManagerServiceForRequestBackup(); + UserBackupManagerService backupManagerService = + createBackupManagerServiceForRequestBackup(); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); @@ -930,14 +927,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#backupNow()} clears the calling identity + * Test verifying that {@link UserBackupManagerService#backupNow()} clears the calling identity * for scheduling a job and then restores the original calling identity after the operation. */ @Test @Config(shadows = {ShadowBinder.class, ShadowKeyValueBackupJob.class}) public void testBackupNow_clearsCallingIdentityForJobScheduler() { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); setUpPowerManager(backupManagerService); ShadowBinder.setCallingUid(1); @@ -948,14 +945,14 @@ public class BackupManagerServiceTest { } /** - * Test verifying that {@link BackupManagerService#backupNow()} restores the original calling - * identity if an exception is thrown during execution. + * Test verifying that {@link UserBackupManagerService#backupNow()} restores the original + * calling identity if an exception is thrown during execution. */ @Test @Config(shadows = {ShadowBinder.class, ShadowKeyValueBackupJobException.class}) public void testBackupNow_whenExceptionThrown_restoresCallingIdentity() { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); setUpPowerManager(backupManagerService); ShadowBinder.setCallingUid(1); @@ -965,17 +962,17 @@ public class BackupManagerServiceTest { assertThat(Binder.getCallingUid()).isEqualTo(1); } - private BackupManagerService createBackupManagerServiceForRequestBackup() { - BackupManagerService backupManagerService = createInitializedBackupManagerService(); + private UserBackupManagerService createBackupManagerServiceForRequestBackup() { + UserBackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); return backupManagerService; } /** - * Test verifying that {@link BackupManagerService#BackupManagerService(Context, Trampoline, - * HandlerThread, File, File, TransportManager)} posts a transport registration task to the - * backup handler thread. + * Test verifying that {@link UserBackupManagerService#UserBackupManagerService(Context, + * Trampoline, HandlerThread, File, File, TransportManager)} posts a transport registration task + * to the backup handler thread. */ @Test public void testConstructor_postRegisterTransports() { @@ -988,9 +985,9 @@ public class BackupManagerServiceTest { } /** - * Test verifying that the {@link BackupManagerService#BackupManagerService(Context, Trampoline, - * HandlerThread, File, File, TransportManager)} does not directly register transports in its - * own thread. + * Test verifying that the {@link UserBackupManagerService#UserBackupManagerService(Context, + * Trampoline, HandlerThread, File, File, TransportManager)} does not directly register + * transports in its own thread. */ @Test public void testConstructor_doesNotRegisterTransportsSynchronously() { @@ -1002,8 +999,8 @@ public class BackupManagerServiceTest { verify(mTransportManager, never()).registerTransports(); } - private BackupManagerService createBackupManagerService() { - return new BackupManagerService( + private UserBackupManagerService createBackupManagerService() { + return new UserBackupManagerService( mContext, new Trampoline(mContext), mBackupThread, @@ -1012,12 +1009,12 @@ public class BackupManagerServiceTest { mTransportManager); } - private BackupManagerService createInitializedBackupManagerService() { - return BackupManagerServiceTestUtils.createInitializedBackupManagerService( + private UserBackupManagerService createInitializedBackupManagerService() { + return BackupManagerServiceTestUtils.createInitializedUserBackupManagerService( mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager); } - private void setUpPowerManager(BackupManagerService backupManagerService) { + private void setUpPowerManager(UserBackupManagerService backupManagerService) { PowerManager powerManagerMock = mock(PowerManager.class); when(powerManagerMock.getPowerSaveState(anyInt())) .thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(true).build()); diff --git a/services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java b/services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java index fd7ced2d58b6..423512ce4b70 100644 --- a/services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java +++ b/services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java @@ -1,10 +1,10 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_VERSION; -import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_FILENAME; -import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_VERSION; -import static com.android.server.backup.BackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; +import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_VERSION; +import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; +import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_VERSION; +import static com.android.server.backup.UserBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; import static com.google.common.truth.Truth.assertThat; diff --git a/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java b/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java index 6ee6eb67dd57..8ec0759e52db 100644 --- a/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java +++ b/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java @@ -44,8 +44,9 @@ import android.platform.test.annotations.Presubmit; import android.util.Log; import com.android.internal.backup.IBackupTransport; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.GlobalBackupManagerService; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportTestUtils; import com.android.server.backup.testing.TransportTestUtils.TransportMock; @@ -71,7 +72,7 @@ import java.util.stream.Stream; @Config(shadows = ShadowSlog.class) @Presubmit public class PerformInitializeTaskTest { - @Mock private BackupManagerService mBackupManagerService; + @Mock private UserBackupManagerService mBackupManagerService; @Mock private TransportManager mTransportManager; @Mock private OnTaskFinishedListener mListener; @Mock private IBackupTransport mTransportBinder; @@ -211,7 +212,7 @@ public class PerformInitializeTaskTest { performInitializeTask.run(); assertLogcatContains( - BackupManagerService.TAG, + GlobalBackupManagerService.TAG, log -> log.msg.contains("finishBackup()") && log.type >= Log.ERROR); } @@ -224,7 +225,7 @@ public class PerformInitializeTaskTest { performInitializeTask.run(); assertLogcatContains( - BackupManagerService.TAG, + GlobalBackupManagerService.TAG, log -> log.msg.contains("initializeDevice()") && log.type >= Log.ERROR); } diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java index a0afb5e0d84e..a1b8a9520524 100644 --- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java +++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java @@ -26,7 +26,7 @@ import android.app.backup.IBackupObserver; import android.platform.test.annotations.Presubmit; import android.util.Log; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; import com.android.server.testing.shadows.ShadowEventLog; import com.android.server.testing.shadows.ShadowSlog; @@ -41,7 +41,7 @@ import org.robolectric.annotation.Config; @Config(shadows = {ShadowEventLog.class, ShadowSlog.class}) @Presubmit public class KeyValueBackupReporterTest { - @Mock private BackupManagerService mBackupManagerService; + @Mock private UserBackupManagerService mBackupManagerService; @Mock private IBackupObserver mObserver; @Mock private IBackupManagerMonitor mMonitor; diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index a69f007dfe08..1aa4999b1d3a 100644 --- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -26,7 +26,7 @@ import static android.app.backup.ForwardingBackupAgent.forward; import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock; import static com.android.server.backup.testing.BackupManagerServiceTestUtils - .createInitializedBackupManagerService; + .createInitializedUserBackupManagerService; import static com.android.server.backup.testing.BackupManagerServiceTestUtils .setUpBackupManagerServiceBasics; import static com.android.server.backup.testing.BackupManagerServiceTestUtils @@ -103,12 +103,12 @@ import android.util.Pair; import com.android.internal.backup.IBackupTransport; import com.android.server.EventLogTags; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.KeyValueBackupJob; import com.android.server.backup.PackageManagerBackupAgent; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.internal.BackupHandler; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.remote.RemoteCall; @@ -178,7 +178,7 @@ public class KeyValueBackupTaskTest { @Mock private IBackupObserver mObserver; @Mock private IBackupManagerMonitor mMonitor; @Mock private OnTaskFinishedListener mListener; - private BackupManagerService mBackupManagerService; + private UserBackupManagerService mBackupManagerService; private TransportData mTransport; private ShadowLooper mShadowBackupLooper; private Handler mBackupHandler; @@ -227,7 +227,7 @@ public class KeyValueBackupTaskTest { setUpBinderCallerAndApplicationAsSystem(mApplication); mBackupManagerService = spy( - createInitializedBackupManagerService( + createInitializedUserBackupManagerService( mContext, mBaseStateDir, mDataDir, mTransportManager)); setUpBackupManagerServiceBasics( mBackupManagerService, @@ -720,7 +720,7 @@ public class KeyValueBackupTaskTest { } /** - * Agent unavailable means {@link BackupManagerService#bindToAgentSynchronous(ApplicationInfo, + * Agent unavailable means {@link UserBackupManagerService#bindToAgentSynchronous(ApplicationInfo, * int)} returns {@code null}. * * @see #setUpAgent(PackageData) @@ -2597,7 +2597,7 @@ public class KeyValueBackupTaskTest { * * <ul> * <li>The transport being initialized with {@link IBackupTransport#initializeDevice()} - * <li>{@link BackupManagerService#resetBackupState(File)} being called, which will: + * <li>{@link UserBackupManagerService#resetBackupState(File)} being called, which will: * <ul> * <li>Reset processed packages journal. * <li>Reset current token to 0. @@ -2617,7 +2617,7 @@ public class KeyValueBackupTaskTest { /** * Forces transport initialization and call to {@link - * BackupManagerService#resetBackupState(File)} + * UserBackupManagerService#resetBackupState(File)} */ private void deletePmStateFile() throws IOException { Files.deleteIfExists(getStateFile(mTransport, PM_PACKAGE)); diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java index 0e2b95b3167d..859392d80d36 100644 --- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java +++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java @@ -51,8 +51,8 @@ import android.platform.test.annotations.Presubmit; import com.android.server.EventLogTags; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.internal.BackupHandler; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportTestUtils; @@ -85,7 +85,7 @@ public class ActiveRestoreSessionTest { private static final long TOKEN_1 = 1L; private static final long TOKEN_2 = 2L; - @Mock private BackupManagerService mBackupManagerService; + @Mock private UserBackupManagerService mBackupManagerService; @Mock private TransportManager mTransportManager; @Mock private IRestoreObserver mObserver; @Mock private IBackupManagerMonitor mMonitor; diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java index f3077309d222..bacc44e685f4 100644 --- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java +++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java @@ -37,9 +37,9 @@ import android.os.Process; import android.util.Log; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.Trampoline; import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; import org.mockito.stubbing.Answer; import org.robolectric.shadows.ShadowApplication; @@ -49,26 +49,26 @@ import java.io.File; import java.lang.Thread.UncaughtExceptionHandler; import java.util.concurrent.atomic.AtomicReference; -/** Test utils for {@link BackupManagerService} and friends. */ +/** Test utils for {@link UserBackupManagerService} and friends. */ public class BackupManagerServiceTestUtils { /** * If the class-under-test is going to execute methods as the system, it's a good idea to also * call {@link #setUpBinderCallerAndApplicationAsSystem(Application)} before this method. */ - public static BackupManagerService createInitializedBackupManagerService( + public static UserBackupManagerService createInitializedUserBackupManagerService( Context context, File baseStateDir, File dataDir, TransportManager transportManager) { - return createInitializedBackupManagerService( + return createInitializedUserBackupManagerService( context, startBackupThread(null), baseStateDir, dataDir, transportManager); } - public static BackupManagerService createInitializedBackupManagerService( + public static UserBackupManagerService createInitializedUserBackupManagerService( Context context, HandlerThread backupThread, File baseStateDir, File dataDir, TransportManager transportManager) { - BackupManagerService backupManagerService = - new BackupManagerService( + UserBackupManagerService backupManagerService = + new UserBackupManagerService( context, new Trampoline(context), backupThread, @@ -80,15 +80,16 @@ public class BackupManagerServiceTestUtils { } /** - * Sets up basic mocks for {@link BackupManagerService} mock. If {@code backupManagerService} is - * a spy, make sure you provide in the arguments the same objects that the original object uses. + * Sets up basic mocks for {@link UserBackupManagerService} mock. If {@code + * backupManagerService} is a spy, make sure you provide in the arguments the same objects that + * the original object uses. * * <p>If the class-under-test is going to execute methods as the system, it's a good idea to * also call {@link #setUpBinderCallerAndApplicationAsSystem(Application)}. */ @SuppressWarnings("ResultOfMethodCallIgnored") public static void setUpBackupManagerServiceBasics( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, Application application, TransportManager transportManager, PackageManager packageManager, diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java index ca8066403eca..ac5d2da9c3cf 100644 --- a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java +++ b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java @@ -18,8 +18,8 @@ package com.android.server.testing.shadows; import android.annotation.Nullable; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.DataChangedJournal; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.keyvalue.KeyValueBackupReporter; import com.android.server.backup.keyvalue.KeyValueBackupTask; @@ -54,7 +54,7 @@ public class ShadowKeyValueBackupTask { @Implementation protected void __constructor__( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, TransportClient transportClient, String transportDirName, List<String> queue, diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java index 228d4eb818a4..2cebbebfbaf4 100644 --- a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java +++ b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java @@ -21,7 +21,7 @@ import android.app.backup.IBackupManagerMonitor; import android.app.backup.IRestoreObserver; import android.content.pm.PackageInfo; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.restore.PerformUnifiedRestoreTask; import com.android.server.backup.transport.TransportClient; @@ -47,7 +47,7 @@ public class ShadowPerformUnifiedRestoreTask { sLastShadow = null; } - private BackupManagerService mBackupManagerService; + private UserBackupManagerService mBackupManagerService; @Nullable private PackageInfo mPackage; private boolean mIsFullSystemRestore; @Nullable private String[] mFilterSet; @@ -55,7 +55,7 @@ public class ShadowPerformUnifiedRestoreTask { @Implementation protected void __constructor__( - BackupManagerService backupManagerService, + UserBackupManagerService backupManagerService, TransportClient transportClient, IRestoreObserver observer, IBackupManagerMonitor monitor, diff --git a/services/tests/servicestests/res/xml/shortcut_share_targets.xml b/services/tests/servicestests/res/xml/shortcut_share_targets.xml new file mode 100644 index 000000000000..ec696e9256f8 --- /dev/null +++ b/services/tests/servicestests/res/xml/shortcut_share_targets.xml @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright 2018 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- Test XML resource to read share-targets from, used in ShortcutManagerTest1.java --> +<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> + <shortcut + android:shortcutId="dummy_shortcut1" + android:enabled="true" + android:shortcutShortLabel="@string/shortcut_title1"> + <intent + android:action="android.intent.action.VIEW" + android:targetPackage="com.test.somepackage" + android:targetClass="com.test.somepackage.someclass" /> + <categories android:name="android.shortcut.conversation" /> + </shortcut> + + <!-- Valid share target definition --> + <share-target android:targetClass="com.test.directshare.TestActivity1"> + <data + android:scheme="http" + android:host="www.google.com" + android:port="1234" + android:path="somePath" + android:pathPrefix="somePathPrefix" + android:pathPattern="somePathPattern" + android:mimeType="text/plain"/> + <category android:name="com.test.category.CATEGORY1"/> + <category android:name="com.test.category.CATEGORY2"/> + </share-target> + + <!-- Share target missing data tag, will be dropped --> + <share-target android:targetClass="com.test.directshare.TestActivity"> + <category android:name="com.test.category.CATEGORY2"/> + </share-target> + + <!-- Share target missing target class, will be dropped --> + <share-target> + <data + android:scheme="file" + android:host="www.somehost.com" + android:port="1234" + android:mimeType="video/*"/> + <category android:name="com.test.category.CATEGORY3"/> + </share-target> + + <shortcut + android:shortcutId="dummy_shortcut2" + android:enabled="true" + android:shortcutShortLabel="@string/shortcut_title1"> + <intent + android:action="android.intent.action.VIEW" + android:targetPackage="com.test.somepackage" + android:targetClass="com.test.somepackage.someclass" /> + <categories android:name="android.shortcut.conversation" /> + </shortcut> + + <!-- Share target missing category, will be dropped --> + <share-target android:targetClass="com.test.directshare.TestActivity"> + <data + android:scheme="content" + android:mimeType="text/plain"/> + </share-target> + + <!-- Valid share target definition --> + <share-target android:targetClass="com.test.directshare.TestActivity5"> + <category android:name="com.test.category.CATEGORY5"/> + <category android:name="com.test.category.CATEGORY6"/> + <data android:mimeType="video/mp4"/> + <data + android:scheme="content" + android:mimeType="video/*"/> + </share-target> +</shortcuts>
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java index 7c002995a769..c99e2a850679 100644 --- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java @@ -83,7 +83,7 @@ public class TrampolineTest { }; private final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1; - @Mock private BackupManagerService mBackupManagerServiceMock; + @Mock private GlobalBackupManagerService mBackupManagerServiceMock; @Mock private Context mContextMock; @Mock private File mSuppressFileMock; @Mock private File mSuppressFileParentMock; @@ -864,7 +864,7 @@ public class TrampolineTest { static boolean sBackupDisabled = false; static File sSuppressFile = null; static int sCallingUid = -1; - static BackupManagerService sBackupManagerServiceMock = null; + static GlobalBackupManagerService sBackupManagerServiceMock = null; private int mCreateServiceCallsCount = 0; TrampolineTestable(Context context) { @@ -887,7 +887,7 @@ public class TrampolineTest { } @Override - protected BackupManagerService createBackupManagerService() { + protected GlobalBackupManagerService createBackupManagerService() { mCreateServiceCallsCount++; return sBackupManagerServiceMock; } 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 d52051eec5bd..479a19b93ca7 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 @@ -34,7 +34,7 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.server.backup.BackupManagerService; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.testutils.PackageManagerStub; import org.junit.Before; @@ -97,7 +97,7 @@ public class AppBackupUtilsTest { applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; applicationInfo.uid = Process.SYSTEM_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; - applicationInfo.packageName = BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; + applicationInfo.packageName = UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManagerStub); diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java index 47749856a7ec..d43b677d0e50 100644 --- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java @@ -51,8 +51,8 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.servicestests.R; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.FileMetadata; +import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.restore.PerformAdbRestoreTask; import com.android.server.backup.restore.RestorePolicy; import com.android.server.backup.testutils.PackageManagerStub; @@ -150,7 +150,7 @@ public class TarBackupReaderTest { assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE); assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME); - assertThat(fileMetadata.path).isEqualTo(BackupManagerService.BACKUP_MANIFEST_FILENAME); + assertThat(fileMetadata.path).isEqualTo(UserBackupManagerService.BACKUP_MANIFEST_FILENAME); tarBackupReader.skipTarPadding(fileMetadata.size); diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index a3348c26f772..1f5c64e92ac0 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -91,8 +91,8 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.LauncherAppsService.LauncherAppsImpl; import com.android.server.pm.ShortcutUser.PackageWithUser; - import com.android.server.wm.ActivityTaskManagerInternal; + import org.junit.Assert; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; @@ -105,8 +105,6 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -762,6 +760,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mMockActivityManagerInternal); + LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); LocalServices.addService(ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal); LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); @@ -963,6 +962,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return getInstrumentation().getContext(); } + protected Context getClientContext() { + return mClientContext; + } + protected ShortcutManager getManager() { return mManager; } @@ -1792,6 +1795,15 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } /** + * @return all share targets stored internally for the caller. + */ + protected List<ShareTargetInfo> getCallerShareTargets() { + final ShortcutPackage p = mService.getPackageShortcutForTest( + getCallingPackage(), getCallingUserId()); + return p == null ? null : p.getAllShareTargetsForTest(); + } + + /** * @return all shortcuts owned by caller that are actually visible via ShortcutManager. * See also {@link #getCallerShortcuts}. */ diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index fa734477cfe7..3172afbb086f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -106,6 +106,7 @@ import org.mockito.ArgumentCaptor; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.BiConsumer; @@ -398,7 +399,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(3, mManager.getRemainingCallCount()); } - public void testPublishWithNoActivity() { + public void testPublishWithNoActivity() { // If activity is not explicitly set, use the default one. mRunningUsers.put(USER_10, true); @@ -8015,4 +8016,56 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertFalse(mInternal.isForegroundDefaultLauncher("another", uid)); } + + public void testParseShareTargetsFromManifest() { + // These values must exactly match the content of shortcuts_share_targets.xml resource + List<ShareTargetInfo> expectedValues = new ArrayList<>(); + expectedValues.add(new ShareTargetInfo( + new ShareTargetInfo.TargetData[]{new ShareTargetInfo.TargetData( + "http", "www.google.com", "1234", "somePath", "somePathPattern", + "somePathPrefix", "text/plain")}, "com.test.directshare.TestActivity1", + new String[]{"com.test.category.CATEGORY1", "com.test.category.CATEGORY2"})); + expectedValues.add(new ShareTargetInfo(new ShareTargetInfo.TargetData[]{ + new ShareTargetInfo.TargetData(null, null, null, null, null, null, "video/mp4"), + new ShareTargetInfo.TargetData("content", null, null, null, null, null, "video/*")}, + "com.test.directshare.TestActivity5", + new String[]{"com.test.category.CATEGORY5", "com.test.category.CATEGORY6"})); + + addManifestShortcutResource( + new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), + R.xml.shortcut_share_targets); + updatePackageVersion(CALLING_PACKAGE_1, 1); + mService.mPackageMonitor.onReceive(getTestContext(), + genPackageAddIntent(CALLING_PACKAGE_1, USER_0)); + + List<ShareTargetInfo> shareTargets = getCallerShareTargets(); + + assertNotNull(shareTargets); + assertEquals(expectedValues.size(), shareTargets.size()); + + for (int i = 0; i < expectedValues.size(); i++) { + ShareTargetInfo expected = expectedValues.get(i); + ShareTargetInfo actual = shareTargets.get(i); + + assertEquals(expected.mTargetData.length, actual.mTargetData.length); + for (int j = 0; j < expected.mTargetData.length; j++) { + assertEquals(expected.mTargetData[j].mScheme, actual.mTargetData[j].mScheme); + assertEquals(expected.mTargetData[j].mHost, actual.mTargetData[j].mHost); + assertEquals(expected.mTargetData[j].mPort, actual.mTargetData[j].mPort); + assertEquals(expected.mTargetData[j].mPath, actual.mTargetData[j].mPath); + assertEquals(expected.mTargetData[j].mPathPrefix, + actual.mTargetData[j].mPathPrefix); + assertEquals(expected.mTargetData[j].mPathPattern, + actual.mTargetData[j].mPathPattern); + assertEquals(expected.mTargetData[j].mMimeType, actual.mTargetData[j].mMimeType); + } + + assertEquals(expected.mTargetClass, actual.mTargetClass); + + assertEquals(expected.mCategories.length, actual.mCategories.length); + for (int j = 0; j < expected.mCategories.length; j++) { + assertEquals(expected.mCategories[j], actual.mCategories[j]); + } + } + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 76d52fd48431..9b59f9151fd0 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -144,8 +144,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertExpectException( IllegalArgumentException.class, "Short label must be provided", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") - .setActivity(new ComponentName(getTestContext().getPackageName(), "s")) + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") + .setActivity(new ComponentName(getClientContext().getPackageName(), "s")) .build(); assertTrue(getManager().setDynamicShortcuts(list(si))); }); @@ -153,15 +153,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // same for add. assertExpectException( IllegalArgumentException.class, "Short label must be provided", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") - .setActivity(new ComponentName(getTestContext().getPackageName(), "s")) + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") + .setActivity(new ComponentName(getClientContext().getPackageName(), "s")) .build(); assertTrue(getManager().addDynamicShortcuts(list(si))); }); assertExpectException(NullPointerException.class, "Intent must be provided", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") - .setActivity(new ComponentName(getTestContext().getPackageName(), "s")) + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") + .setActivity(new ComponentName(getClientContext().getPackageName(), "s")) .setShortLabel("x") .build(); assertTrue(getManager().setDynamicShortcuts(list(si))); @@ -169,8 +169,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // same for add. assertExpectException(NullPointerException.class, "Intent must be provided", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") - .setActivity(new ComponentName(getTestContext().getPackageName(), "s")) + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") + .setActivity(new ComponentName(getClientContext().getPackageName(), "s")) .setShortLabel("x") .build(); assertTrue(getManager().addDynamicShortcuts(list(si))); @@ -178,7 +178,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertExpectException( IllegalStateException.class, "does not belong to package", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") .setActivity(new ComponentName("xxx", "s")) .build(); assertTrue(getManager().setDynamicShortcuts(list(si))); @@ -187,7 +187,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { // same for add. assertExpectException( IllegalStateException.class, "does not belong to package", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") .setActivity(new ComponentName("xxx", "s")) .build(); assertTrue(getManager().addDynamicShortcuts(list(si))); @@ -198,24 +198,24 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertExpectException( IllegalStateException.class, "is not main", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") - .setActivity(new ComponentName(getTestContext(), "s")) + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") + .setActivity(new ComponentName(getClientContext(), "s")) .build(); assertTrue(getManager().setDynamicShortcuts(list(si))); }); // For add assertExpectException( IllegalStateException.class, "is not main", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") - .setActivity(new ComponentName(getTestContext(), "s")) + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") + .setActivity(new ComponentName(getClientContext(), "s")) .build(); assertTrue(getManager().addDynamicShortcuts(list(si))); }); // For update assertExpectException( IllegalStateException.class, "is not main", () -> { - ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id") - .setActivity(new ComponentName(getTestContext(), "s")) + ShortcutInfo si = new ShortcutInfo.Builder(getClientContext(), "id") + .setActivity(new ComponentName(getClientContext(), "s")) .build(); assertTrue(getManager().updateShortcuts(list(si))); }); 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 5eda14f7f387..fcd29e13a07b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -38,10 +38,8 @@ import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.os.Build.VERSION_CODES.O_MR1; import static android.os.Build.VERSION_CODES.P; -import static android.service.notification.NotificationListenerService.Ranking - .USER_SENTIMENT_NEGATIVE; -import static android.service.notification.NotificationListenerService.Ranking - .USER_SENTIMENT_NEUTRAL; +import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; +import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -2508,6 +2506,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied()); + verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r.sbn)); } @Test @@ -2516,8 +2515,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(r); mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true); + verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(true), eq((true))); assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); + mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false); + verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(true), eq((false))); assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); } @@ -2528,8 +2530,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true); assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); + verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(false), eq((true))); + mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false); assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); + verify(mAssistants).notifyAssistantExpansionChangedLocked( + eq(r.sbn), eq(false), eq((false))); } @Test @@ -3690,4 +3696,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { new TestableToastCallback(), 2000, 0); assertEquals(1, mService.mToastQueue.size()); } + + @Test + public void testOnNotificationSmartReplySent() { + final int replyIndex = 2; + final String reply = "Hello"; + final boolean generatedByAssistant = true; + + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + mService.addNotification(r); + + mService.mNotificationDelegate.onNotificationSmartReplySent( + r.getKey(), replyIndex, reply, generatedByAssistant); + verify(mAssistants).notifyAssistantSuggestedReplySent( + eq(r.sbn), eq(reply), eq(generatedByAssistant)); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index cb2a8ec8a274..5bf3d2dabe24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -62,8 +62,9 @@ public class ActivityDisplayTests extends ActivityTestsBase { @Test public void testLastFocusedStackIsUpdatedWhenMovingStack() { // Create a stack at bottom. - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final ActivityStack stack = new StackBuilder(mSupervisor).setOnTop(!ON_TOP).build(); + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); + final ActivityStack stack = + new StackBuilder(mRootActivityContainer).setOnTop(!ON_TOP).build(); final ActivityStack prevFocusedStack = display.getFocusedStack(); stack.moveToFront("moveStackToFront"); @@ -83,7 +84,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { @Test public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() { // Create a pinned stack and move to front. - final ActivityStack pinnedStack = mSupervisor.getDefaultDisplay().createStack( + final ActivityStack pinnedStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); final TaskRecord pinnedTask = new TaskBuilder(mService.mStackSupervisor) .setStack(pinnedStack).build(); @@ -96,7 +97,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { // Create a fullscreen stack and move to front. final ActivityStack fullscreenStack = createFullscreenStackWithSimpleActivityAt( - mSupervisor.getDefaultDisplay()); + mRootActivityContainer.getDefaultDisplay()); fullscreenStack.moveToFront("moveFullscreenStackToFront"); // The focused stack should be the fullscreen stack. @@ -138,7 +139,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { final ActivityDisplay display = spy(createNewActivityDisplay()); doReturn(false).when(display).shouldDestroyContentOnRemove(); doReturn(true).when(display).supportsSystemDecorations(); - mSupervisor.addChild(display, ActivityDisplay.POSITION_TOP); + mRootActivityContainer.addChild(display, ActivityDisplay.POSITION_TOP); // Put home stack on the display. final ActivityStack homeStack = display.createStack( @@ -175,14 +176,14 @@ public class ActivityDisplayTests extends ActivityTestsBase { */ @Test public void testTopRunningActivity() { - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); final KeyguardController keyguard = mSupervisor.getKeyguardController(); - final ActivityStack stack = new StackBuilder(mSupervisor).build(); + final ActivityStack stack = new StackBuilder(mRootActivityContainer).build(); final ActivityRecord activity = stack.getTopActivity(); // Create empty stack on top. final ActivityStack emptyStack = - new StackBuilder(mSupervisor).setCreateActivity(false).build(); + new StackBuilder(mRootActivityContainer).setCreateActivity(false).build(); // Make sure the top running activity is not affected when keyguard is not locked. assertTopRunningActivity(activity, display); @@ -225,7 +226,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { */ @Test public void testAlwaysOnTopStackLocation() { - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); final ActivityStack alwaysOnTopStack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index c7f0521adb7b..0e30037bde6c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -74,7 +74,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. // This seems to be the easiest way to create an ActivityRecord. - mStack = mSupervisor.getDefaultDisplay().createStack( + mStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 170bd3311de2..b15b8c1977cb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -65,7 +65,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Before public void setUp() throws Exception { setupActivityTaskManagerService(); - mStack = new StackBuilder(mSupervisor).build(); + mStack = new StackBuilder(mRootActivityContainer).build(); mTask = mStack.getChildAt(0); mActivity = mTask.getTopActivity(); } @@ -86,7 +86,7 @@ public class ActivityRecordTests extends ActivityTestsBase { public void testStackCleanupOnTaskRemoval() { mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING); // Stack should be gone on task removal. - assertNull(mService.mStackSupervisor.getStack(mStack.mStackId)); + assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId)); } @Test @@ -116,7 +116,7 @@ public class ActivityRecordTests extends ActivityTestsBase { assertFalse(pauseFound.value); // Clear focused stack - final ActivityDisplay display = mActivity.mStackSupervisor.getDefaultDisplay(); + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); when(display.getFocusedStack()).thenReturn(null); // In the unfocused stack, the activity should move to paused. diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index 8a6d5873927a..78a67d212f24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -38,8 +38,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityDisplay.POSITION_TOP; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.wm.ActivityStackSupervisor - .MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; import static com.google.common.truth.Truth.assertThat; @@ -83,78 +82,11 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { @Before public void setUp() throws Exception { setupActivityTaskManagerService(); - mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); } /** - * This test ensures that we do not try to restore a task based off an invalid task id. We - * should expect {@code null} to be returned in this case. - */ - @Test - public void testRestoringInvalidTask() { - ((TestActivityDisplay) mSupervisor.getDefaultDisplay()).removeAllTasks(); - TaskRecord task = mSupervisor.anyTaskForIdLocked(0 /*taskId*/, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */); - assertNull(task); - } - - /** - * This test ensures that an existing task in the pinned stack is moved to the fullscreen - * activity stack when a new task is added. - */ - @Test - public void testReplacingTaskInPinnedStack() { - final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(mFullscreenStack).build(); - final TaskRecord firstTask = firstActivity.getTask(); - - final ActivityRecord secondActivity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(mFullscreenStack).build(); - final TaskRecord secondTask = secondActivity.getTask(); - - mFullscreenStack.moveToFront("testReplacingTaskInPinnedStack"); - - // Ensure full screen stack has both tasks. - ensureStackPlacement(mFullscreenStack, firstTask, secondTask); - - // Move first activity to pinned stack. - final Rect sourceBounds = new Rect(); - mSupervisor.moveActivityToPinnedStackLocked(firstActivity, sourceBounds, - 0f /*aspectRatio*/, "initialMove"); - - final ActivityDisplay display = mFullscreenStack.getDisplay(); - ActivityStack pinnedStack = display.getPinnedStack(); - // Ensure a task has moved over. - ensureStackPlacement(pinnedStack, firstTask); - ensureStackPlacement(mFullscreenStack, secondTask); - - // Move second activity to pinned stack. - mSupervisor.moveActivityToPinnedStackLocked(secondActivity, sourceBounds, - 0f /*aspectRatio*/, "secondMove"); - - // Need to get stacks again as a new instance might have been created. - pinnedStack = display.getPinnedStack(); - mFullscreenStack = display.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - // Ensure stacks have swapped tasks. - ensureStackPlacement(pinnedStack, secondTask); - ensureStackPlacement(mFullscreenStack, firstTask); - } - - private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) { - final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); - assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); - - if (tasks == null) { - return; - } - - for (TaskRecord task : tasks) { - assertTrue(stackTasks.contains(task)); - } - } - - /** * Ensures that an activity is removed from the stopping activities list once it is resumed. */ @Test @@ -179,7 +111,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { // #notifyAll will be called on the ActivityManagerService. we must hold the object lock // when this happens. - synchronized (mSupervisor.mService.mGlobalLock) { + synchronized (mService.mGlobalLock) { final WaitResult taskToFrontWait = new WaitResult(); mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait); mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT); @@ -198,334 +130,4 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { assertEquals(deliverToTopWait.who, firstActivity.realActivity); } } - - @Test - public void testApplySleepTokensLocked() { - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final KeyguardController keyguard = mSupervisor.getKeyguardController(); - final ActivityStack stack = mock(ActivityStack.class); - display.addChild(stack, 0 /* position */); - - // Make sure we wake and resume in the case the display is turning on and the keyguard is - // not showing. - verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/, - false /* displayShouldSleep */, true /* isFocusedStack */, - false /* keyguardShowing */, true /* expectWakeFromSleep */, - true /* expectResumeTopActivity */); - - // Make sure we wake and don't resume when the display is turning on and the keyguard is - // showing. - verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/, - false /* displayShouldSleep */, true /* isFocusedStack */, - true /* keyguardShowing */, true /* expectWakeFromSleep */, - false /* expectResumeTopActivity */); - - // Make sure we wake and don't resume when the display is turning on and the keyguard is - // not showing as unfocused. - verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/, - false /* displayShouldSleep */, false /* isFocusedStack */, - false /* keyguardShowing */, true /* expectWakeFromSleep */, - false /* expectResumeTopActivity */); - - // Should not do anything if the display state hasn't changed. - verifySleepTokenBehavior(display, keyguard, stack, false /*displaySleeping*/, - false /* displayShouldSleep */, true /* isFocusedStack */, - false /* keyguardShowing */, false /* expectWakeFromSleep */, - false /* expectResumeTopActivity */); - } - - private void verifySleepTokenBehavior(ActivityDisplay display, KeyguardController keyguard, - ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep, - boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep, - boolean expectResumeTopActivity) { - reset(stack); - - doReturn(displayShouldSleep).when(display).shouldSleep(); - doReturn(displaySleeping).when(display).isSleeping(); - doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt()); - - doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay(); - doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack(); - mSupervisor.applySleepTokensLocked(true); - verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked(); - verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked( - null /* target */, null /* targetOptions */); - } - - /** - * Verifies that removal of activity with task and stack is done correctly. - */ - @Test - public void testRemovingStackOnAppCrash() { - final ActivityDisplay defaultDisplay = mService.mStackSupervisor.getDefaultDisplay(); - final int originalStackCount = defaultDisplay.getChildCount(); - final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); - final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(stack).build(); - - assertEquals(originalStackCount + 1, defaultDisplay.getChildCount()); - - // Let's pretend that the app has crashed. - firstActivity.app.setThread(null); - mService.mStackSupervisor.finishTopCrashedActivitiesLocked(firstActivity.app, "test"); - - // Verify that the stack was removed. - assertEquals(originalStackCount, defaultDisplay.getChildCount()); - } - - @Test - public void testFocusability() { - final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(stack).build(); - - // Under split screen primary we should be focusable when not minimized - mService.mStackSupervisor.setDockedStackMinimized(false); - assertTrue(stack.isFocusable()); - assertTrue(activity.isFocusable()); - - // Under split screen primary we should not be focusable when minimized - mService.mStackSupervisor.setDockedStackMinimized(true); - assertFalse(stack.isFocusable()); - assertFalse(activity.isFocusable()); - - final ActivityStack pinnedStack = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(pinnedStack).build(); - - // We should not be focusable when in pinned mode - assertFalse(pinnedStack.isFocusable()); - assertFalse(pinnedActivity.isFocusable()); - - // Add flag forcing focusability. - pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE; - - // We should not be focusable when in pinned mode - assertTrue(pinnedStack.isFocusable()); - assertTrue(pinnedActivity.isFocusable()); - - // Without the overridding activity, stack should not be focusable. - pinnedStack.removeTask(pinnedActivity.getTask(), "testFocusability", - REMOVE_TASK_MODE_DESTROYING); - assertFalse(pinnedStack.isFocusable()); - } - - /** - * Verify that split-screen primary stack will be chosen if activity is launched that targets - * split-screen secondary, but a matching existing instance is found on top of split-screen - * primary stack. - */ - @Test - public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() { - // Create primary split-screen stack with a task and an activity. - final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay() - .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, - true /* onTop */); - final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); - final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build(); - - // Find a launch stack for the top activity in split-screen primary, while requesting - // split-screen secondary. - final ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); - final ActivityStack result = mSupervisor.getLaunchStack(r, options, task, true /* onTop */); - - // Assert that the primary stack is returned. - assertEquals(primaryStack, result); - } - - /** - * Verify split-screen primary stack & task can resized by - * {@link android.app.IActivityTaskManager#resizeDockedStack} as expect. - */ - @Test - public void testResizeDockedStackForSplitScreenPrimary() { - final Rect taskSize = new Rect(0, 0, 600, 600); - final Rect stackSize = new Rect(0, 0, 300, 300); - - // Create primary split-screen stack with a task. - final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay() - .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, - true /* onTop */); - final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); - - // Resize dock stack. - mService.resizeDockedStack(stackSize, taskSize, null, null, null); - - // Verify dock stack & its task bounds if is equal as resized result. - assertEquals(primaryStack.getBounds(), stackSize); - assertEquals(task.getBounds(), taskSize); - } - - /** - * Verify that home stack would be moved to front when the top activity is Recents. - */ - @Test - public void testFindTaskToMoveToFrontWhenRecentsOnTop() { - // Create stack/task on default display. - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final TestActivityStack targetStack = new StackBuilder(mSupervisor).setOnTop(false).build(); - final TaskRecord targetTask = targetStack.getChildAt(0); - - // Create Recents on top of the display. - final ActivityStack stack = - new StackBuilder(mSupervisor).setActivityType(ACTIVITY_TYPE_RECENTS).build(); - - final String reason = "findTaskToMoveToFront"; - mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, - false); - - verify(display).moveHomeStackToFront(contains(reason)); - } - - /** - * Verify that home stack won't be moved to front if the top activity on other display is - * Recents. - */ - @Test - public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() { - // Create stack/task on default display. - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, false /* onTop */); - final TaskRecord targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build(); - - // Create Recents on secondary display. - final TestActivityDisplay secondDisplay = addNewActivityDisplayAt( - ActivityDisplay.POSITION_TOP); - final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_RECENTS, true /* onTop */); - final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build(); - new ActivityBuilder(mService).setTask(task).build(); - - final String reason = "findTaskToMoveToFront"; - mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, - false); - - verify(display, never()).moveHomeStackToFront(contains(reason)); - } - - /** - * Verify if a stack is not at the topmost position, it should be able to resume its activity if - * the stack is the top focused. - */ - @Test - public void testResumeActivityWhenNonTopmostStackIsTopFocused() { - // Create a stack at bottom. - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, false /* onTop */)); - final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); - final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); - display.positionChildAtBottom(targetStack); - - // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it - // is the current top focused stack. - assertFalse(targetStack.isTopStackOnDisplay()); - doReturn(targetStack).when(mSupervisor).getTopDisplayFocusedStack(); - - // Use the stack as target to resume. - mSupervisor.resumeFocusedStacksTopActivitiesLocked( - targetStack, activity, null /* targetOptions */); - - // Verify the target stack should resume its activity. - verify(targetStack, times(1)).resumeTopActivityUncheckedLocked( - eq(activity), eq(null /* targetOptions */)); - } - - /** - * Tests home activities that targeted sdk before Q cannot start on secondary display. - */ - @Test - public void testStartHomeTargetSdkBeforeQ() throws Exception { - final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay()); - mSupervisor.addChild(secondDisplay, POSITION_TOP); - doReturn(true).when(secondDisplay).supportsSystemDecorations(); - - final ActivityInfo info = new ActivityInfo(); - info.launchMode = LAUNCH_MULTIPLE; - info.applicationInfo = new ApplicationInfo(); - info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; - assertTrue(mSupervisor.canStartHomeOnDisplay(info, secondDisplay.mDisplayId, - false /* allowInstrumenting */)); - - info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.P; - assertFalse(mSupervisor.canStartHomeOnDisplay(info, secondDisplay.mDisplayId, - false /* allowInstrumenting */)); - } - - /** - * Tests that home activities can be started on the displays that supports system decorations. - */ - @Test - public void testStartHomeOnAllDisplays() { - // Create secondary displays. - final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay()); - mSupervisor.addChild(secondDisplay, POSITION_TOP); - doReturn(true).when(secondDisplay).supportsSystemDecorations(); - - // Create mock tasks and other necessary mocks. - TaskBuilder taskBuilder = new TaskBuilder(mService.mStackSupervisor).setCreateStack(false); - final TaskRecord.TaskRecordFactory factory = mock(TaskRecord.TaskRecordFactory.class); - TaskRecord.setTaskRecordFactory(factory); - doAnswer(i -> taskBuilder.build()).when(factory) - .create(any(), anyInt(), any(), any(), any(), any()); - doReturn(true).when(mService.mStackSupervisor) - .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean()); - doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt(), anyBoolean()); - - mSupervisor.startHomeOnAllDisplays(0, "testStartHome"); - - assertTrue(mSupervisor.getDefaultDisplay().getTopStack().isActivityTypeHome()); - assertNotNull(secondDisplay.getTopStack()); - assertTrue(secondDisplay.getTopStack().isActivityTypeHome()); - } - - /** - * Tests that home activities won't be started before booting when display added. - */ - @Test - public void testNotStartHomeBeforeBoot() { - final int displayId = 1; - final boolean isBooting = mService.mAmInternal.isBooting(); - final boolean isBooted = mService.mAmInternal.isBooted(); - try { - mService.mAmInternal.setBooting(false); - mService.mAmInternal.setBooted(false); - mSupervisor.onDisplayAdded(displayId); - verify(mSupervisor, never()).startHomeOnDisplay(anyInt(), any(), anyInt()); - } finally { - mService.mAmInternal.setBooting(isBooting); - mService.mAmInternal.setBooted(isBooted); - } - } - - /** - * Tests whether home can be started if being instrumented. - */ - @Test - public void testCanStartHomeWhenInstrumented() { - final ActivityInfo info = new ActivityInfo(); - info.applicationInfo = new ApplicationInfo(); - final WindowProcessController app = mock(WindowProcessController.class); - doReturn(app).when(mService).getProcessController(any(), anyInt()); - - // Can not start home if we don't want to start home while home is being instrumented. - doReturn(true).when(app).isInstrumenting(); - assertFalse(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, - false /* allowInstrumenting*/)); - - // Can start home for other cases. - assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, - true /* allowInstrumenting*/)); - - doReturn(false).when(app).isInstrumenting(); - assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, - false /* allowInstrumenting*/)); - assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, - true /* allowInstrumenting*/)); - } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 2fe45b86df4a..0da0b247b60c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -74,7 +74,7 @@ public class ActivityStackTests extends ActivityTestsBase { @Before public void setUp() throws Exception { setupActivityTaskManagerService(); - mDefaultDisplay = mSupervisor.getDefaultDisplay(); + mDefaultDisplay = mRootActivityContainer.getDefaultDisplay(); mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */)); mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); @@ -112,7 +112,7 @@ public class ActivityStackTests extends ActivityTestsBase { r.setState(RESUMED, "testResumedActivityFromTaskReparenting"); assertEquals(r, mStack.getResumedActivity()); - final ActivityStack destStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + final ActivityStack destStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mTask.reparent(destStack, true /* toTop */, TaskRecord.REPARENT_KEEP_STACK_AT_FRONT, @@ -130,7 +130,7 @@ public class ActivityStackTests extends ActivityTestsBase { r.setState(RESUMED, "testResumedActivityFromActivityReparenting"); assertEquals(r, mStack.getResumedActivity()); - final ActivityStack destStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + final ActivityStack destStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final TaskRecord destTask = new TaskBuilder(mSupervisor).setStack(destStack).build(); @@ -239,8 +239,8 @@ public class ActivityStackTests extends ActivityTestsBase { .setUid(UserHandle.PER_USER_RANGE * 2).build(); taskOverlay.mTaskOverlay = true; - final ActivityStackSupervisor.FindTaskResult result = - new ActivityStackSupervisor.FindTaskResult(); + final RootActivityContainer.FindTaskResult result = + new RootActivityContainer.FindTaskResult(); mStack.findTaskLocked(r, result); assertEquals(r, task.getTopActivity(false /* includeOverlays */)); @@ -700,7 +700,7 @@ public class ActivityStackTests extends ActivityTestsBase { // should be destroyed immediately with updating configuration to restore original state. final ActivityRecord activity1 = finishCurrentActivity(stack1); assertEquals(DESTROYING, activity1.getState()); - verify(mSupervisor).ensureVisibilityAndConfig(eq(null) /* starting */, + verify(mRootActivityContainer).ensureVisibilityAndConfig(eq(null) /* starting */, eq(display.mDisplayId), anyBoolean(), anyBoolean()); } @@ -778,7 +778,7 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityDisplay display = mock(ActivityDisplay.class); final KeyguardController keyguardController = mSupervisor.getKeyguardController(); - doReturn(display).when(mSupervisor).getActivityDisplay(anyInt()); + doReturn(display).when(mRootActivityContainer).getActivityDisplay(anyInt()); doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway(); doReturn(displaySleeping).when(display).isSleeping(); doReturn(focusedStack).when(mStack).isFocusedStackOnDisplay(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index 9d93c85480bc..2ba2fdbcb959 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -74,7 +74,7 @@ public class ActivityStartControllerTests extends ActivityTestsBase { final ActivityRecord activity = new ActivityBuilder(mService).build(); final ActivityRecord source = new ActivityBuilder(mService).build(); final int startFlags = random.nextInt(); - final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( + final ActivityStack stack = mService.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final WindowProcessController wpc = new WindowProcessController(mService, mService.mContext.getApplicationInfo(), "name", 12345, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java index 27fa20b91a80..350114c792bf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -90,6 +90,8 @@ public class ActivityStartInterceptorTest { @Mock private ActivityTaskManagerService mService; @Mock + private RootActivityContainer mRootActivityContainer; + @Mock private ActivityStackSupervisor mSupervisor; @Mock private DevicePolicyManagerInternal mDevicePolicyManager; @@ -111,7 +113,8 @@ public class ActivityStartInterceptorTest { public void setUp() { MockitoAnnotations.initMocks(this); mService.mAmInternal = mAmInternal; - mInterceptor = new ActivityStartInterceptor(mService, mSupervisor, mContext); + mInterceptor = new ActivityStartInterceptor( + mService, mSupervisor, mRootActivityContainer, mContext); mInterceptor.setStates(TEST_USER_ID, TEST_REAL_CALLING_PID, TEST_REAL_CALLING_UID, TEST_START_FLAGS, TEST_CALLING_PACKAGE); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 50aa541a9549..4840a64bcbb4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -125,7 +125,7 @@ public class ActivityStarterTests extends ActivityTestsBase { public void testUpdateLaunchBounds() { // When in a non-resizeable stack, the task bounds should be updated. final TaskRecord task = new TaskBuilder(mService.mStackSupervisor) - .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack( + .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */)) .build(); final Rect bounds = new Rect(10, 10, 100, 100); @@ -136,7 +136,7 @@ public class ActivityStarterTests extends ActivityTestsBase { // When in a resizeable stack, the stack bounds should be updated as well. final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor) - .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack( + .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */)) .build(); assertThat((Object) task2.getStack()).isInstanceOf(PinnedActivityStack.class); @@ -314,7 +314,7 @@ public class ActivityStarterTests extends ActivityTestsBase { * Creates a {@link ActivityStarter} with default parameters and necessary mocks. * * @param launchFlags The intent flags to launch activity. - * @param mockGetLaunchStack Whether to mock {@link ActivityStackSupervisor#getLaunchStack} for + * @param mockGetLaunchStack Whether to mock {@link RootActivityContainer#getLaunchStack} for * always launching to the testing stack. Set to false when allowing * the activity can be launched to any stack that is decided by real * implementation. @@ -323,14 +323,14 @@ public class ActivityStarterTests extends ActivityTestsBase { private ActivityStarter prepareStarter(@Intent.Flags int launchFlags, boolean mockGetLaunchStack) { // always allow test to start activity. - doReturn(true).when(mService.mStackSupervisor).checkStartAnyActivityPermission( + doReturn(true).when(mSupervisor).checkStartAnyActivityPermission( any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), anyBoolean(), anyBoolean(), any(), any(), any()); // instrument the stack and task used. - final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( + final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TaskRecord task = new TaskBuilder(mService.mStackSupervisor) + final TaskRecord task = new TaskBuilder(mSupervisor) .setCreateStack(false) .build(); @@ -343,9 +343,9 @@ public class ActivityStarterTests extends ActivityTestsBase { if (mockGetLaunchStack) { // Direct starter to use spy stack. - doReturn(stack).when(mService.mStackSupervisor) + doReturn(stack).when(mRootActivityContainer) .getLaunchStack(any(), any(), any(), anyBoolean()); - doReturn(stack).when(mService.mStackSupervisor) + doReturn(stack).when(mRootActivityContainer) .getLaunchStack(any(), any(), any(), anyBoolean(), any()); } @@ -441,7 +441,7 @@ public class ActivityStarterTests extends ActivityTestsBase { final ActivityStack focusStack = focusActivity.getStack(); focusStack.moveToFront("testSplitScreenDeliverToTop"); - doReturn(reusableActivity).when(mService.mStackSupervisor).findTaskLocked(any(), anyInt()); + doReturn(reusableActivity).when(mRootActivityContainer).findTask(any(), anyInt()); final int result = starter.setReason("testSplitScreenDeliverToTop").execute(); @@ -473,7 +473,7 @@ public class ActivityStarterTests extends ActivityTestsBase { // Enter split-screen. Primary stack should have focus. focusActivity.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - doReturn(reusableActivity).when(mService.mStackSupervisor).findTaskLocked(any(), anyInt()); + doReturn(reusableActivity).when(mRootActivityContainer).findTask(any(), anyInt()); final int result = starter.setReason("testSplitScreenMoveToFront").execute(); @@ -486,7 +486,7 @@ public class ActivityStarterTests extends ActivityTestsBase { */ @Test public void testTaskModeViolation() { - final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay(); + final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); ((TestActivityDisplay) display).removeAllTasks(); assertNoTasks(display); @@ -562,7 +562,7 @@ public class ActivityStarterTests extends ActivityTestsBase { // Create a secondary display at bottom. final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay()); - mSupervisor.addChild(secondaryDisplay, POSITION_BOTTOM); + mRootActivityContainer.addChild(secondaryDisplay, POSITION_BOTTOM); final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -600,7 +600,7 @@ public class ActivityStarterTests extends ActivityTestsBase { // Create a secondary display with an activity. final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay()); - mSupervisor.addChild(secondaryDisplay, POSITION_TOP); + mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP); final ActivityRecord singleTaskActivity = createSingleTaskActivityOn( secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index caabdbd5640d..4fc73bc201b3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -35,6 +35,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; @@ -66,6 +67,8 @@ import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.ServiceThread; import com.android.server.am.ActivityManagerService; +import com.android.server.am.PendingIntentController; +import com.android.server.firewall.IntentFirewall; import com.android.server.uri.UriGrantsManagerInternal; import org.junit.After; @@ -91,6 +94,7 @@ class ActivityTestsBase { final TestInjector mTestInjector = new TestInjector(); ActivityTaskManagerService mService; + RootActivityContainer mRootActivityContainer; ActivityStackSupervisor mSupervisor; // Default package name @@ -115,27 +119,14 @@ class ActivityTestsBase { } ActivityTaskManagerService createActivityTaskManagerService() { - final TestActivityTaskManagerService atm = - spy(new TestActivityTaskManagerService(mContext)); - setupActivityManagerService(atm); - return atm; - } - - void setupActivityTaskManagerService() { - mService = createActivityTaskManagerService(); + mService = new TestActivityTaskManagerService(mContext); mSupervisor = mService.mStackSupervisor; + mRootActivityContainer = mService.mRootActivityContainer; + return mService; } - ActivityManagerService createActivityManagerService() { - final TestActivityTaskManagerService atm = - spy(new TestActivityTaskManagerService(mContext)); - return setupActivityManagerService(atm); - } - - ActivityManagerService setupActivityManagerService(TestActivityTaskManagerService atm) { - final TestActivityManagerService am = spy(new TestActivityManagerService(mTestInjector)); - setupActivityManagerService(am, atm); - return am; + void setupActivityTaskManagerService() { + createActivityTaskManagerService(); } /** Creates a {@link TestActivityDisplay}. */ @@ -150,36 +141,10 @@ class ActivityTestsBase { /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */ TestActivityDisplay addNewActivityDisplayAt(int position) { final TestActivityDisplay display = createNewActivityDisplay(); - mSupervisor.addChild(display, position); + mRootActivityContainer.addChild(display, position); return display; } - void setupActivityManagerService( - TestActivityManagerService am, TestActivityTaskManagerService atm) { - atm.setActivityManagerService(am.mIntentFirewall, am.mPendingIntentController); - atm.mAmInternal = am.getLocalService(); - am.mAtmInternal = atm.getLocalService(); - // Makes sure the supervisor is using with the spy object. - atm.mStackSupervisor.setService(atm); - doReturn(mock(IPackageManager.class)).when(am).getPackageManager(); - doReturn(mock(IPackageManager.class)).when(atm).getPackageManager(); - PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class); - doReturn(mockPackageManager).when(am).getPackageManagerInternalLocked(); - doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt()); - doNothing().when(am).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt()); - am.mActivityTaskManager = atm; - am.mWindowManager = prepareMockWindowManager(); - atm.setWindowManager(am.mWindowManager); - - // Put a home stack on the default display, so that we'll always have something focusable. - final TestActivityStackSupervisor supervisor = - (TestActivityStackSupervisor) atm.mStackSupervisor; - supervisor.mDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); - final TaskRecord task = new TaskBuilder(atm.mStackSupervisor) - .setStack(supervisor.getDefaultDisplay().getHomeStack()).build(); - new ActivityBuilder(atm).setTask(task).build(); - } - /** * Builder for creating new activities. */ @@ -354,7 +319,7 @@ class ActivityTestsBase { TaskRecord build() { if (mStack == null && mCreateStack) { - mStack = mSupervisor.getDefaultDisplay().createStack( + mStack = mSupervisor.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); } @@ -405,23 +370,71 @@ class ActivityTestsBase { } } - protected static class TestActivityTaskManagerService extends ActivityTaskManagerService { - private LockTaskController mLockTaskController; - private ActivityTaskManagerInternal mInternal; + protected class TestActivityTaskManagerService extends ActivityTaskManagerService { private PackageManagerInternal mPmInternal; // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS. // We keep the reference in order to prevent creating it twice. - private ActivityStackSupervisor mTestStackSupervisor; + ActivityStackSupervisor mTestStackSupervisor; + + ActivityDisplay mDefaultDisplay; TestActivityTaskManagerService(Context context) { super(context); + spyOn(this); + + mUgmInternal = mock(UriGrantsManagerInternal.class); + mSupportsMultiWindow = true; mSupportsMultiDisplay = true; mSupportsSplitScreenMultiWindow = true; mSupportsFreeformWindowManagement = true; mSupportsPictureInPicture = true; - mUgmInternal = mock(UriGrantsManagerInternal.class); + + final TestActivityManagerService am = + new TestActivityManagerService(mTestInjector, this); + + spyOn(getLifecycleManager()); + spyOn(getLockTaskController()); + doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); + } + + void setActivityManagerService(IntentFirewall intentFirewall, + PendingIntentController intentController, ActivityManagerInternal amInternal, + WindowManagerService wm) { + mAmInternal = amInternal; + setActivityManagerService(intentFirewall, intentController); + initRootActivityContainerMocks(wm); + setWindowManager(wm); + } + + void initRootActivityContainerMocks(WindowManagerService wm) { + spyOn(mRootActivityContainer); + mRootActivityContainer.setWindowContainerController( + mock(RootWindowContainerController.class)); + mRootActivityContainer.mWindowManager = wm; + mRootActivityContainer.mDisplayManager = + (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); + doNothing().when(mRootActivityContainer).setWindowManager(any()); + // Invoked during {@link ActivityStack} creation. + doNothing().when(mRootActivityContainer).updateUIDsPresentOnDisplay(); + // Always keep things awake. + doReturn(true).when(mRootActivityContainer).hasAwakeDisplay(); + // Called when moving activity to pinned stack. + doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(), + anyBoolean()); + + // Create a default display and put a home stack on it so that we'll always have + // something focusable. + mDefaultDisplay = TestActivityDisplay.create(mStackSupervisor, DEFAULT_DISPLAY); + spyOn(mDefaultDisplay); + mRootActivityContainer.addChild(mDefaultDisplay, ActivityDisplay.POSITION_TOP); + mDefaultDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + final TaskRecord task = new TaskBuilder(mStackSupervisor) + .setStack(mDefaultDisplay.getHomeStack()).build(); + new ActivityBuilder(this).setTask(task).build(); + + doReturn(mDefaultDisplay).when(mRootActivityContainer).getDefaultDisplay(); } @Override @@ -430,54 +443,17 @@ class ActivityTestsBase { } @Override - public LockTaskController getLockTaskController() { - if (mLockTaskController == null) { - mLockTaskController = spy(super.getLockTaskController()); - } - - return mLockTaskController; - } - - @Override void updateUsageStats(ActivityRecord component, boolean resumed) { } @Override - protected final ActivityStackSupervisor createStackSupervisor() { + protected ActivityStackSupervisor createStackSupervisor() { if (mTestStackSupervisor == null) { - final ActivityStackSupervisor supervisor = spy(createTestSupervisor()); - final KeyguardController keyguardController = mock(KeyguardController.class); - - // Invoked during {@link ActivityStack} creation. - doNothing().when(supervisor).updateUIDsPresentOnDisplay(); - // Always keep things awake. - doReturn(true).when(supervisor).hasAwakeDisplay(); - // Called when moving activity to pinned stack. - doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), - anyBoolean()); - // Do not schedule idle timeouts - doNothing().when(supervisor).scheduleIdleTimeoutLocked(any()); - // unit test version does not handle launch wake lock - doNothing().when(supervisor).acquireLaunchWakelock(); - doReturn(keyguardController).when(supervisor).getKeyguardController(); - - supervisor.initialize(); - mTestStackSupervisor = supervisor; + mTestStackSupervisor = new TestActivityStackSupervisor(this, mH.getLooper()); } return mTestStackSupervisor; } - protected ActivityStackSupervisor createTestSupervisor() { - return new TestActivityStackSupervisor(this, mH.getLooper()); - } - - ActivityTaskManagerInternal getLocalService() { - if (mInternal == null) { - mInternal = new ActivityTaskManagerService.LocalService(); - } - return mInternal; - } - @Override PackageManagerInternal getPackageManagerInternalLocked() { if (mPmInternal == null) { @@ -524,24 +500,31 @@ class ActivityTestsBase { } } + // TODO: Replace this with a mock object since we are no longer in AMS package. /** * An {@link ActivityManagerService} subclass which provides a test * {@link ActivityStackSupervisor}. */ - static class TestActivityManagerService extends ActivityManagerService { - - private ActivityManagerInternal mInternal; + class TestActivityManagerService extends ActivityManagerService { - TestActivityManagerService(TestInjector testInjector) { + TestActivityManagerService(TestInjector testInjector, TestActivityTaskManagerService atm) { super(testInjector, testInjector.mHandlerThread); + spyOn(this); + + mWindowManager = prepareMockWindowManager(); mUgmInternal = mock(UriGrantsManagerInternal.class); - } - ActivityManagerInternal getLocalService() { - if (mInternal == null) { - mInternal = new LocalService(); - } - return mInternal; + atm.setActivityManagerService(mIntentFirewall, mPendingIntentController, + new LocalService(), mWindowManager); + + mActivityTaskManager = atm; + mAtmInternal = atm.mInternal; + + doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); + PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class); + doReturn(mockPackageManager).when(this).getPackageManagerInternalLocked(); + doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt()); + doNothing().when(this).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt()); } } @@ -549,24 +532,22 @@ class ActivityTestsBase { * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on * setup not available in the test environment. Also specifies an injector for */ - protected static class TestActivityStackSupervisor extends ActivityStackSupervisor { - private ActivityDisplay mDisplay; + protected class TestActivityStackSupervisor extends ActivityStackSupervisor { private KeyguardController mKeyguardController; - public TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) { + TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) { super(service, looper); - mDisplayManager = - (DisplayManager) mService.mContext.getSystemService(Context.DISPLAY_SERVICE); + spyOn(this); mWindowManager = prepareMockWindowManager(); mKeyguardController = mock(KeyguardController.class); - setWindowContainerController(mock(RootWindowContainerController.class)); - } - @Override - public void initialize() { - super.initialize(); - mDisplay = spy(TestActivityDisplay.create(this, DEFAULT_DISPLAY)); - addChild(mDisplay, ActivityDisplay.POSITION_TOP); + // Do not schedule idle timeouts + doNothing().when(this).scheduleIdleTimeoutLocked(any()); + // unit test version does not handle launch wake lock + doNothing().when(this).acquireLaunchWakelock(); + doReturn(mKeyguardController).when(this).getKeyguardController(); + + initialize(); } @Override @@ -575,11 +556,6 @@ class ActivityTestsBase { } @Override - ActivityDisplay getDefaultDisplay() { - return mDisplay; - } - - @Override void setWindowManager(WindowManagerService wm) { mWindowManager = wm; } @@ -596,7 +572,7 @@ class ActivityTestsBase { DisplayInfo info) { if (displayId == DEFAULT_DISPLAY) { return new TestActivityDisplay(supervisor, - supervisor.mDisplayManager.getDisplay(displayId)); + supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId)); } final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, info, DEFAULT_DISPLAY_ADJUSTMENTS); @@ -604,7 +580,7 @@ class ActivityTestsBase { } TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) { - super(supervisor, display); + super(supervisor.mService.mRootActivityContainer, display); // Normally this comes from display-properties as exposed by WM. Without that, just // hard-code to FULLSCREEN for tests. setWindowingMode(WINDOWING_MODE_FULLSCREEN); @@ -615,7 +591,7 @@ class ActivityTestsBase { @Override <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop) { - return new StackBuilder(mSupervisor).setDisplay(this) + return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this) .setWindowingMode(windowingMode).setActivityType(activityType) .setStackId(stackId).setOnTop(onTop).setCreateActivity(false).build(); } @@ -757,8 +733,8 @@ class ActivityTestsBase { } } - protected static class StackBuilder { - private final ActivityStackSupervisor mSupervisor; + static class StackBuilder { + private final RootActivityContainer mRootActivityContainer; private ActivityDisplay mDisplay; private int mStackId = -1; private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; @@ -766,9 +742,9 @@ class ActivityTestsBase { private boolean mOnTop = true; private boolean mCreateActivity = true; - StackBuilder(ActivityStackSupervisor supervisor) { - mSupervisor = supervisor; - mDisplay = mSupervisor.getDefaultDisplay(); + StackBuilder(RootActivityContainer root) { + mRootActivityContainer = root; + mDisplay = mRootActivityContainer.getDefaultDisplay(); } StackBuilder setWindowingMode(int windowingMode) { @@ -805,7 +781,8 @@ class ActivityTestsBase { <T extends ActivityStack> T build() { final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId(); if (mWindowingMode == WINDOWING_MODE_PINNED) { - return (T) new PinnedActivityStack(mDisplay, stackId, mSupervisor, mOnTop) { + return (T) new PinnedActivityStack(mDisplay, stackId, + mRootActivityContainer.mStackSupervisor, mOnTop) { @Override Rect getDefaultPictureInPictureBounds(float aspectRatio) { return new Rect(50, 50, 100, 100); @@ -821,7 +798,8 @@ class ActivityTestsBase { } }; } else { - return (T) new TestActivityStack(mDisplay, stackId, mSupervisor, mWindowingMode, + return (T) new TestActivityStack(mDisplay, stackId, + mRootActivityContainer.mStackSupervisor, mWindowingMode, mActivityType, mOnTop, mCreateActivity); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index dc22bc1d5820..2c3c66be6248 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -110,8 +110,9 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { final DisplayInfo info = new DisplayInfo(); info.uniqueId = mDisplayUniqueId; mTestDisplay = createNewActivityDisplay(info); - mSupervisor.addChild(mTestDisplay, ActivityDisplay.POSITION_TOP); - when(mSupervisor.getActivityDisplay(eq(mDisplayUniqueId))).thenReturn(mTestDisplay); + mRootActivityContainer.addChild(mTestDisplay, ActivityDisplay.POSITION_TOP); + when(mRootActivityContainer.getActivityDisplay(eq(mDisplayUniqueId))) + .thenReturn(mTestDisplay); ActivityStack stack = mTestDisplay.createStack(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); @@ -184,7 +185,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { public void testReturnsEmptyDisplayIfDisplayIsNotFound() { mTarget.saveTask(mTestTask); - when(mSupervisor.getActivityDisplay(eq(mDisplayUniqueId))).thenReturn(null); + when(mRootActivityContainer.getActivityDisplay(eq(mDisplayUniqueId))).thenReturn(null); mTarget.getLaunchParams(mTestTask, null, mResult); diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index 33e6063bbb97..6259fa669ce8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -104,6 +104,7 @@ public class LockTaskControllerTest { new DexmakerShareClassLoaderRule(); @Mock private ActivityStackSupervisor mSupervisor; + @Mock private RootActivityContainer mRootActivityContainer; @Mock private IDevicePolicyManager mDevicePolicyManager; @Mock private IStatusBarService mStatusBarService; @Mock private WindowManagerService mWindowManager; @@ -129,6 +130,7 @@ public class LockTaskControllerTest { } mSupervisor.mRecentTasks = mRecentTasks; + mSupervisor.mRootActivityContainer = mRootActivityContainer; mLockTaskController = new LockTaskController(mContext, mSupervisor, new ImmediatelyExecuteHandler()); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 2f3f6984e390..3c7b4b1248b5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -110,14 +110,13 @@ public class RecentTasksTest extends ActivityTestsBase { @Before public void setUp() throws Exception { mTaskPersister = new TestTaskPersister(mContext.getFilesDir()); - mTestService = spy(new MyTestActivityTaskManagerService(mContext)); - final TestActivityManagerService am = spy(new MyTestActivityManagerService()); - setupActivityManagerService(am, mTestService); + mTestService = new MyTestActivityTaskManagerService(mContext); mRecentTasks = (TestRecentTasks) mTestService.getRecentTasks(); mRecentTasks.loadParametersFromResources(mContext.getResources()); - mHomeStack = mTestService.mStackSupervisor.getDefaultDisplay().getOrCreateStack( + mRunningTasks = (TestRunningTasks) mTestService.mStackSupervisor.mRunningTasks; + mHomeStack = mTestService.mRootActivityContainer.getDefaultDisplay().getOrCreateStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - mStack = mTestService.mStackSupervisor.getDefaultDisplay().createStack( + mStack = mTestService.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mCallbacksRecorder = new CallbacksRecorder(); mRecentTasks.registerCallback(mCallbacksRecorder); @@ -868,20 +867,20 @@ public class RecentTasksTest extends ActivityTestsBase { } @Override - protected ActivityStackSupervisor createTestSupervisor() { - return new MyTestActivityStackSupervisor(this, mH.getLooper()); - } - - } - - private class MyTestActivityManagerService extends TestActivityManagerService { - MyTestActivityManagerService() { - super(mTestInjector); + protected ActivityStackSupervisor createStackSupervisor() { + if (mTestStackSupervisor == null) { + mTestStackSupervisor = new MyTestActivityStackSupervisor(this, mH.getLooper()); + } + return mTestStackSupervisor; } @Override - public boolean isUserRunning(int userId, int flags) { - return true; + void initRootActivityContainerMocks(WindowManagerService wm) { + super.initRootActivityContainerMocks(wm); + mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY); + mOtherDisplay = TestActivityDisplay.create(mTestStackSupervisor, DEFAULT_DISPLAY + 1); + mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP); + mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP); } } @@ -891,15 +890,6 @@ public class RecentTasksTest extends ActivityTestsBase { } @Override - public void initialize() { - super.initialize(); - mDisplay = getActivityDisplay(DEFAULT_DISPLAY); - mOtherDisplay = TestActivityDisplay.create(this, DEFAULT_DISPLAY + 1); - addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP); - addChild(mDisplay, ActivityDisplay.POSITION_TOP); - } - - @Override RunningTasks createRunningTasks() { mRunningTasks = new TestRunningTasks(); return mRunningTasks; diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 50190e7c623f..0ff67d7b1f83 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -25,6 +25,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; @@ -50,61 +51,50 @@ import org.junit.Test; public class RecentsAnimationTest extends ActivityTestsBase { private Context mContext = InstrumentationRegistry.getContext(); - private TestActivityTaskManagerService mTestService; private ComponentName mRecentsComponent; @Before public void setUp() throws Exception { mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity"); - mTestService = spy(new MyTestActivityTaskManagerService(mContext)); - setupActivityManagerService(mTestService); + mService = new TestActivityTaskManagerService(mContext); + + final RecentTasks recentTasks = mService.getRecentTasks(); + spyOn(recentTasks); + mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity"); + doReturn(mRecentsComponent).when(recentTasks).getRecentsComponent(); } @Test public void testCancelAnimationOnStackOrderChange() { ActivityStack fullscreenStack = - mTestService.mStackSupervisor.getDefaultDisplay().createStack( + mService.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - ActivityStack recentsStack = mTestService.mStackSupervisor.getDefaultDisplay().createStack( + ActivityStack recentsStack = mService.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); - ActivityRecord recentsActivity = new ActivityBuilder(mTestService) + ActivityRecord recentsActivity = new ActivityBuilder(mService) .setComponent(mRecentsComponent) .setCreateTask(true) .setStack(recentsStack) .build(); ActivityStack fullscreenStack2 = - mTestService.mStackSupervisor.getDefaultDisplay().createStack( + mService.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - ActivityRecord fsActivity = new ActivityBuilder(mTestService) + ActivityRecord fsActivity = new ActivityBuilder(mService) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) .setCreateTask(true) .setStack(fullscreenStack2) .build(); - doReturn(true).when(mTestService.mWindowManager).canStartRecentsAnimation(); + doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation(); // Start the recents animation Intent recentsIntent = new Intent(); recentsIntent.setComponent(mRecentsComponent); - mTestService.startRecentsActivity(recentsIntent, null, mock(IRecentsAnimationRunner.class)); + mService.startRecentsActivity(recentsIntent, null, mock(IRecentsAnimationRunner.class)); fullscreenStack.moveToFront("Activity start"); // Ensure that the recents animation was canceled - verify(mTestService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously( + verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously( eq(REORDER_KEEP_IN_PLACE), any()); } - - private class MyTestActivityTaskManagerService extends TestActivityTaskManagerService { - MyTestActivityTaskManagerService(Context context) { - super(context); - } - - @Override - protected RecentTasks createRecentTasks() { - RecentTasks recents = mock(RecentTasks.class); - doReturn(mRecentsComponent).when(recents).getRecentsComponent(); - System.out.println(mRecentsComponent); - return recents; - } - } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java new file mode 100644 index 000000000000..631de99dc3ad --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import static android.app.ActivityManager.START_DELIVERED_TO_TOP; +import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; +import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.ActivityDisplay.POSITION_TOP; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; +import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.ArgumentMatchers.eq; + +import android.app.ActivityOptions; +import android.app.WaitResult; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.graphics.Rect; +import android.os.Build; +import android.platform.test.annotations.Presubmit; +import androidx.test.filters.MediumTest; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; + +/** + * Tests for the {@link ActivityStackSupervisor} class. + * + * Build/Install/Run: + * atest WmTests:ActivityStackSupervisorTests + */ +@MediumTest +@Presubmit +public class RootActivityContainerTests extends ActivityTestsBase { + private ActivityStack mFullscreenStack; + + @Before + public void setUp() throws Exception { + setupActivityTaskManagerService(); + mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + } + + /** + * This test ensures that we do not try to restore a task based off an invalid task id. We + * should expect {@code null} to be returned in this case. + */ + @Test + public void testRestoringInvalidTask() { + ((TestActivityDisplay) mRootActivityContainer.getDefaultDisplay()).removeAllTasks(); + TaskRecord task = mRootActivityContainer.anyTaskForId(0 /*taskId*/, + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */); + assertNull(task); + } + + /** + * This test ensures that an existing task in the pinned stack is moved to the fullscreen + * activity stack when a new task is added. + */ + @Test + public void testReplacingTaskInPinnedStack() { + final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(mFullscreenStack).build(); + final TaskRecord firstTask = firstActivity.getTask(); + + final ActivityRecord secondActivity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(mFullscreenStack).build(); + final TaskRecord secondTask = secondActivity.getTask(); + + mFullscreenStack.moveToFront("testReplacingTaskInPinnedStack"); + + // Ensure full screen stack has both tasks. + ensureStackPlacement(mFullscreenStack, firstTask, secondTask); + + // Move first activity to pinned stack. + final Rect sourceBounds = new Rect(); + mRootActivityContainer.moveActivityToPinnedStack(firstActivity, sourceBounds, + 0f /*aspectRatio*/, "initialMove"); + + final ActivityDisplay display = mFullscreenStack.getDisplay(); + ActivityStack pinnedStack = display.getPinnedStack(); + // Ensure a task has moved over. + ensureStackPlacement(pinnedStack, firstTask); + ensureStackPlacement(mFullscreenStack, secondTask); + + // Move second activity to pinned stack. + mRootActivityContainer.moveActivityToPinnedStack(secondActivity, sourceBounds, + 0f /*aspectRatio*/, "secondMove"); + + // Need to get stacks again as a new instance might have been created. + pinnedStack = display.getPinnedStack(); + mFullscreenStack = display.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); + // Ensure stacks have swapped tasks. + ensureStackPlacement(pinnedStack, secondTask); + ensureStackPlacement(mFullscreenStack, firstTask); + } + + private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) { + final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); + assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); + + if (tasks == null) { + return; + } + + for (TaskRecord task : tasks) { + assertTrue(stackTasks.contains(task)); + } + } + + @Test + public void testApplySleepTokens() { + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); + final KeyguardController keyguard = mSupervisor.getKeyguardController(); + final ActivityStack stack = mock(ActivityStack.class); + display.addChild(stack, 0 /* position */); + + // Make sure we wake and resume in the case the display is turning on and the keyguard is + // not showing. + verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/, + false /* displayShouldSleep */, true /* isFocusedStack */, + false /* keyguardShowing */, true /* expectWakeFromSleep */, + true /* expectResumeTopActivity */); + + // Make sure we wake and don't resume when the display is turning on and the keyguard is + // showing. + verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/, + false /* displayShouldSleep */, true /* isFocusedStack */, + true /* keyguardShowing */, true /* expectWakeFromSleep */, + false /* expectResumeTopActivity */); + + // Make sure we wake and don't resume when the display is turning on and the keyguard is + // not showing as unfocused. + verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/, + false /* displayShouldSleep */, false /* isFocusedStack */, + false /* keyguardShowing */, true /* expectWakeFromSleep */, + false /* expectResumeTopActivity */); + + // Should not do anything if the display state hasn't changed. + verifySleepTokenBehavior(display, keyguard, stack, false /*displaySleeping*/, + false /* displayShouldSleep */, true /* isFocusedStack */, + false /* keyguardShowing */, false /* expectWakeFromSleep */, + false /* expectResumeTopActivity */); + } + + private void verifySleepTokenBehavior(ActivityDisplay display, KeyguardController keyguard, + ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep, + boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep, + boolean expectResumeTopActivity) { + reset(stack); + + doReturn(displayShouldSleep).when(display).shouldSleep(); + doReturn(displaySleeping).when(display).isSleeping(); + doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt()); + + doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay(); + doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack(); + mRootActivityContainer.applySleepTokens(true); + verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked(); + verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked( + null /* target */, null /* targetOptions */); + } + + /** + * Verifies that removal of activity with task and stack is done correctly. + */ + @Test + public void testRemovingStackOnAppCrash() { + final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay(); + final int originalStackCount = defaultDisplay.getChildCount(); + final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(stack).build(); + + assertEquals(originalStackCount + 1, defaultDisplay.getChildCount()); + + // Let's pretend that the app has crashed. + firstActivity.app.setThread(null); + mRootActivityContainer.finishTopCrashedActivities(firstActivity.app, "test"); + + // Verify that the stack was removed. + assertEquals(originalStackCount, defaultDisplay.getChildCount()); + } + + @Test + public void testFocusability() { + final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(stack).build(); + + // Under split screen primary we should be focusable when not minimized + mRootActivityContainer.setDockedStackMinimized(false); + assertTrue(stack.isFocusable()); + assertTrue(activity.isFocusable()); + + // Under split screen primary we should not be focusable when minimized + mRootActivityContainer.setDockedStackMinimized(true); + assertFalse(stack.isFocusable()); + assertFalse(activity.isFocusable()); + + final ActivityStack pinnedStack = mRootActivityContainer.getDefaultDisplay().createStack( + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(pinnedStack).build(); + + // We should not be focusable when in pinned mode + assertFalse(pinnedStack.isFocusable()); + assertFalse(pinnedActivity.isFocusable()); + + // Add flag forcing focusability. + pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE; + + // We should not be focusable when in pinned mode + assertTrue(pinnedStack.isFocusable()); + assertTrue(pinnedActivity.isFocusable()); + + // Without the overridding activity, stack should not be focusable. + pinnedStack.removeTask(pinnedActivity.getTask(), "testFocusability", + REMOVE_TASK_MODE_DESTROYING); + assertFalse(pinnedStack.isFocusable()); + } + + /** + * Verify that split-screen primary stack will be chosen if activity is launched that targets + * split-screen secondary, but a matching existing instance is found on top of split-screen + * primary stack. + */ + @Test + public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() { + // Create primary split-screen stack with a task and an activity. + final ActivityStack primaryStack = mRootActivityContainer.getDefaultDisplay() + .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, + true /* onTop */); + final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); + final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build(); + + // Find a launch stack for the top activity in split-screen primary, while requesting + // split-screen secondary. + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); + final ActivityStack result = + mRootActivityContainer.getLaunchStack(r, options, task, true /* onTop */); + + // Assert that the primary stack is returned. + assertEquals(primaryStack, result); + } + + /** + * Verify split-screen primary stack & task can resized by + * {@link android.app.IActivityTaskManager#resizeDockedStack} as expect. + */ + @Test + public void testResizeDockedStackForSplitScreenPrimary() { + final Rect taskSize = new Rect(0, 0, 600, 600); + final Rect stackSize = new Rect(0, 0, 300, 300); + + // Create primary split-screen stack with a task. + final ActivityStack primaryStack = mRootActivityContainer.getDefaultDisplay() + .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, + true /* onTop */); + final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); + + // Resize dock stack. + mService.resizeDockedStack(stackSize, taskSize, null, null, null); + + // Verify dock stack & its task bounds if is equal as resized result. + assertEquals(primaryStack.getBounds(), stackSize); + assertEquals(task.getBounds(), taskSize); + } + + /** + * Verify that home stack would be moved to front when the top activity is Recents. + */ + @Test + public void testFindTaskToMoveToFrontWhenRecentsOnTop() { + // Create stack/task on default display. + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); + final TestActivityStack targetStack = + new StackBuilder(mRootActivityContainer).setOnTop(false).build(); + final TaskRecord targetTask = targetStack.getChildAt(0); + + // Create Recents on top of the display. + final ActivityStack stack = new StackBuilder(mRootActivityContainer).setActivityType( + ACTIVITY_TYPE_RECENTS).build(); + + final String reason = "findTaskToMoveToFront"; + mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, + false); + + verify(display).moveHomeStackToFront(contains(reason)); + } + + /** + * Verify that home stack won't be moved to front if the top activity on other display is + * Recents. + */ + @Test + public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() { + // Create stack/task on default display. + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); + final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, false /* onTop */); + final TaskRecord targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build(); + + // Create Recents on secondary display. + final TestActivityDisplay secondDisplay = addNewActivityDisplayAt( + ActivityDisplay.POSITION_TOP); + final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_RECENTS, true /* onTop */); + final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build(); + new ActivityBuilder(mService).setTask(task).build(); + + final String reason = "findTaskToMoveToFront"; + mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, + false); + + verify(display, never()).moveHomeStackToFront(contains(reason)); + } + + /** + * Verify if a stack is not at the topmost position, it should be able to resume its activity if + * the stack is the top focused. + */ + @Test + public void testResumeActivityWhenNonTopmostStackIsTopFocused() { + // Create a stack at bottom. + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); + final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, false /* onTop */)); + final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); + final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); + display.positionChildAtBottom(targetStack); + + // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it + // is the current top focused stack. + assertFalse(targetStack.isTopStackOnDisplay()); + doReturn(targetStack).when(mRootActivityContainer).getTopDisplayFocusedStack(); + + // Use the stack as target to resume. + mRootActivityContainer.resumeFocusedStacksTopActivities( + targetStack, activity, null /* targetOptions */); + + // Verify the target stack should resume its activity. + verify(targetStack, times(1)).resumeTopActivityUncheckedLocked( + eq(activity), eq(null /* targetOptions */)); + } + + /** + * Tests home activities that targeted sdk before Q cannot start on secondary display. + */ + @Test + public void testStartHomeTargetSdkBeforeQ() throws Exception { + final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay()); + mRootActivityContainer.addChild(secondDisplay, POSITION_TOP); + doReturn(true).when(secondDisplay).supportsSystemDecorations(); + + final ActivityInfo info = new ActivityInfo(); + info.launchMode = LAUNCH_MULTIPLE; + info.applicationInfo = new ApplicationInfo(); + info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; + assertTrue(mRootActivityContainer.canStartHomeOnDisplay(info, secondDisplay.mDisplayId, + false /* allowInstrumenting */)); + + info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.P; + assertFalse(mRootActivityContainer.canStartHomeOnDisplay(info, secondDisplay.mDisplayId, + false /* allowInstrumenting */)); + } + + /** + * Tests that home activities can be started on the displays that supports system decorations. + */ + @Test + public void testStartHomeOnAllDisplays() { + // Create secondary displays. + final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay()); + mRootActivityContainer.addChild(secondDisplay, POSITION_TOP); + doReturn(true).when(secondDisplay).supportsSystemDecorations(); + + // Create mock tasks and other necessary mocks. + TaskBuilder taskBuilder = new TaskBuilder(mService.mStackSupervisor).setCreateStack(false); + final TaskRecord.TaskRecordFactory factory = mock(TaskRecord.TaskRecordFactory.class); + TaskRecord.setTaskRecordFactory(factory); + doAnswer(i -> taskBuilder.build()).when(factory) + .create(any(), anyInt(), any(), any(), any(), any()); + doReturn(true).when(mRootActivityContainer) + .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean()); + doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay( + any(), anyInt(), anyBoolean()); + + mRootActivityContainer.startHomeOnAllDisplays(0, "testStartHome"); + + assertTrue(mRootActivityContainer.getDefaultDisplay().getTopStack().isActivityTypeHome()); + assertNotNull(secondDisplay.getTopStack()); + assertTrue(secondDisplay.getTopStack().isActivityTypeHome()); + } + + /** + * Tests that home activities won't be started before booting when display added. + */ + @Test + public void testNotStartHomeBeforeBoot() { + final int displayId = 1; + final boolean isBooting = mService.mAmInternal.isBooting(); + final boolean isBooted = mService.mAmInternal.isBooted(); + try { + mService.mAmInternal.setBooting(false); + mService.mAmInternal.setBooted(false); + mRootActivityContainer.onDisplayAdded(displayId); + verify(mRootActivityContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt()); + } finally { + mService.mAmInternal.setBooting(isBooting); + mService.mAmInternal.setBooted(isBooted); + } + } + + /** + * Tests whether home can be started if being instrumented. + */ + @Test + public void testCanStartHomeWhenInstrumented() { + final ActivityInfo info = new ActivityInfo(); + info.applicationInfo = new ApplicationInfo(); + final WindowProcessController app = mock(WindowProcessController.class); + doReturn(app).when(mService).getProcessController(any(), anyInt()); + + // Can not start home if we don't want to start home while home is being instrumented. + doReturn(true).when(app).isInstrumenting(); + assertFalse(mRootActivityContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, + false /* allowInstrumenting*/)); + + // Can start home for other cases. + assertTrue(mRootActivityContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, + true /* allowInstrumenting*/)); + + doReturn(false).when(app).isInstrumenting(); + assertTrue(mRootActivityContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, + false /* allowInstrumenting*/)); + assertTrue(mRootActivityContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY, + true /* allowInstrumenting*/)); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index 0e1624ebef63..a8b6dc373cbf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -63,7 +63,7 @@ public class RunningTasksTest extends ActivityTestsBase { final int numStacks = 2; for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) { final ActivityStack stack = - new StackBuilder(mSupervisor).setCreateActivity(false).build(); + new StackBuilder(mRootActivityContainer).setCreateActivity(false).build(); display.addChild(stack, POSITION_BOTTOM); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 6638eeb8af19..bd8cd1f37f5e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -888,10 +888,10 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { @Test public void testAdjustBoundsToFitNewDisplay_LargerThanDisplay_RTL() { - final Configuration overrideConfig = mSupervisor.getOverrideConfiguration(); + final Configuration overrideConfig = mRootActivityContainer.getOverrideConfiguration(); // Egyptian Arabic is a RTL language. overrideConfig.setLayoutDirection(new Locale("ar", "EG")); - mSupervisor.onOverrideConfigurationChanged(overrideConfig); + mRootActivityContainer.onOverrideConfigurationChanged(overrideConfig); final TestActivityDisplay freeformDisplay = createNewActivityDisplay( WINDOWING_MODE_FREEFORM); diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 152831f50770..4f573a475ae7 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -27,8 +27,6 @@ import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOU import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START; -import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START; -import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN; @@ -846,8 +844,6 @@ public class AppStandbyController { // Inform listeners if necessary if ((event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND || event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND - || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START - || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_STOP || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION || event.mEventType == UsageEvents.Event.USER_INTERACTION || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN @@ -900,10 +896,6 @@ public class AppStandbyController { switch (eventType) { case UsageEvents.Event.MOVE_TO_FOREGROUND: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND; case UsageEvents.Event.MOVE_TO_BACKGROUND: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND; - case UsageEvents.Event.FOREGROUND_SERVICE_START: - return REASON_SUB_USAGE_FOREGROUND_SERVICE_START; - case UsageEvents.Event.FOREGROUND_SERVICE_STOP: - return REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP; case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION; case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION; case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN; diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java index d94062002dcd..01e566cdd85f 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java +++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java @@ -20,6 +20,7 @@ import android.app.usage.UsageEvents; import android.app.usage.UsageStats; import android.content.res.Configuration; import android.util.ArrayMap; +import android.util.Log; import com.android.internal.util.XmlUtils; @@ -89,11 +90,23 @@ final class UsageStatsXmlV1 { // Apply the offset to the beginTime to find the absolute time. stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute( parser, LAST_TIME_ACTIVE_ATTR); - stats.mLastTimeForegroundServiceUsed = statsOut.beginTime + XmlUtils.readLongAttribute( - parser, LAST_TIME_SERVICE_USED_ATTR); + + try { + stats.mLastTimeForegroundServiceUsed = statsOut.beginTime + XmlUtils.readLongAttribute( + parser, LAST_TIME_SERVICE_USED_ATTR); + } catch (IOException e) { + Log.e(TAG, "Failed to parse mLastTimeForegroundServiceUsed", e); + } + stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR); - stats.mTotalTimeForegroundServiceUsed = XmlUtils.readLongAttribute(parser, + + try { + stats.mTotalTimeForegroundServiceUsed = XmlUtils.readLongAttribute(parser, TOTAL_TIME_SERVICE_USED_ATTR); + } catch (IOException e) { + Log.e(TAG, "Failed to parse mTotalTimeForegroundServiceUsed", e); + } + stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR); stats.mAppLaunchCount = XmlUtils.readIntAttribute(parser, APP_LAUNCH_COUNT_ATTR, 0); @@ -350,8 +363,17 @@ final class UsageStatsXmlV1 { } statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR); - statsOut.majorVersion = XmlUtils.readIntAttribute(parser, MAJOR_VERSION_ATTR); - statsOut.minorVersion = XmlUtils.readIntAttribute(parser, MINOR_VERSION_ATTR); + try { + statsOut.majorVersion = XmlUtils.readIntAttribute(parser, MAJOR_VERSION_ATTR); + } catch (IOException e) { + Log.e(TAG, "Failed to parse majorVersion", e); + } + + try { + statsOut.minorVersion = XmlUtils.readIntAttribute(parser, MINOR_VERSION_ATTR); + } catch (IOException e) { + Log.e(TAG, "Failed to parse minorVersion", e); + } int eventCode; int outerDepth = parser.getDepth(); diff --git a/telephony/java/android/telephony/MbmsGroupCallSession.java b/telephony/java/android/telephony/MbmsGroupCallSession.java index e3737976adf7..269cda13bd93 100644 --- a/telephony/java/android/telephony/MbmsGroupCallSession.java +++ b/telephony/java/android/telephony/MbmsGroupCallSession.java @@ -37,6 +37,7 @@ import android.telephony.mbms.vendor.IMbmsGroupCallService; import android.util.ArraySet; import android.util.Log; +import java.util.List; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; @@ -107,14 +108,14 @@ public class MbmsGroupCallSession implements AutoCloseable { * {@link MbmsGroupCallSession} that you received before calling this method again. * * @param context The {@link Context} to use. - * @param executor The executor on which you wish to execute callbacks. * @param subscriptionId The subscription ID to use. + * @param executor The executor on which you wish to execute callbacks. * @param callback A callback object on which you wish to receive results of asynchronous * operations. * @return An instance of {@link MbmsGroupCallSession}, or null if an error occurred. */ public static @Nullable MbmsGroupCallSession create(@NonNull Context context, - @NonNull Executor executor, int subscriptionId, + int subscriptionId, @NonNull Executor executor, final @NonNull MbmsGroupCallSessionCallback callback) { if (!sIsInitialized.compareAndSet(false, true)) { throw new IllegalStateException("Cannot create two instances of MbmsGroupCallSession"); @@ -138,11 +139,11 @@ public class MbmsGroupCallSession implements AutoCloseable { /** * Create a new {@link MbmsGroupCallSession} using the system default data subscription ID. - * See {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)}. + * See {@link #create(Context, int, Executor, MbmsGroupCallSessionCallback)}. */ public static MbmsGroupCallSession create(@NonNull Context context, @NonNull Executor executor, @NonNull MbmsGroupCallSessionCallback callback) { - return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback); + return create(context, SubscriptionManager.getDefaultSubscriptionId(), executor, callback); } /** @@ -153,7 +154,7 @@ public class MbmsGroupCallSession implements AutoCloseable { * instance of {@link MbmsGroupCallSessionCallback}, but callbacks that have already been * enqueued will still be delivered. * - * It is safe to call {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)} to + * It is safe to call {@link #create(Context, int, Executor, MbmsGroupCallSessionCallback)} to * obtain another instance of {@link MbmsGroupCallSession} immediately after this method * returns. * @@ -189,18 +190,19 @@ public class MbmsGroupCallSession implements AutoCloseable { * Asynchronous errors through the callback include any of the errors in * {@link MbmsErrors.GeneralErrors}. * - * @param executor The executor on which you wish to execute callbacks for this stream. * @param tmgi The TMGI, an identifier for the group call you want to join. - * @param saiArray An array of SAIs for the group call that should be negotiated separately with + * @param saiList A list of SAIs for the group call that should be negotiated separately with * the carrier. - * @param frequencyArray An array of frequencies for the group call that should be negotiated + * @param frequencyList A lost of frequencies for the group call that should be negotiated * separately with the carrier. + * @param executor The executor on which you wish to execute callbacks for this stream. * @param callback The callback that you want to receive information about the call on. * @return An instance of {@link GroupCall} through which the call can be controlled. * May be {@code null} if an error occurred. */ - public @Nullable GroupCall startGroupCall(@NonNull Executor executor, long tmgi, int[] saiArray, - int[] frequencyArray, @NonNull GroupCallCallback callback) { + public @Nullable GroupCall startGroupCall(long tmgi, @NonNull List<Integer> saiList, + @NonNull List<Integer> frequencyList, @NonNull Executor executor, + @NonNull GroupCallCallback callback) { IMbmsGroupCallService groupCallService = mService.get(); if (groupCallService == null) { throw new IllegalStateException("Middleware not yet bound"); @@ -215,7 +217,7 @@ public class MbmsGroupCallSession implements AutoCloseable { try { int returnCode = groupCallService.startGroupCall( - mSubscriptionId, tmgi, saiArray, frequencyArray, serviceCallback); + mSubscriptionId, tmgi, saiList, frequencyList, serviceCallback); if (returnCode == MbmsErrors.UNKNOWN) { // Unbind and throw an obvious error close(); diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index d2001ae6ea0e..22ddb4adcbf7 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -16,11 +16,15 @@ package android.telephony; +import android.annotation.IntDef; import android.os.Parcel; import android.os.Parcelable; -import android.annotation.IntDef; +import android.telephony.TelephonyManager.NetworkType; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Objects; /** * @hide @@ -50,6 +54,7 @@ public final class PhysicalChannelConfig implements Parcelable { * * <p>One of {@link #CONNECTION_PRIMARY_SERVING}, {@link #CONNECTION_SECONDARY_SERVING}. */ + @ConnectionStatus private int mCellConnectionStatus; /** @@ -57,15 +62,33 @@ public final class PhysicalChannelConfig implements Parcelable { */ private int mCellBandwidthDownlinkKhz; - public PhysicalChannelConfig(int status, int bandwidth) { - mCellConnectionStatus = status; - mCellBandwidthDownlinkKhz = bandwidth; - } + /** + * The radio technology for this physical channel. + */ + @NetworkType + private int mRat; - public PhysicalChannelConfig(Parcel in) { - mCellConnectionStatus = in.readInt(); - mCellBandwidthDownlinkKhz = in.readInt(); - } + /** + * The rough frequency range for this physical channel. + */ + @ServiceState.FrequencyRange + private int mFrequencyRange; + + /** + * The absolute radio frequency channel number, {@link Integer#MAX_VALUE} if unknown. + */ + private int mChannelNumber; + + /** + * A list of data calls mapped to this physical channel. An empty list means the physical + * channel has no data call mapped to it. + */ + private int[] mContextIds; + + /** + * The physical cell identifier for this cell - PCI, PSC, {@link Integer#MAX_VALUE} if known. + */ + private int mPhysicalCellId; @Override public int describeContents() { @@ -76,6 +99,11 @@ public final class PhysicalChannelConfig implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mCellConnectionStatus); dest.writeInt(mCellBandwidthDownlinkKhz); + dest.writeInt(mRat); + dest.writeInt(mChannelNumber); + dest.writeInt(mFrequencyRange); + dest.writeIntArray(mContextIds); + dest.writeInt(mPhysicalCellId); } /** @@ -86,6 +114,60 @@ public final class PhysicalChannelConfig implements Parcelable { } /** + * Get the list of data call ids mapped to this physical channel. This list is sorted into + * ascending numerical order. Each id in this list must match the id in + * {@link com.android.internal.telephony.dataconnection.DataConnection}. An empty list means the + * physical channel has no data call mapped to it. + * + * @return an integer list indicates the data call ids. + */ + public int[] getContextIds() { + return mContextIds; + } + + /** + * @return the rough frequency range for this physical channel. + * @see {@link ServiceState#FREQUENCY_RANGE_LOW} + * @see {@link ServiceState#FREQUENCY_RANGE_MID} + * @see {@link ServiceState#FREQUENCY_RANGE_HIGH} + * @see {@link ServiceState#FREQUENCY_RANGE_MMWAVE} + */ + @ServiceState.FrequencyRange + public int getFrequencyRange() { + return mFrequencyRange; + } + + /** + * @return the absolute radio frequency channel number for this physical channel, + * {@link Integer#MAX_VALUE} if unknown. + */ + public int getChannelNumber() { + return mChannelNumber; + } + + /** + * In UTRAN, this value is primary scrambling code. The range is [0, 511]. + * Reference: 3GPP TS 25.213 section 5.2.2. + * + * In EUTRAN, this value is physical layer cell identity. The range is [0, 503]. + * Reference: 3GPP TS 36.211 section 6.11. + * + * In 5G RAN, this value is physical layer cell identity. The range is [0, 1008]. + * Reference: 3GPP TS 38.211 section 7.4.2.1. + * + * @return the physical cell identifier for this cell, {@link Integer#MAX_VALUE} if unknown. + */ + public int getPhysicalCellId() { + return mPhysicalCellId; + } + + /**The radio technology for this physical channel. */ + @NetworkType + public int getRat() { + return mRat; + } + + /** * Gets the connection status of the cell. * * @see #CONNECTION_PRIMARY_SERVING @@ -125,12 +207,19 @@ public final class PhysicalChannelConfig implements Parcelable { PhysicalChannelConfig config = (PhysicalChannelConfig) o; return mCellConnectionStatus == config.mCellConnectionStatus - && mCellBandwidthDownlinkKhz == config.mCellBandwidthDownlinkKhz; + && mCellBandwidthDownlinkKhz == config.mCellBandwidthDownlinkKhz + && mRat == config.mRat + && mFrequencyRange == config.mFrequencyRange + && mChannelNumber == config.mChannelNumber + && mPhysicalCellId == config.mPhysicalCellId + && Arrays.equals(mContextIds, config.mContextIds); } @Override public int hashCode() { - return (mCellBandwidthDownlinkKhz * 29) + (mCellConnectionStatus * 31); + return Objects.hash( + mCellConnectionStatus, mCellBandwidthDownlinkKhz, mRat, mFrequencyRange, + mChannelNumber, mPhysicalCellId, mContextIds); } public static final Parcelable.Creator<PhysicalChannelConfig> CREATOR = @@ -147,11 +236,111 @@ public final class PhysicalChannelConfig implements Parcelable { @Override public String toString() { return new StringBuilder() - .append("{mConnectionStatus=") - .append(getConnectionStatusString()) - .append(",mCellBandwidthDownlinkKhz=") - .append(mCellBandwidthDownlinkKhz) - .append("}") - .toString(); + .append("{mConnectionStatus=") + .append(getConnectionStatusString()) + .append(",mCellBandwidthDownlinkKhz=") + .append(mCellBandwidthDownlinkKhz) + .append(",mRat=") + .append(mRat) + .append(",mFrequencyRange=") + .append(mFrequencyRange) + .append(",mChannelNumber=") + .append(mChannelNumber) + .append(",mContextIds=") + .append(mContextIds.toString()) + .append(",mPhysicalCellId=") + .append(mPhysicalCellId) + .append("}") + .toString(); + } + + private PhysicalChannelConfig(Parcel in) { + mCellConnectionStatus = in.readInt(); + mCellBandwidthDownlinkKhz = in.readInt(); + mRat = in.readInt(); + mChannelNumber = in.readInt(); + mFrequencyRange = in.readInt(); + mContextIds = in.createIntArray(); + mPhysicalCellId = in.readInt(); + } + + private PhysicalChannelConfig(Builder builder) { + mCellConnectionStatus = builder.mCellConnectionStatus; + mCellBandwidthDownlinkKhz = builder.mCellBandwidthDownlinkKhz; + mRat = builder.mRat; + mChannelNumber = builder.mChannelNumber; + mFrequencyRange = builder.mFrequencyRange; + mContextIds = builder.mContextIds; + mPhysicalCellId = builder.mPhysicalCellId; + } + + /** The builder of {@code PhysicalChannelConfig}. */ + public static final class Builder { + private int mRat; + private int mFrequencyRange; + private int mChannelNumber; + private int mCellBandwidthDownlinkKhz; + private int mCellConnectionStatus; + private int[] mContextIds; + private int mPhysicalCellId; + + /** @hide */ + public Builder() { + mRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; + mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN; + mChannelNumber = Integer.MAX_VALUE; + mCellBandwidthDownlinkKhz = 0; + mCellConnectionStatus = CONNECTION_UNKNOWN; + mContextIds = new int[0]; + mPhysicalCellId = Integer.MAX_VALUE; + } + + /** @hide */ + public PhysicalChannelConfig build() { + return new PhysicalChannelConfig(this); + } + + /** @hide */ + public Builder setRat(int rat) { + this.mRat = rat; + return this; + } + + /** @hide */ + public Builder setFrequencyRange(int frequencyRange) { + this.mFrequencyRange = frequencyRange; + return this; + } + + /** @hide */ + public Builder setChannelNumber(int channelNumber) { + this.mChannelNumber = channelNumber; + return this; + } + + /** @hide */ + public Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) { + this.mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz; + return this; + } + + /** @hide */ + public Builder setCellConnectionStatus(int connectionStatus) { + this.mCellConnectionStatus = connectionStatus; + return this; + } + + /** @hide */ + public Builder setContextIds(int[] contextIds) { + if (contextIds != null) Arrays.sort(contextIds); + this.mContextIds = contextIds; + return this; + } + + /** @hide */ + public Builder setPhysicalCellId(int physicalCellId) { + this.mPhysicalCellId = physicalCellId; + return this; + } } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 3200aeaaa116..34a8c9659595 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -147,7 +147,8 @@ public class SubscriptionManager { public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc"); /** - * A content {@link Uri} used to receive updates on advanced calling user setting. + * A content {@link Uri} used to receive updates on advanced calling user setting + * @see ImsMmTelManager#isAdvancedCallingSettingEnabled(). * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription advanced calling enabled @@ -1426,7 +1427,7 @@ public class SubscriptionManager { * subscriptions in the slot. */ @Nullable - public static int[] getSubscriptionIds(int slotIndex) { + public int[] getSubscriptionIds(int slotIndex) { return getSubId(slotIndex); } diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index bdba8c860db0..2d46ec26a755 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -17,8 +17,8 @@ package android.telephony.emergency; import android.annotation.IntDef; -import android.hardware.radio.V1_3.EmergencyNumberSource; -import android.hardware.radio.V1_3.EmergencyServiceCategory; +import android.hardware.radio.V1_4.EmergencyNumberSource; +import android.hardware.radio.V1_4.EmergencyServiceCategory; import android.os.Parcel; import android.os.Parcelable; @@ -138,7 +138,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu } /** - * The source to tell where the corresponding @1.3::EmergencyNumber comes from. + * The source to tell where the corresponding @1.4::EmergencyNumber comes from. * * The emergency number has one or more defined emergency number sources. * diff --git a/telephony/java/android/telephony/mbms/GroupCall.java b/telephony/java/android/telephony/mbms/GroupCall.java index 9aca18e07812..25e274e4cb13 100644 --- a/telephony/java/android/telephony/mbms/GroupCall.java +++ b/telephony/java/android/telephony/mbms/GroupCall.java @@ -17,6 +17,7 @@ package android.telephony.mbms; import android.annotation.IntDef; +import android.annotation.NonNull; import android.os.RemoteException; import android.telephony.MbmsGroupCallSession; import android.telephony.mbms.vendor.IMbmsGroupCallService; @@ -24,6 +25,7 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; /** * Class used to represent a single MBMS group call. After a call has been started with @@ -41,8 +43,26 @@ public class GroupCall implements AutoCloseable { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "STATE_" }, value = {STATE_STOPPED, STATE_STARTED, STATE_STALLED}) public @interface GroupCallState {} + + /** + * Indicates that the group call is in a stopped state + * + * This can be reported after network action or after calling {@link #close}. + */ public static final int STATE_STOPPED = 1; + + /** + * Indicates that the group call is started. + * + * Data can be transmitted and received in this state. + */ public static final int STATE_STARTED = 2; + + /** + * Indicates that the group call is stalled. + * + * This may be due to a network issue or the device being temporarily out of range. + */ public static final int STATE_STALLED = 3; /** @@ -122,16 +142,17 @@ public class GroupCall implements AutoCloseable { * Send an update to the middleware when the SAI (Service Area Identifier) list and frequency * information of the group call has * changed. Callers must obtain this information from the * wireless carrier independently. - * @param saiArray New array of SAIs that the call is available on. - * @param frequencyArray New array of frequencies that the call is available on. + * @param saiList New list of SAIs that the call is available on. + * @param frequencyList New list of frequencies that the call is available on. */ - public void updateGroupCall(int[] saiArray, int[] frequencyArray) { + public void updateGroupCall(@NonNull List<Integer> saiList, + @NonNull List<Integer> frequencyList) { if (mService == null) { throw new IllegalStateException("No group call service attached"); } try { - mService.updateGroupCall(mSubscriptionId, mTmgi, saiArray, frequencyArray); + mService.updateGroupCall(mSubscriptionId, mTmgi, saiList, frequencyList); } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService = null; diff --git a/telephony/java/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java index 001bb02aad94..77e36bbcf2ae 100644 --- a/telephony/java/android/telephony/mbms/GroupCallCallback.java +++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java @@ -17,6 +17,7 @@ package android.telephony.mbms; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.Nullable; import java.lang.annotation.Retention; @@ -26,7 +27,7 @@ import java.lang.annotation.RetentionPolicy; * A callback class for use when the application is in a group call. The middleware * will provide updates on the status of the call via this callback. */ -public class GroupCallCallback { +public interface GroupCallCallback { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { @@ -40,7 +41,7 @@ public class GroupCallCallback { MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE, MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM, MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" }) - private @interface GroupCallError{} + @interface GroupCallError{} /** * Indicates broadcast signal strength is not available for this call. @@ -48,7 +49,7 @@ public class GroupCallCallback { * This may be due to the call no longer being available due to geography * or timing (end of service) */ - public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; + int SIGNAL_STRENGTH_UNAVAILABLE = -1; /** * Called by the middleware when it has detected an error condition in this group call. The @@ -56,9 +57,7 @@ public class GroupCallCallback { * @param errorCode The error code. * @param message A human-readable message generated by the middleware for debugging purposes. */ - public void onError(@GroupCallError int errorCode, @Nullable String message) { - // default implementation empty - } + void onError(@GroupCallError int errorCode, @Nullable String message); /** * Called to indicate this call has changed state. @@ -66,10 +65,8 @@ public class GroupCallCallback { * See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED} * and {@link GroupCall#STATE_STALLED}. */ - public void onGroupCallStateChanged(@GroupCall.GroupCallState int state, - @GroupCall.GroupCallStateChangeReason int reason) { - // default implementation empty - } + void onGroupCallStateChanged(@GroupCall.GroupCallState int state, + @GroupCall.GroupCallStateChangeReason int reason); /** * Broadcast Signal Strength updated. @@ -81,7 +78,5 @@ public class GroupCallCallback { * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available * for this call due to timing, geography or popularity. */ - public void onBroadcastSignalStrengthUpdated(int signalStrength) { - // default implementation empty - } + void onBroadcastSignalStrengthUpdated(@IntRange(from = -1, to = 4) int signalStrength); } diff --git a/telephony/java/android/telephony/mbms/MbmsErrors.java b/telephony/java/android/telephony/mbms/MbmsErrors.java index 7c4321ba75c3..52e4d333b29d 100644 --- a/telephony/java/android/telephony/mbms/MbmsErrors.java +++ b/telephony/java/android/telephony/mbms/MbmsErrors.java @@ -140,5 +140,21 @@ public class MbmsErrors { public static final int ERROR_UNKNOWN_FILE_INFO = 403; } + /** + * Indicates the errors that are applicable only to the group call use-case. + */ + public static class GroupCallErrors { + private GroupCallErrors() { } + /** Indicates that the middleware was unable to start the group call. */ + public static final int ERROR_UNABLE_TO_START_SERVICE = 501; + + /** + * Indicates that the app called + * {@link android.telephony.MbmsGroupCallSession#startGroupCall} more than once for the + * same {@code tmgi}. + */ + public static final int ERROR_DUPLICATE_START_GROUP_CALL = 502; + } + private MbmsErrors() {} } diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java index 7da734ee5837..04e7ba1af372 100644 --- a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java @@ -17,6 +17,7 @@ package android.telephony.mbms; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.telephony.MbmsGroupCallSession; @@ -29,9 +30,9 @@ import java.util.concurrent.Executor; /** * A callback class that is used to receive information from the middleware on MBMS group-call * services. An instance of this object should be passed into - * {@link MbmsGroupCallSession#create(Context, Executor, int, MbmsGroupCallSessionCallback)}. + * {@link MbmsGroupCallSession#create(Context, int, Executor, MbmsGroupCallSessionCallback)}. */ -public class MbmsGroupCallSessionCallback { +public interface MbmsGroupCallSessionCallback { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { @@ -48,7 +49,7 @@ public class MbmsGroupCallSessionCallback { MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE, MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM, MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" }) - private @interface GroupCallError{} + @interface GroupCallError{} /** * Called by the middleware when it has detected an error condition. The possible error codes @@ -56,8 +57,7 @@ public class MbmsGroupCallSessionCallback { * @param errorCode The error code. * @param message A human-readable message generated by the middleware for debugging purposes. */ - public void onError(@GroupCallError int errorCode, @Nullable String message) { - } + void onError(@GroupCallError int errorCode, @Nullable String message); /** * Indicates that the list of currently available SAIs has been updated. The app may use this @@ -70,21 +70,22 @@ public class MbmsGroupCallSessionCallback { * @param availableSais A list of lists of available SAIS in neighboring cells, where each list * contains the available SAIs in an individual cell. */ - public void onAvailableSaisUpdated(List<Integer> currentSais, - List<List<Integer>> availableSais) { - } + void onAvailableSaisUpdated(@NonNull List<Integer> currentSais, + @NonNull List<List<Integer>> availableSais); /** * Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied - * via this callback may be used to establish a data-link interface with the modem before the - * middleware is ready. - * Note that this method may be called before {@link #onMiddlewareReady()}. + * via this callback may be used to establish a data-link interface with the modem. + * + * In order to establish the data-link interface, the multicast IP and port must be obtained + * out-of-band from the carrier. A {@link java.net.MulticastSocket} may then be constructed + * using a {@link java.net.NetworkInterface} with the name and interface supplied by this + * callback. * * @param interfaceName The interface name for the data link. * @param index The index for the data link. */ - public void onServiceInterfaceAvailable(String interfaceName, int index) { - } + void onServiceInterfaceAvailable(@NonNull String interfaceName, int index); /** * Called to indicate that the middleware has been initialized and is ready. @@ -94,6 +95,5 @@ public class MbmsGroupCallSessionCallback { * delivered via {@link #onError(int, String)} with error code * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}. */ - public void onMiddlewareReady() { - } + void onMiddlewareReady(); } diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl index 721256a95396..44cc24a839f2 100755 --- a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl +++ b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl @@ -29,11 +29,11 @@ interface IMbmsGroupCallService void stopGroupCall(int subId, long tmgi); - void updateGroupCall(int subscriptionId, long tmgi, in int[] saiArray, - in int[] frequencyArray); + void updateGroupCall(int subscriptionId, long tmgi, in List saiList, + in List frequencyList); - int startGroupCall(int subscriptionId, long tmgi, in int[] saiArray, - in int[] frequencyArray, IGroupCallCallback callback); + int startGroupCall(int subscriptionId, long tmgi, in List saiList, + in List frequencyList, IGroupCallCallback callback); void dispose(int subId); } diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java index 3734ca7d6fc9..e86a47d5bfa1 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java @@ -115,15 +115,16 @@ public class MbmsGroupCallServiceBase extends Service { } @Override - public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray, - int[] frequencyArray) { + public void updateGroupCall(int subscriptionId, long tmgi, List saiList, + List frequencyList) { MbmsGroupCallServiceBase.this.updateGroupCall( - subscriptionId, tmgi, saiArray, frequencyArray); + subscriptionId, tmgi, saiList, frequencyList); } @Override - public int startGroupCall(final int subscriptionId, final long tmgi, final int[] saiArray, - final int[] frequencyArray, final IGroupCallCallback callback) + public int startGroupCall(final int subscriptionId, final long tmgi, + final List saiList, + final List frequencyList, final IGroupCallCallback callback) throws RemoteException { if (callback == null) { throw new NullPointerException("Callback must not be null"); @@ -132,7 +133,7 @@ public class MbmsGroupCallServiceBase extends Service { final int uid = Binder.getCallingUid(); int result = MbmsGroupCallServiceBase.this.startGroupCall( - subscriptionId, tmgi, saiArray, frequencyArray, new GroupCallCallback() { + subscriptionId, tmgi, saiList, frequencyList, new GroupCallCallback() { @Override public void onError(final int errorCode, final String message) { try { @@ -209,13 +210,13 @@ public class MbmsGroupCallServiceBase extends Service { * * @param subscriptionId The subscription id to use. * @param tmgi The TMGI, an identifier for the group call. - * @param saiArray An array of SAIs for the group call. - * @param frequencyArray An array of frequencies for the group call. + * @param saiList A list of SAIs for the group call. + * @param frequencyList A list of frequencies for the group call. * @param callback The callback object on which the app wishes to receive updates. * @return Any error in {@link MbmsErrors.GeneralErrors} */ - public int startGroupCall(int subscriptionId, long tmgi, int[] saiArray, int[] frequencyArray, - GroupCallCallback callback) { + public int startGroupCall(int subscriptionId, long tmgi, List<Integer> saiList, + List<Integer> frequencyList, GroupCallCallback callback) { throw new UnsupportedOperationException("Not implemented"); } @@ -237,11 +238,11 @@ public class MbmsGroupCallServiceBase extends Service { /** * Called when the app receives new SAI and frequency information for the group call identified * by {@code tmgi}. - * @param saiArray New array of SAIs that the call is available on. - * @param frequencyArray New array of frequencies that the call is available on. + * @param saiList New list of SAIs that the call is available on. + * @param frequencyList New list of frequencies that the call is available on. */ - public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray, - int[] frequencyArray) { + public void updateGroupCall(int subscriptionId, long tmgi, List<Integer> saiList, + List<Integer> frequencyList) { throw new UnsupportedOperationException("Not implemented"); } diff --git a/tests/TouchLatency/.gitignore b/tests/TouchLatency/.gitignore index bd79078a904e..7f4121a9623a 100644 --- a/tests/TouchLatency/.gitignore +++ b/tests/TouchLatency/.gitignore @@ -3,4 +3,5 @@ /.idea .DS_Store /build +/gen .iml diff --git a/tests/TouchLatency/app/build.gradle b/tests/TouchLatency/app/build.gradle index 233711055eb8..2594322e3727 100644 --- a/tests/TouchLatency/app/build.gradle +++ b/tests/TouchLatency/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 21 - buildToolsVersion "21.1.2" + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { applicationId "com.prefabulated.touchlatency" minSdkVersion 21 - targetSdkVersion 21 + targetSdkVersion 28 versionCode 1 versionName "1.0" } diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java index b4b5ca7161fc..360c22f832b3 100644 --- a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java +++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java @@ -19,11 +19,9 @@ package com.prefabulated.touchlatency; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; -import android.os.CountDownTimer; +import android.graphics.Paint.Align; import android.os.Bundle; -import android.text.method.Touch; import android.util.AttributeSet; import android.util.Log; import android.view.Menu; @@ -31,15 +29,17 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.os.Trace; - -import java.util.ArrayList; -import java.util.Collections; +import java.math.RoundingMode; +import java.text.DecimalFormat; class TouchLatencyView extends View implements View.OnTouchListener { private static final String LOG_TAG = "TouchLatency"; private static final int BACKGROUND_COLOR = 0xFF400080; private static final int INNER_RADIUS = 70; - private static final int BALL_RADIUS = 100; + private static final int BALL_DIAMETER = 200; + private static final int SEC_TO_NANOS = 1000000000; + private static final float FPS_UPDATE_THRESHOLD = 20; + private static final long BALL_VELOCITY = 420; public TouchLatencyView(Context context, AttributeSet attrs) { super(context, attrs); @@ -58,13 +58,17 @@ class TouchLatencyView extends View implements View.OnTouchListener { mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mRedPaint.setColor(0xFFFF0000); mRedPaint.setStyle(Paint.Style.FILL); + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setColor(0xFFFFFFFF); + mTextPaint.setTextSize(100); + mTextPaint.setTextAlign(Align.RIGHT); mTouching = false; - mBallX = 100.0f; - mBallY = 100.0f; - mVelocityX = 7.0f; - mVelocityY = 7.0f; + mLastDrawNano = 0; + mFps = 0; + mLastFpsUpdate = 0; + mFrameCount = 0; Trace.endSection(); } @@ -113,43 +117,70 @@ class TouchLatencyView extends View implements View.OnTouchListener { } } + private Paint getBallColor() { + if (mFps > 75) + return mGreenPaint; + else if (mFps > 45) + return mYellowPaint; + else + return mRedPaint; + } + private void drawBall(Canvas canvas) { Trace.beginSection("TouchLatencyView drawBall"); int width = canvas.getWidth(); int height = canvas.getHeight(); + float fps = 0f; - // Update position - mBallX += mVelocityX; - mBallY += mVelocityY; + long t = System.nanoTime(); + long tDiff = t - mLastDrawNano; + mLastDrawNano = t; + mFrameCount++; - // Clamp and change velocity if necessary - float left = mBallX - BALL_RADIUS; - if (left < 0) { - left = 0; - mVelocityX *= -1; + if (tDiff < SEC_TO_NANOS) { + fps = 1f * SEC_TO_NANOS / tDiff; } - float top = mBallY - BALL_RADIUS; - if (top < 0) { - top = 0; - mVelocityY *= -1; + long fDiff = t - mLastFpsUpdate; + if (Math.abs(mFps - fps) > FPS_UPDATE_THRESHOLD) { + mFps = fps; + mLastFpsUpdate = t; + mFrameCount = 0; + } else if (fDiff > SEC_TO_NANOS) { + mFps = 1f * mFrameCount * SEC_TO_NANOS / fDiff; + mLastFpsUpdate = t; + mFrameCount = 0; } - float right = mBallX + BALL_RADIUS; - if (right > width) { - right = width; - mVelocityX *= -1; + final long pos = t * BALL_VELOCITY / SEC_TO_NANOS; + final long xMax = width - BALL_DIAMETER; + final long yMax = height - BALL_DIAMETER; + long xOffset = pos % xMax; + long yOffset = pos % yMax; + + float left, right, top, bottom; + + if (((pos / xMax) & 1) == 0) { + left = xMax - xOffset; + } else { + left = xOffset; } + right = left + BALL_DIAMETER; - float bottom = mBallY + BALL_RADIUS; - if (bottom > height) { - bottom = height; - mVelocityY *= -1; + if (((pos / yMax) & 1) == 0) { + top = yMax - yOffset; + } else { + top = yOffset; } + bottom = top + BALL_DIAMETER; // Draw the ball canvas.drawColor(BACKGROUND_COLOR); - canvas.drawOval(left, top, right, bottom, mYellowPaint); + canvas.drawOval(left, top, right, bottom, getBallColor()); + DecimalFormat df = new DecimalFormat("fps: #.##"); + df.setRoundingMode(RoundingMode.HALF_UP); + canvas.drawText(df.format(mFps), width, 100, mTextPaint); + invalidate(); Trace.endSection(); } @@ -176,15 +207,15 @@ class TouchLatencyView extends View implements View.OnTouchListener { Trace.endSection(); } - private Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint; + private final Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint, mTextPaint; private int mMode; private boolean mTouching; private float mTouchX, mTouchY; private float mLastDrawnX, mLastDrawnY; - private float mBallX, mBallY; - private float mVelocityX, mVelocityY; + private long mLastDrawNano, mLastFpsUpdate, mFrameCount; + private float mFps; } public class TouchLatencyActivity extends Activity { diff --git a/tests/TouchLatency/build.gradle b/tests/TouchLatency/build.gradle index d3ff69d6e7f9..03abe82a4359 100644 --- a/tests/TouchLatency/build.gradle +++ b/tests/TouchLatency/build.gradle @@ -3,9 +3,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,5 +16,6 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties index 0c71e760dc93..111992a460fa 100644 --- a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties +++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Tue Nov 27 13:37:59 PST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java index b399b0d51577..6e07b26e883a 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java @@ -40,6 +40,7 @@ import android.net.captiveportal.CaptivePortalProbeResult; import android.net.metrics.IpConnectivityLog; import android.net.wifi.WifiManager; import android.os.Handler; +import android.os.SystemClock; import android.provider.Settings; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -70,6 +71,7 @@ public class NetworkMonitorTest { private @Mock Handler mHandler; private @Mock IpConnectivityLog mLogger; private @Mock NetworkAgentInfo mAgent; + private @Mock NetworkAgentInfo mNotMeteredAgent; private @Mock NetworkInfo mNetworkInfo; private @Mock NetworkRequest mRequest; private @Mock TelephonyManager mTelephony; @@ -87,6 +89,10 @@ public class NetworkMonitorTest { private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204"; private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204"; + private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; + private static final int RETURN_CODE_DNS_SUCCESS = 0; + private static final int RETURN_CODE_DNS_TIMEOUT = 255; + @Before public void setUp() throws IOException { MockitoAnnotations.initMocks(this); @@ -95,6 +101,12 @@ public class NetworkMonitorTest { .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); mAgent.networkInfo = mNetworkInfo; + mNotMeteredAgent.linkProperties = new LinkProperties(); + mNotMeteredAgent.networkCapabilities = new NetworkCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + mNotMeteredAgent.networkInfo = mNetworkInfo; + when(mAgent.network()).thenReturn(mNetwork); when(mDependencies.getNetwork(any())).thenReturn(mNetwork); when(mDependencies.getRandom()).thenReturn(mRandom); @@ -138,6 +150,40 @@ public class NetworkMonitorTest { when(mNetwork.getAllByName(any())).thenReturn(new InetAddress[] { InetAddress.parseNumericAddress("192.168.0.0") }); + + setMinDataStallEvaluateInterval(500); + setDataStallEvaluationType(1 << DATA_STALL_EVALUATION_TYPE_DNS); + setValidDataStallDnsTimeThreshold(500); + setConsecutiveDnsTimeoutThreshold(5); + } + + private class WrappedNetworkMonitor extends NetworkMonitor { + private long mProbeTime = 0; + + WrappedNetworkMonitor(Context context, Handler handler, + NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest, + IpConnectivityLog logger, Dependencies deps) { + super(context, handler, networkAgentInfo, defaultRequest, logger, deps); + } + + @Override + protected long getLastProbeTime() { + return mProbeTime; + } + + protected void setLastProbeTime(long time) { + mProbeTime = time; + } + } + + WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() { + return new WrappedNetworkMonitor( + mContext, mHandler, mAgent, mRequest, mLogger, mDependencies); + } + + WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() { + return new WrappedNetworkMonitor( + mContext, mHandler, mNotMeteredAgent, mRequest, mLogger, mDependencies); } NetworkMonitor makeMonitor() { @@ -272,6 +318,113 @@ public class NetworkMonitorTest { assertPortal(makeMonitor().isCaptivePortal()); } + @Test + public void testIsDataStall_EvaluationDisabled() { + setDataStallEvaluationType(0); + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + assertFalse(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() { + WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertTrue(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsOnMeteredNetwork() { + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + assertFalse(wrappedMonitor.isDataStall()); + + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertTrue(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() { + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + makeDnsTimeoutEvent(wrappedMonitor, 3); + assertFalse(wrappedMonitor.isDataStall()); + // Reset consecutive timeout counts. + makeDnsSuccessEvent(wrappedMonitor, 1); + makeDnsTimeoutEvent(wrappedMonitor, 2); + assertFalse(wrappedMonitor.isDataStall()); + + makeDnsTimeoutEvent(wrappedMonitor, 3); + assertTrue(wrappedMonitor.isDataStall()); + + // Set the value to larger than the default dns log size. + setConsecutiveDnsTimeoutThreshold(51); + wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + makeDnsTimeoutEvent(wrappedMonitor, 50); + assertFalse(wrappedMonitor.isDataStall()); + + makeDnsTimeoutEvent(wrappedMonitor, 1); + assertTrue(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() { + // Test dns events happened in valid dns time threshold. + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertFalse(wrappedMonitor.isDataStall()); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + assertTrue(wrappedMonitor.isDataStall()); + + // Test dns events happened before valid dns time threshold. + setValidDataStallDnsTimeThreshold(0); + wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertFalse(wrappedMonitor.isDataStall()); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + assertFalse(wrappedMonitor.isDataStall()); + } + + private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) { + for (int i = 0; i < count; i++) { + wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount( + RETURN_CODE_DNS_TIMEOUT); + } + } + + private void makeDnsSuccessEvent(WrappedNetworkMonitor wrappedMonitor, int count) { + for (int i = 0; i < count; i++) { + wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount( + RETURN_CODE_DNS_SUCCESS); + } + } + + private void setDataStallEvaluationType(int type) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type); + } + + private void setMinDataStallEvaluateInterval(int time) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time); + } + + private void setValidDataStallDnsTimeThreshold(int time) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time); + } + + private void setConsecutiveDnsTimeoutThreshold(int num) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())) + .thenReturn(num); + } + private void setFallbackUrl(String url) { when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL), any())).thenReturn(url); diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index af7123b84842..f2bd770d085a 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -27,9 +27,17 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.os.Process.SYSTEM_UID; +import static com.android.server.connectivity.PermissionMonitor.NETWORK; +import static com.android.server.connectivity.PermissionMonitor.SYSTEM; + +import static junit.framework.Assert.fail; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.spy; @@ -40,6 +48,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; +import android.os.INetworkManagementService; +import android.os.UserHandle; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -48,12 +58,19 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; + +import java.util.HashMap; @RunWith(AndroidJUnit4.class) @SmallTest public class PermissionMonitorTest { - private static final int MOCK_UID = 10001; - private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" }; + private static final int MOCK_USER1 = 0; + private static final int MOCK_USER2 = 1; + private static final int MOCK_UID1 = 10001; + private static final String MOCK_PACKAGE1 = "appName1"; + private static final String SYSTEM_PACKAGE1 = "sysName1"; + private static final String SYSTEM_PACKAGE2 = "sysName2"; private static final String PARTITION_SYSTEM = "system"; private static final String PARTITION_OEM = "oem"; private static final String PARTITION_PRODUCT = "product"; @@ -63,6 +80,7 @@ public class PermissionMonitorTest { @Mock private Context mContext; @Mock private PackageManager mPackageManager; + @Mock private INetworkManagementService mNMS; private PermissionMonitor mPermissionMonitor; @@ -70,8 +88,7 @@ public class PermissionMonitorTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); - when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(MOCK_PACKAGE_NAMES); - mPermissionMonitor = spy(new PermissionMonitor(mContext, null)); + mPermissionMonitor = spy(new PermissionMonitor(mContext, mNMS)); } private boolean hasBgPermission(String partition, int targetSdkVersion, int uid, @@ -80,7 +97,8 @@ public class PermissionMonitorTest { packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion; packageInfo.applicationInfo.uid = uid; when(mPackageManager.getPackageInfoAsUser( - eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo); + eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo); + when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[] {MOCK_PACKAGE1}); return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid); } @@ -143,16 +161,16 @@ public class PermissionMonitorTest { @Test public void testHasUseBackgroundNetworksPermission() throws Exception { - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, NETWORK_STACK)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, + assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1)); + assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE)); + assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK)); + assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL)); + assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE)); + assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE)); - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID)); - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE)); + assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); + assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE)); } @Test @@ -172,15 +190,150 @@ public class PermissionMonitorTest { @Test public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception { - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, NETWORK_STACK)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, + assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1)); + assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE)); + assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK)); + assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL)); + assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE)); + assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE)); + + assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1)); + assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE)); + } + + private class NMSMonitor { + private final HashMap<Integer, Boolean> mApps = new HashMap<>(); + + NMSMonitor(INetworkManagementService mockNMS) throws Exception { + // Add hook to verify and track result of setPermission. + doAnswer((InvocationOnMock invocation) -> { + final Object[] args = invocation.getArguments(); + final Boolean isSystem = args[0].equals("SYSTEM"); + for (final int uid : (int[]) args[1]) { + // TODO: Currently, permission monitor will send duplicate commands for each uid + // corresponding to each user. Need to fix that and uncomment below test. + // if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) { + // fail("uid " + uid + " is already set to " + isSystem); + // } + mApps.put(uid, isSystem); + } + return null; + }).when(mockNMS).setPermission(anyString(), any(int[].class)); + + // Add hook to verify and track result of clearPermission. + doAnswer((InvocationOnMock invocation) -> { + final Object[] args = invocation.getArguments(); + for (final int uid : (int[]) args[0]) { + // TODO: Currently, permission monitor will send duplicate commands for each uid + // corresponding to each user. Need to fix that and uncomment below test. + // if (!mApps.containsKey(uid)) { + // fail("uid " + uid + " does not exist."); + // } + mApps.remove(uid); + } + return null; + }).when(mockNMS).clearPermission(any(int[].class)); + } + + public void expectPermission(Boolean permission, int[] users, int[] apps) { + for (final int user : users) { + for (final int app : apps) { + final int uid = UserHandle.getUid(user, app); + if (!mApps.containsKey(uid)) { + fail("uid " + uid + " does not exist."); + } + if (mApps.get(uid) != permission) { + fail("uid " + uid + " has wrong permission: " + permission); + } + } + } + } + + public void expectNoPermission(int[] users, int[] apps) { + for (final int user : users) { + for (final int app : apps) { + final int uid = UserHandle.getUid(user, app); + if (mApps.containsKey(uid)) { + fail("uid " + uid + " has listed permissions, expected none."); + } + } + } + } + } + + @Test + public void testUserAndPackageAddRemove() throws Exception { + final NMSMonitor mNMSMonitor = new NMSMonitor(mNMS); - assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID)); - assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE)); + // MOCK_UID1: MOCK_PACKAGE1 only has network permission. + // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission. + // SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission. + doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString()); + doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(), + eq(SYSTEM_PACKAGE1)); + doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(), + eq(SYSTEM_PACKAGE2)); + doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(), + eq(MOCK_PACKAGE1)); + + // Add SYSTEM_PACKAGE2, expect only have network permission. + mPermissionMonitor.onUserAdded(MOCK_USER1); + addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID); + mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID}); + + // Add SYSTEM_PACKAGE1, expect permission escalate. + addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID); + mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID}); + + mPermissionMonitor.onUserAdded(MOCK_USER2); + mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2}, + new int[]{SYSTEM_UID}); + + addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1); + mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2}, + new int[]{SYSTEM_UID}); + mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, + new int[]{MOCK_UID1}); + + // Remove MOCK_UID1, expect no permission left for all user. + mPermissionMonitor.onPackageRemoved(MOCK_UID1); + removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1); + mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1}); + + // Remove SYSTEM_PACKAGE1, expect permission downgrade. + when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2}); + removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID); + mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, + new int[]{SYSTEM_UID}); + + mPermissionMonitor.onUserRemoved(MOCK_USER1); + mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID}); + + // Remove all packages, expect no permission left. + when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{}); + removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID); + mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, + new int[]{SYSTEM_UID, MOCK_UID1}); + + // Remove last user, expect no redundant clearPermission is invoked. + mPermissionMonitor.onUserRemoved(MOCK_USER2); + mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, + new int[]{SYSTEM_UID, MOCK_UID1}); + } + + // Normal package add/remove operations will trigger multiple intent for uids corresponding to + // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be + // called multiple times with the uid corresponding to each user. + private void addPackageForUsers(int[] users, String packageName, int uid) { + for (final int user : users) { + mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid)); + } + } + + private void removePackageForUsers(int[] users, int uid) { + for (final int user : users) { + mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid)); + } } } diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 91cd1cba964d..cb8fef946baf 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -1285,10 +1285,19 @@ def verify_user_handle(clazz): if clazz.fullname == "android.os.UserManager": return for m in clazz.methods: - if m.name.endswith("AsUser") or m.name.endswith("ForUser"): continue if re.match("on[A-Z]+", m.name): continue - if "android.os.UserHandle" in m.args: - warn(clazz, m, None, "Method taking UserHandle should be named 'doFooAsUser' or 'queryFooForUser'") + + has_arg = "android.os.UserHandle" in m.args + has_name = m.name.endswith("AsUser") or m.name.endswith("ForUser") + + if clazz.fullname.endswith("Manager") and has_arg: + warn(clazz, m, None, "When a method overload is needed to target a specific " + "UserHandle, callers should be directed to use " + "Context.createPackageContextAsUser() and re-obtain the relevant " + "Manager, and no new API should be added") + elif has_arg and not has_name: + warn(clazz, m, None, "Method taking UserHandle should be named 'doFooAsUser' " + "or 'queryFooForUser'") def verify_params(clazz): diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java index aa8d325419f0..87706b936f03 100644 --- a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java +++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java @@ -60,14 +60,27 @@ public class WifiNetworkConfigBuilder { */ private @Nullable Pair<MacAddress, MacAddress> mBssidPatternMatcher; /** + * Whether this is an OWE network or not. + */ + private boolean mIsEnhancedOpen; + /** * Pre-shared key for use with WPA-PSK networks. */ - private @Nullable String mPskPassphrase; + private @Nullable String mWpa2PskPassphrase; + /** + * Pre-shared key for use with WPA3-SAE networks. + */ + private @Nullable String mWpa3SaePassphrase; + /** + * The enterprise configuration details specifying the EAP method, + * certificates and other settings associated with the WPA-EAP networks. + */ + private @Nullable WifiEnterpriseConfig mWpa2EnterpriseConfig; /** * The enterprise configuration details specifying the EAP method, - * certificates and other settings associated with the EAP. + * certificates and other settings associated with the SuiteB networks. */ - private @Nullable WifiEnterpriseConfig mEnterpriseConfig; + private @Nullable WifiEnterpriseConfig mWpa3EnterpriseConfig; /** * This is a network that does not broadcast its SSID, so an * SSID-specific probe request must be used for scans. @@ -94,8 +107,11 @@ public class WifiNetworkConfigBuilder { public WifiNetworkConfigBuilder() { mSsidPatternMatcher = null; mBssidPatternMatcher = null; - mPskPassphrase = null; - mEnterpriseConfig = null; + mIsEnhancedOpen = false; + mWpa2PskPassphrase = null; + mWpa3SaePassphrase = null; + mWpa2EnterpriseConfig = null; + mWpa3EnterpriseConfig = null; mIsHiddenSSID = false; mIsAppInteractionRequired = false; mIsUserInteractionRequired = false; @@ -188,36 +204,81 @@ public class WifiNetworkConfigBuilder { } /** - * Set the ASCII PSK passphrase for this network. Needed for authenticating to - * WPA_PSK networks. + * Specifies whether this represents an Enhanced Open (OWE) network. * - * @param pskPassphrase PSK passphrase of the network. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setIsEnhancedOpen() { + mIsEnhancedOpen = true; + return this; + } + + /** + * Set the ASCII WPA2 passphrase for this network. Needed for authenticating to + * WPA2-PSK networks. + * + * @param passphrase passphrase of the network. * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder * method. * @throws IllegalArgumentException if the passphrase is not ASCII encodable. */ - public WifiNetworkConfigBuilder setPskPassphrase(@NonNull String pskPassphrase) { - checkNotNull(pskPassphrase); + public WifiNetworkConfigBuilder setWpa2Passphrase(@NonNull String passphrase) { + checkNotNull(passphrase); final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); - if (!asciiEncoder.canEncode(pskPassphrase)) { + if (!asciiEncoder.canEncode(passphrase)) { throw new IllegalArgumentException("passphrase not ASCII encodable"); } - mPskPassphrase = pskPassphrase; + mWpa2PskPassphrase = passphrase; + return this; + } + + /** + * Set the ASCII WPA3 passphrase for this network. Needed for authenticating to + * WPA3-SAE networks. + * + * @param passphrase passphrase of the network. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + * @throws IllegalArgumentException if the passphrase is not ASCII encodable. + */ + public WifiNetworkConfigBuilder setWpa3Passphrase(@NonNull String passphrase) { + checkNotNull(passphrase); + final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); + if (!asciiEncoder.canEncode(passphrase)) { + throw new IllegalArgumentException("passphrase not ASCII encodable"); + } + mWpa3SaePassphrase = passphrase; + return this; + } + + /** + * Set the associated enterprise configuration for this network. Needed for authenticating to + * WPA2-EAP networks. See {@link WifiEnterpriseConfig} for description. + * + * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setWpa2EnterpriseConfig( + @NonNull WifiEnterpriseConfig enterpriseConfig) { + checkNotNull(enterpriseConfig); + mWpa2EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); return this; } /** * Set the associated enterprise configuration for this network. Needed for authenticating to - * WPA_EAP networks. See {@link WifiEnterpriseConfig} for description. + * WPA3-SuiteB networks. See {@link WifiEnterpriseConfig} for description. * * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder * method. */ - public WifiNetworkConfigBuilder setEnterpriseConfig( + public WifiNetworkConfigBuilder setWpa3EnterpriseConfig( @NonNull WifiEnterpriseConfig enterpriseConfig) { checkNotNull(enterpriseConfig); - mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); + mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); return this; } @@ -324,16 +385,38 @@ public class WifiNetworkConfigBuilder { configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); } - private void setKeyMgmtInWifiConfiguration(@NonNull WifiConfiguration configuration) { - if (!TextUtils.isEmpty(mPskPassphrase)) { - // WPA_PSK network. + private void setSecurityParamsInWifiConfiguration(@NonNull WifiConfiguration configuration) { + if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network. configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); - } else if (mEnterpriseConfig != null) { - // WPA_EAP network + // WifiConfiguration.preSharedKey needs quotes around ASCII password. + configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\""; + } else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network. + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE); + // PMF mandatory for SAE. + configuration.requirePMF = true; + // WifiConfiguration.preSharedKey needs quotes around ASCII password. + configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\""; + } else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); - } else { - // Open network + configuration.enterpriseConfig = mWpa2EnterpriseConfig; + } else if (mWpa3EnterpriseConfig != null) { // WPA3-SuiteB network + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192); + configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256); + // TODO (b/113878056): Verify these params once we verify SuiteB configuration. + configuration.allowedGroupMgmtCiphers.set( + WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256); + configuration.allowedSuiteBCiphers.set( + WifiConfiguration.SuiteBCipher.ECDHE_ECDSA); + configuration.allowedSuiteBCiphers.set( + WifiConfiguration.SuiteBCipher.ECDHE_RSA); + configuration.requirePMF = true; + configuration.enterpriseConfig = mWpa3EnterpriseConfig; + } else if (mIsEnhancedOpen) { // OWE network + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE); + // PMF mandatory. + configuration.requirePMF = true; + } else { // Open network configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); } } @@ -349,12 +432,7 @@ public class WifiNetworkConfigBuilder { if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) { wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\""; } - setKeyMgmtInWifiConfiguration(wifiConfiguration); - // WifiConfiguration.preSharedKey needs quotes around ASCII password. - if (mPskPassphrase != null) { - wifiConfiguration.preSharedKey = "\"" + mPskPassphrase + "\""; - } - wifiConfiguration.enterpriseConfig = mEnterpriseConfig; + setSecurityParamsInWifiConfiguration(wifiConfiguration); wifiConfiguration.hiddenSSID = mIsHiddenSSID; wifiConfiguration.priority = mPriority; wifiConfiguration.meteredOverride = @@ -396,6 +474,20 @@ public class WifiNetworkConfigBuilder { return false; } + private void validateSecurityParams() { + int numSecurityTypes = 0; + numSecurityTypes += mIsEnhancedOpen ? 1 : 0; + numSecurityTypes += !TextUtils.isEmpty(mWpa2PskPassphrase) ? 1 : 0; + numSecurityTypes += !TextUtils.isEmpty(mWpa3SaePassphrase) ? 1 : 0; + numSecurityTypes += mWpa2EnterpriseConfig != null ? 1 : 0; + numSecurityTypes += mWpa3EnterpriseConfig != null ? 1 : 0; + if (numSecurityTypes > 1) { + throw new IllegalStateException("only one of setIsEnhancedOpen, setWpa2Passphrase," + + "setWpa3Passphrase, setWpa2EnterpriseConfig or setWpa3EnterpriseConfig" + + " can be invoked for network specifier"); + } + } + /** * Create a specifier object used to request a Wi-Fi network. The generated * {@link NetworkSpecifier} should be used in @@ -464,10 +556,7 @@ public class WifiNetworkConfigBuilder { + "setIsUserInteractionRequired/setPriority/setIsMetered are allowed for " + "specifier"); } - if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) { - throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can" - + " be invoked for network specifier"); - } + validateSecurityParams(); return new WifiNetworkSpecifier( mSsidPatternMatcher, @@ -493,10 +582,7 @@ public class WifiNetworkConfigBuilder { throw new IllegalStateException("none of setSsidPattern/setBssidPattern/setBssid are" + " allowed for suggestion"); } - if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) { - throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can" - + "be invoked for suggestion"); - } + validateSecurityParams(); return new WifiNetworkSuggestion( buildWifiConfiguration(), diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java index 8980ddba238b..c455c6f0836d 100644 --- a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java +++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java @@ -22,6 +22,7 @@ import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.net.MacAddress; @@ -81,11 +82,11 @@ public class WifiNetworkConfigBuilderTest { * pattern. */ @Test - public void testWifiNetworkSpecifierBuilderForWpaPskNetworkWithBssidPattern() { + public void testWifiNetworkSpecifierBuilderForWpa2PskNetworkWithBssidPattern() { NetworkSpecifier specifier = new WifiNetworkConfigBuilder() .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), MacAddress.fromString(TEST_BSSID_OUI_MASK)) - .setPskPassphrase(TEST_PRESHARED_KEY) + .setWpa2Passphrase(TEST_PRESHARED_KEY) .buildNetworkSpecifier(); assertTrue(specifier instanceof WifiNetworkSpecifier); @@ -119,7 +120,7 @@ public class WifiNetworkConfigBuilderTest { * SSID and BSSID pattern. */ @Test - public void testWifiNetworkSpecifierBuilderForEnterpriseHiddenNetworkWithSsidAndBssid() { + public void testWifiNetworkSpecifierBuilderForWpa2EapHiddenNetworkWithSsidAndBssid() { WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS); enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC); @@ -127,7 +128,7 @@ public class WifiNetworkConfigBuilderTest { NetworkSpecifier specifier = new WifiNetworkConfigBuilder() .setSsid(TEST_SSID) .setBssid(MacAddress.fromString(TEST_BSSID)) - .setEnterpriseConfig(enterpriseConfig) + .setWpa2EnterpriseConfig(enterpriseConfig) .setIsHiddenSsid() .buildNetworkSpecifier(); @@ -174,14 +175,14 @@ public class WifiNetworkConfigBuilderTest { } /** - * Ensure {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} throws an exception + * Ensure {@link WifiNetworkConfigBuilder#setWpa2Passphrase(String)} throws an exception * when the string is not ASCII encodable. */ @Test(expected = IllegalArgumentException.class) - public void testSetPskPassphraseWithNonAsciiString() { + public void testSetWpa2PasphraseWithNonAsciiString() { new WifiNetworkConfigBuilder() .setSsid(TEST_SSID) - .setPskPassphrase("salvē") + .setWpa2Passphrase("salvē") .buildNetworkSpecifier(); } @@ -275,15 +276,15 @@ public class WifiNetworkConfigBuilderTest { /** * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception - * when both {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} and - * {@link WifiNetworkConfigBuilder#setEnterpriseConfig(WifiEnterpriseConfig)} are invoked. + * when both {@link WifiNetworkConfigBuilder#setWpa2Passphrase(String)} and + * {@link WifiNetworkConfigBuilder#setWpa2EnterpriseConfig(WifiEnterpriseConfig)} are invoked. */ @Test(expected = IllegalStateException.class) - public void testWifiNetworkSpecifierBuilderWithBothPskPassphraseAndEnterpriseConfig() { + public void testWifiNetworkSpecifierBuilderWithBothWpa2PasphraseAndEnterpriseConfig() { new WifiNetworkConfigBuilder() .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) - .setPskPassphrase(TEST_PRESHARED_KEY) - .setEnterpriseConfig(new WifiEnterpriseConfig()) + .setWpa2Passphrase(TEST_PRESHARED_KEY) + .setWpa2EnterpriseConfig(new WifiEnterpriseConfig()) .buildNetworkSpecifier(); } @@ -375,10 +376,11 @@ public class WifiNetworkConfigBuilderTest { * app interaction and has a priority of zero set. */ @Test - public void testWifiNetworkSuggestionBuilderForWpaEapNetworkWithPriorityAndReqAppInteraction() { + public void + testWifiNetworkSuggestionBuilderForWpa2EapNetworkWithPriorityAndReqAppInteraction() { WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() .setSsid(TEST_SSID) - .setPskPassphrase(TEST_PRESHARED_KEY) + .setWpa2Passphrase(TEST_PRESHARED_KEY) .setIsAppInteractionRequired() .setPriority(0) .buildNetworkSuggestion(); @@ -401,10 +403,11 @@ public class WifiNetworkConfigBuilderTest { * user interaction and is metered. */ @Test - public void testWifiNetworkSuggestionBuilderForWpaPskNetworkWithMeteredAndReqUserInteraction() { + public void + testWifiNetworkSuggestionBuilderForWpa2PskNetworkWithMeteredAndReqUserInteraction() { WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() .setSsid(TEST_SSID) - .setPskPassphrase(TEST_PRESHARED_KEY) + .setWpa2Passphrase(TEST_PRESHARED_KEY) .setIsUserInteractionRequired() .setIsMetered() .buildNetworkSuggestion(); @@ -422,6 +425,74 @@ public class WifiNetworkConfigBuilderTest { } /** + * Validate correctness of WifiNetworkSuggestion object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for OWE network. + */ + @Test + public void testWifiNetworkSuggestionBuilderForEnhancedOpenNetwork() { + WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setIsEnhancedOpen() + .buildNetworkSuggestion(); + + assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); + assertTrue(suggestion.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.OWE)); + assertNull(suggestion.wifiConfiguration.preSharedKey); + assertTrue(suggestion.wifiConfiguration.requirePMF); + } + + /** + * Validate correctness of WifiNetworkSuggestion object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for SAE network. + */ + @Test + public void testWifiNetworkSuggestionBuilderForWpa3PskNetwork() { + WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setWpa3Passphrase(TEST_PRESHARED_KEY) + .buildNetworkSuggestion(); + + assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); + assertTrue(suggestion.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.SAE)); + assertEquals("\"" + TEST_PRESHARED_KEY + "\"", + suggestion.wifiConfiguration.preSharedKey); + assertTrue(suggestion.wifiConfiguration.requirePMF); + } + + + /** + * Validate correctness of WifiNetworkSuggestion object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for SuiteB network. + */ + @Test + public void testWifiNetworkSuggestionBuilderForWpa3EapNetwork() { + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS); + enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC); + + WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setWpa3EnterpriseConfig(enterpriseConfig) + .buildNetworkSuggestion(); + + assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); + assertTrue(suggestion.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.SUITE_B_192)); + assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers + .get(WifiConfiguration.GroupCipher.GCMP_256)); + assertTrue(suggestion.wifiConfiguration.allowedGroupMgmtCiphers + .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256)); + assertTrue(suggestion.wifiConfiguration.allowedSuiteBCiphers + .get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA)); + assertTrue(suggestion.wifiConfiguration.allowedSuiteBCiphers + .get(WifiConfiguration.SuiteBCipher.ECDHE_RSA)); + assertTrue(suggestion.wifiConfiguration.requirePMF); + assertNull(suggestion.wifiConfiguration.preSharedKey); + } + + /** * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception * when {@link WifiNetworkConfigBuilder#setSsidPattern(PatternMatcher)} is set. */ @@ -478,4 +549,46 @@ public class WifiNetworkConfigBuilderTest { .setPriority(-1) .buildNetworkSuggestion(); } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when both {@link WifiNetworkConfigBuilder#setWpa2Passphrase(String)} and + * {@link WifiNetworkConfigBuilder#setWpa3Passphrase(String)} are invoked. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithBothWpa2PasphraseAndWpa3Passphrase() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setWpa2Passphrase(TEST_PRESHARED_KEY) + .setWpa3Passphrase(TEST_PRESHARED_KEY) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when both {@link WifiNetworkConfigBuilder#setWpa3Passphrase(String)} and + * {@link WifiNetworkConfigBuilder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)} are invoked. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithBothWpa3PasphraseAndEnterprise() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setWpa3Passphrase(TEST_PRESHARED_KEY) + .setWpa3EnterpriseConfig(new WifiEnterpriseConfig()) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when both {@link WifiNetworkConfigBuilder#setWpa3Passphrase(String)} and + * {@link WifiNetworkConfigBuilder#setIsEnhancedOpen(} are invoked. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithBothWpa3PasphraseAndEnhancedOpen() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setWpa3Passphrase(TEST_PRESHARED_KEY) + .setIsEnhancedOpen() + .buildNetworkSpecifier(); + } } |