diff options
201 files changed, 6345 insertions, 3427 deletions
diff --git a/Android.mk b/Android.mk index eb649c9152c3..e27aa307e1e6 100644 --- a/Android.mk +++ b/Android.mk @@ -102,6 +102,7 @@ LOCAL_SRC_FILES += \ core/java/android/app/IUserSwitchObserver.aidl \ core/java/android/app/IWallpaperManager.aidl \ core/java/android/app/IWallpaperManagerCallback.aidl \ + core/java/android/app/admin/IDeviceAdminService.aidl \ core/java/android/app/admin/IDevicePolicyManager.aidl \ core/java/android/app/trust/IStrongAuthTracker.aidl \ core/java/android/app/trust/ITrustManager.aidl \ @@ -319,6 +320,8 @@ LOCAL_SRC_FILES += \ core/java/android/service/wallpaper/IWallpaperService.aidl \ core/java/android/service/chooser/IChooserTargetService.aidl \ core/java/android/service/chooser/IChooserTargetResult.aidl \ + core/java/android/service/resolver/IResolverRankerService.aidl \ + core/java/android/service/resolver/IResolverRankerResult.aidl \ core/java/android/text/ITextClassificationService.aidl \ core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\ core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\ @@ -366,7 +369,6 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \ core/java/com/android/internal/backup/IBackupTransport.aidl \ core/java/com/android/internal/backup/IObbBackupService.aidl \ - core/java/com/android/internal/font/IFontManager.aidl \ core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \ core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \ core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \ @@ -728,6 +730,7 @@ aidl_files := \ frameworks/base/core/java/android/service/notification/SnoozeCriterion.aidl \ frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \ frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \ + frameworks/base/core/java/android/service/resolver/ResolverTarget.aidl \ frameworks/base/core/java/android/speech/tts/Voice.aidl \ frameworks/base/core/java/android/app/usage/CacheQuotaHint.aidl \ frameworks/base/core/java/android/app/usage/ExternalStorageStats.aidl \ @@ -1460,8 +1463,7 @@ LOCAL_PROTOC_FLAGS := \ LOCAL_SRC_FILES := \ $(call all-proto-files-under, core/proto) \ $(call all-proto-files-under, libs/incident/proto) -LOCAL_SHARED_LIBRARIES := libprotobuf-cpp-full -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_STATIC_LIBRARY) # ==== c++ proto host library ============================== include $(CLEAR_VARS) diff --git a/api/current.txt b/api/current.txt index d18d88137720..3c045ac2ee45 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6232,6 +6232,11 @@ package android.app.admin { field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE"; } + public class DeviceAdminService extends android.app.Service { + ctor public DeviceAdminService(); + method public final android.os.IBinder onBind(android.content.Intent); + } + public class DevicePolicyManager { method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int); method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); @@ -6398,6 +6403,7 @@ package android.app.admin { method public void wipeData(int); field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"; field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED"; + field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE"; field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED"; field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL"; @@ -8883,7 +8889,6 @@ package android.content { field public static final java.lang.String DOWNLOAD_SERVICE = "download"; field public static final java.lang.String DROPBOX_SERVICE = "dropbox"; field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint"; - field public static final java.lang.String FONT_SERVICE = "font"; field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties"; field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method"; field public static final java.lang.String INPUT_SERVICE = "input"; @@ -9270,6 +9275,8 @@ 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_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED"; + field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED"; 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"; @@ -9469,8 +9476,9 @@ package android.content { field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT"; field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME"; field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"; - field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM"; + field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM"; field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT"; + field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX"; field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE"; field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT"; field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE"; @@ -9829,6 +9837,7 @@ package android.content { } public abstract interface ServiceConnection { + method public default void onBindingDead(android.content.ComponentName); method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder); method public abstract void onServiceDisconnected(android.content.ComponentName); } @@ -10333,12 +10342,12 @@ package android.content.pm { ctor public LauncherApps.ShortcutQuery(); method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName); method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long); - method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent); + method public deprecated android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent); method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String); method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int); method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>); field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4 - field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10 + field public static final deprecated int FLAG_MATCH_CHOOSER = 16; // 0x10 field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1 field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8 field public static final int FLAG_MATCH_PINNED = 2; // 0x2 @@ -10635,6 +10644,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen"; field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods"; field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback"; + field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv"; field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper"; field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location"; @@ -10888,9 +10898,9 @@ package android.content.pm { method public int describeContents(); method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); - method public android.content.ComponentName[] getChooserComponentNames(); - method public android.os.PersistableBundle getChooserExtras(); - method public android.content.IntentFilter[] getChooserIntentFilters(); + method public deprecated android.content.ComponentName[] getChooserComponentNames(); + method public deprecated android.os.PersistableBundle getChooserExtras(); + method public deprecated android.content.IntentFilter[] getChooserIntentFilters(); method public java.lang.CharSequence getDisabledMessage(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); @@ -10903,7 +10913,7 @@ package android.content.pm { method public java.lang.CharSequence getShortLabel(); method public android.os.UserHandle getUserHandle(); method public boolean hasKeyFieldsOnly(); - method public boolean isChooser(); + method public deprecated boolean isChooser(); method public boolean isDeclaredInManifest(); method public boolean isDynamic(); method public boolean isEnabled(); @@ -10916,11 +10926,11 @@ package android.content.pm { public static class ShortcutInfo.Builder { ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String); - method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName); + method public deprecated android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName); method public android.content.pm.ShortcutInfo build(); method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName); method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>); - method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle); + method public deprecated android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence); method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon); @@ -12693,7 +12703,7 @@ package android.graphics { enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP; } - public final class Color { + public class Color { ctor public Color(); method public static int HSVToColor(float[]); method public static int HSVToColor(int, float[]); @@ -13232,7 +13242,7 @@ package android.graphics { method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(java.lang.String); - method public boolean setFontVariationSettings(java.lang.String); + method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method public void setHinting(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); @@ -13766,8 +13776,8 @@ package android.graphics { method public static android.graphics.Typeface.Builder obtain(); method public void recycle(); method public void reset(); - method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String); - method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]); + method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); method public android.graphics.Typeface.Builder setItalic(int); method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String); method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File); @@ -14377,6 +14387,21 @@ package android.graphics.fonts { field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR; } + public final class FontVariationAxis implements android.os.Parcelable { + ctor public FontVariationAxis(java.lang.String, float) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public int describeContents(); + method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public float getStyleValue(); + method public java.lang.String getTag(); + method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontVariationAxis> CREATOR; + } + + public static class FontVariationAxis.InvalidFormatException extends java.lang.Exception { + ctor public FontVariationAxis.InvalidFormatException(java.lang.String); + } + } package android.graphics.pdf { @@ -15972,11 +15997,11 @@ package android.hardware.usb { ctor public UsbRequest(); method public boolean cancel(); method public void close(); - method public boolean enqueue(java.nio.ByteBuffer); method public java.lang.Object getClientData(); method public android.hardware.usb.UsbEndpoint getEndpoint(); method public boolean initialize(android.hardware.usb.UsbDeviceConnection, android.hardware.usb.UsbEndpoint); method public deprecated boolean queue(java.nio.ByteBuffer, int); + method public boolean queue(java.nio.ByteBuffer); method public void setClientData(java.lang.Object); } @@ -22989,6 +23014,7 @@ package android.media { method public void setProfile(android.media.CamcorderProfile); method public void setVideoEncoder(int) throws java.lang.IllegalStateException; method public void setVideoEncodingBitRate(int); + method public void setVideoEncodingProfileLevel(int, int); method public void setVideoFrameRate(int) throws java.lang.IllegalStateException; method public void setVideoSize(int, int) throws java.lang.IllegalStateException; method public void setVideoSource(int) throws java.lang.IllegalStateException; @@ -24531,19 +24557,19 @@ package android.media.tv { } public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns { - field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9"; - field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1"; - field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3"; - field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2"; - field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE"; - field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION"; - field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT"; - field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri"; + field public static final int ASPECT_RATIO_16_9 = 0; // 0x0 + field public static final int ASPECT_RATIO_1_1 = 2; // 0x2 + field public static final int ASPECT_RATIO_2_3 = 3; // 0x3 + field public static final int ASPECT_RATIO_3_2 = 1; // 0x1 + field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0 + field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1 + field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2 field public static final java.lang.String COLUMN_AUTHOR = "author"; field public static final java.lang.String COLUMN_AVAILABILITY = "availability"; field public static final java.lang.String COLUMN_BROWSABLE = "browsable"; field public static final java.lang.String COLUMN_CONTENT_ID = "content_id"; field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis"; + field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri"; field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count"; field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type"; field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"; @@ -24561,28 +24587,28 @@ package android.media.tv { field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio"; field public static final java.lang.String COLUMN_TRANSIENT = "transient"; field public static final java.lang.String COLUMN_TYPE = "type"; - field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS"; - field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS"; - field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES"; - field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS"; - field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS"; - field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS"; - field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS"; - field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE"; - field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS"; - field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN"; - field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM"; - field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST"; - field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL"; - field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP"; - field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT"; - field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE"; - field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST"; - field public static final java.lang.String TYPE_STATION = "TYPE_STATION"; - field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK"; - field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE"; - field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON"; - field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES"; + field public static final int INTERACTION_TYPE_FANS = 3; // 0x3 + field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2 + field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4 + field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1 + field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5 + field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6 + field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0 + field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2 + field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0 + field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1 + field public static final int TYPE_ALBUM = 8; // 0x8 + field public static final int TYPE_ARTIST = 9; // 0x9 + field public static final int TYPE_CHANNEL = 6; // 0x6 + field public static final int TYPE_CLIP = 4; // 0x4 + field public static final int TYPE_EVENT = 5; // 0x5 + field public static final int TYPE_MOVIE = 0; // 0x0 + field public static final int TYPE_PLAYLIST = 10; // 0xa + field public static final int TYPE_STATION = 11; // 0xb + field public static final int TYPE_TRACK = 7; // 0x7 + field public static final int TYPE_TV_EPISODE = 3; // 0x3 + field public static final int TYPE_TV_SEASON = 2; // 0x2 + field public static final int TYPE_TV_SERIES = 1; // 0x1 } public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns { @@ -24761,10 +24787,10 @@ package android.media.tv { field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program"; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE"; - field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW"; - field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT"; - field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST"; + field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0 + field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2 + field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1 + field public static final int WATCH_NEXT_TYPE_WATCHLIST = 3; // 0x3 } public final class TvInputInfo implements android.os.Parcelable { @@ -39997,7 +40023,7 @@ package android.telephony { method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String); method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String); method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String); - method public boolean isConcurrentVoiceAndDataAllowed(); + method public boolean isConcurrentVoiceAndDataSupported(); method public boolean isDataEnabled(); method public boolean isHearingAidCompatibilitySupported(); method public boolean isNetworkRoaming(); @@ -40010,7 +40036,7 @@ package android.telephony { method public deprecated boolean sendDialerCode(java.lang.String); method public void sendDialerSpecialCode(java.lang.String); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); - method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); + method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public void setDataEnabled(boolean); method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String); method public boolean setOperatorBrandOverride(java.lang.String); @@ -40086,14 +40112,17 @@ package android.telephony { field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3 field public static final int SIM_STATE_READY = 5; // 0x5 field public static final int SIM_STATE_UNKNOWN = 0; // 0x0 + field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe + field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff + field public static final int USSD_RETURN_SUCCESS = 100; // 0x64 field public static final java.lang.String VVM_TYPE_CVVM = "vvm_type_cvvm"; field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp"; } - public static abstract class TelephonyManager.OnReceiveUssdResponseCallback { - ctor public TelephonyManager.OnReceiveUssdResponseCallback(); - method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence); - method public void onReceiveUssdResponseFailed(java.lang.String, int); + public static abstract class TelephonyManager.UssdResponseCallback { + ctor public TelephonyManager.UssdResponseCallback(); + method public void onReceiveUssdResponse(android.telephony.TelephonyManager, java.lang.String, java.lang.CharSequence); + method public void onReceiveUssdResponseFailed(android.telephony.TelephonyManager, java.lang.String, int); } public abstract class VisualVoicemailService extends android.app.Service { @@ -41037,65 +41066,6 @@ package android.text { method public android.text.Editable newEditable(java.lang.CharSequence); } - public final class FontConfig implements android.os.Parcelable { - ctor public FontConfig(android.text.FontConfig.Family[], android.text.FontConfig.Alias[]); - method public int describeContents(); - method public android.text.FontConfig.Alias[] getAliases(); - method public android.text.FontConfig.Family[] getFamilies(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR; - } - - public static final class FontConfig.Alias implements android.os.Parcelable { - ctor public FontConfig.Alias(java.lang.String, java.lang.String, int); - method public int describeContents(); - method public java.lang.String getName(); - method public java.lang.String getToName(); - method public int getWeight(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR; - } - - public static final class FontConfig.Axis implements android.os.Parcelable { - ctor public FontConfig.Axis(int, float); - ctor public FontConfig.Axis(java.lang.String, float); - method public int describeContents(); - method public float getStyleValue(); - method public int getTag(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR; - } - - public static final class FontConfig.Family implements android.os.Parcelable { - ctor public FontConfig.Family(java.lang.String, android.text.FontConfig.Font[], java.lang.String, int); - method public int describeContents(); - method public android.text.FontConfig.Font[] getFonts(); - method public java.lang.String getLanguage(); - method public java.lang.String getName(); - method public int getVariant(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR; - field public static final int VARIANT_COMPACT = 1; // 0x1 - field public static final int VARIANT_DEFAULT = 0; // 0x0 - field public static final int VARIANT_ELEGANT = 2; // 0x2 - } - - public static final class FontConfig.Font implements android.os.Parcelable { - method public int describeContents(); - method public android.text.FontConfig.Axis[] getAxes(); - method public java.lang.String getFontName(); - method public int getTtcIndex(); - method public android.net.Uri getUri(); - method public int getWeight(); - method public boolean isItalic(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR; - } - - public final class FontManager { - method public android.text.FontConfig getSystemFonts(); - } - public abstract interface GetChars implements java.lang.CharSequence { method public abstract void getChars(int, int, char[], int); } @@ -41243,6 +41213,8 @@ package android.text { field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2 field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0 field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1 + field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1 + field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0 } public static final class Layout.Alignment extends java.lang.Enum { @@ -41444,7 +41416,7 @@ package android.text { method public android.text.StaticLayout.Builder setHyphenationFrequency(int); method public android.text.StaticLayout.Builder setIncludePad(boolean); method public android.text.StaticLayout.Builder setIndents(int[], int[]); - method public android.text.StaticLayout.Builder setJustify(boolean); + method public android.text.StaticLayout.Builder setJustificationMode(int); method public android.text.StaticLayout.Builder setLineSpacing(float, float); method public android.text.StaticLayout.Builder setMaxLines(int); method public android.text.StaticLayout.Builder setText(java.lang.CharSequence); @@ -51254,7 +51226,7 @@ package android.widget { method public boolean getIncludeFontPadding(); method public android.os.Bundle getInputExtras(boolean); method public int getInputType(); - method public boolean getJustify(); + method public int getJustificationMode(); method public final android.text.method.KeyListener getKeyListener(); method public final android.text.Layout getLayout(); method public float getLetterSpacing(); @@ -51349,7 +51321,7 @@ package android.widget { method public void setExtractedText(android.view.inputmethod.ExtractedText); method public void setFilters(android.text.InputFilter[]); method public void setFontFeatureSettings(java.lang.String); - method public boolean setFontVariationSettings(java.lang.String); + method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method protected boolean setFrame(int, int, int, int); method public void setFreezesText(boolean); method public void setGravity(int); @@ -51367,7 +51339,7 @@ package android.widget { method public void setIncludeFontPadding(boolean); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void setInputType(int); - method public void setJustify(boolean); + method public void setJustificationMode(int); method public void setKeyListener(android.text.method.KeyListener); method public void setLetterSpacing(float); method public void setLineSpacing(float, float); diff --git a/api/system-current.txt b/api/system-current.txt index 13e843f84f02..2b2cceec7b05 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -53,6 +53,7 @@ package android { field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE"; field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE"; field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS"; + field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE"; field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"; field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE"; field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE"; @@ -6435,6 +6436,11 @@ package android.app.admin { field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE"; } + public class DeviceAdminService extends android.app.Service { + ctor public DeviceAdminService(); + method public final android.os.IBinder onBind(android.content.Intent); + } + public class DevicePolicyManager { method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int); method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); @@ -6622,6 +6628,7 @@ package android.app.admin { field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED"; field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"; field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED"; + field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE"; field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED"; field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL"; @@ -9380,7 +9387,6 @@ package android.content { field public static final java.lang.String DOWNLOAD_SERVICE = "download"; field public static final java.lang.String DROPBOX_SERVICE = "dropbox"; field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint"; - field public static final java.lang.String FONT_SERVICE = "font"; field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties"; field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control"; field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method"; @@ -9781,6 +9787,8 @@ 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_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED"; + field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED"; 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"; @@ -10000,8 +10008,9 @@ package android.content { field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME"; field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"; field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME"; - field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM"; + field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM"; field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT"; + field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX"; field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE"; field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT"; field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE"; @@ -10362,6 +10371,7 @@ package android.content { } public abstract interface ServiceConnection { + method public default void onBindingDead(android.content.ComponentName); method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder); method public abstract void onServiceDisconnected(android.content.ComponentName); } @@ -10957,12 +10967,12 @@ package android.content.pm { ctor public LauncherApps.ShortcutQuery(); method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName); method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long); - method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent); + method public deprecated android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent); method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String); method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int); method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>); field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4 - field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10 + field public static final deprecated int FLAG_MATCH_CHOOSER = 16; // 0x10 field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1 field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8 field public static final int FLAG_MATCH_PINNED = 2; // 0x2 @@ -11288,6 +11298,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen"; field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods"; field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback"; + field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv"; field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper"; field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location"; @@ -11606,9 +11617,9 @@ package android.content.pm { method public int describeContents(); method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); - method public android.content.ComponentName[] getChooserComponentNames(); - method public android.os.PersistableBundle getChooserExtras(); - method public android.content.IntentFilter[] getChooserIntentFilters(); + method public deprecated android.content.ComponentName[] getChooserComponentNames(); + method public deprecated android.os.PersistableBundle getChooserExtras(); + method public deprecated android.content.IntentFilter[] getChooserIntentFilters(); method public java.lang.CharSequence getDisabledMessage(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); @@ -11621,7 +11632,7 @@ package android.content.pm { method public java.lang.CharSequence getShortLabel(); method public android.os.UserHandle getUserHandle(); method public boolean hasKeyFieldsOnly(); - method public boolean isChooser(); + method public deprecated boolean isChooser(); method public boolean isDeclaredInManifest(); method public boolean isDynamic(); method public boolean isEnabled(); @@ -11634,11 +11645,11 @@ package android.content.pm { public static class ShortcutInfo.Builder { ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String); - method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName); + method public deprecated android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName); method public android.content.pm.ShortcutInfo build(); method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName); method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>); - method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle); + method public deprecated android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence); method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon); @@ -13425,7 +13436,7 @@ package android.graphics { enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP; } - public final class Color { + public class Color { ctor public Color(); method public static int HSVToColor(float[]); method public static int HSVToColor(int, float[]); @@ -13964,7 +13975,7 @@ package android.graphics { method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(java.lang.String); - method public boolean setFontVariationSettings(java.lang.String); + method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method public void setHinting(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); @@ -14498,8 +14509,8 @@ package android.graphics { method public static android.graphics.Typeface.Builder obtain(); method public void recycle(); method public void reset(); - method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String); - method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]); + method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); method public android.graphics.Typeface.Builder setItalic(int); method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String); method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File); @@ -15109,6 +15120,21 @@ package android.graphics.fonts { field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR; } + public final class FontVariationAxis implements android.os.Parcelable { + ctor public FontVariationAxis(java.lang.String, float) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public int describeContents(); + method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public float getStyleValue(); + method public java.lang.String getTag(); + method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontVariationAxis> CREATOR; + } + + public static class FontVariationAxis.InvalidFormatException extends java.lang.Exception { + ctor public FontVariationAxis.InvalidFormatException(java.lang.String); + } + } package android.graphics.pdf { @@ -17432,11 +17458,11 @@ package android.hardware.usb { ctor public UsbRequest(); method public boolean cancel(); method public void close(); - method public boolean enqueue(java.nio.ByteBuffer); method public java.lang.Object getClientData(); method public android.hardware.usb.UsbEndpoint getEndpoint(); method public boolean initialize(android.hardware.usb.UsbDeviceConnection, android.hardware.usb.UsbEndpoint); method public deprecated boolean queue(java.nio.ByteBuffer, int); + method public boolean queue(java.nio.ByteBuffer); method public void setClientData(java.lang.Object); } @@ -22831,6 +22857,7 @@ package android.media { method public void adjustStreamVolume(int, int, int); method public void adjustSuggestedStreamVolume(int, int, int); method public void adjustVolume(int, int); + method public int dispatchAudioFocusChange(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy); method public void dispatchMediaKeyEvent(android.view.KeyEvent); method public int generateAudioSessionId(); method public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations(); @@ -24782,6 +24809,7 @@ package android.media { method public void setProfile(android.media.CamcorderProfile); method public void setVideoEncoder(int) throws java.lang.IllegalStateException; method public void setVideoEncodingBitRate(int); + method public void setVideoEncodingProfileLevel(int, int); method public void setVideoFrameRate(int) throws java.lang.IllegalStateException; method public void setVideoSize(int, int) throws java.lang.IllegalStateException; method public void setVideoSource(int) throws java.lang.IllegalStateException; @@ -25832,8 +25860,10 @@ package android.media.audiopolicy { public static abstract class AudioPolicy.AudioPolicyFocusListener { ctor public AudioPolicy.AudioPolicyFocusListener(); + method public void onAudioFocusAbandon(android.media.AudioFocusInfo); method public void onAudioFocusGrant(android.media.AudioFocusInfo, int); method public void onAudioFocusLoss(android.media.AudioFocusInfo, boolean); + method public void onAudioFocusRequest(android.media.AudioFocusInfo, int); } public static abstract class AudioPolicy.AudioPolicyStatusListener { @@ -25848,6 +25878,7 @@ package android.media.audiopolicy { method public android.media.audiopolicy.AudioPolicy build(); method public void setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener); method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener); + method public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); method public android.media.audiopolicy.AudioPolicy.Builder setLooper(android.os.Looper) throws java.lang.IllegalArgumentException; } @@ -26472,19 +26503,19 @@ package android.media.tv { } public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns { - field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9"; - field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1"; - field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3"; - field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2"; - field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE"; - field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION"; - field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT"; - field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri"; + field public static final int ASPECT_RATIO_16_9 = 0; // 0x0 + field public static final int ASPECT_RATIO_1_1 = 2; // 0x2 + field public static final int ASPECT_RATIO_2_3 = 3; // 0x3 + field public static final int ASPECT_RATIO_3_2 = 1; // 0x1 + field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0 + field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1 + field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2 field public static final java.lang.String COLUMN_AUTHOR = "author"; field public static final java.lang.String COLUMN_AVAILABILITY = "availability"; field public static final java.lang.String COLUMN_BROWSABLE = "browsable"; field public static final java.lang.String COLUMN_CONTENT_ID = "content_id"; field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis"; + field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri"; field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count"; field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type"; field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"; @@ -26502,28 +26533,28 @@ package android.media.tv { field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio"; field public static final java.lang.String COLUMN_TRANSIENT = "transient"; field public static final java.lang.String COLUMN_TYPE = "type"; - field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS"; - field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS"; - field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES"; - field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS"; - field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS"; - field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS"; - field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS"; - field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE"; - field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS"; - field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN"; - field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM"; - field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST"; - field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL"; - field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP"; - field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT"; - field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE"; - field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST"; - field public static final java.lang.String TYPE_STATION = "TYPE_STATION"; - field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK"; - field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE"; - field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON"; - field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES"; + field public static final int INTERACTION_TYPE_FANS = 3; // 0x3 + field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2 + field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4 + field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1 + field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5 + field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6 + field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0 + field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2 + field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0 + field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1 + field public static final int TYPE_ALBUM = 8; // 0x8 + field public static final int TYPE_ARTIST = 9; // 0x9 + field public static final int TYPE_CHANNEL = 6; // 0x6 + field public static final int TYPE_CLIP = 4; // 0x4 + field public static final int TYPE_EVENT = 5; // 0x5 + field public static final int TYPE_MOVIE = 0; // 0x0 + field public static final int TYPE_PLAYLIST = 10; // 0xa + field public static final int TYPE_STATION = 11; // 0xb + field public static final int TYPE_TRACK = 7; // 0x7 + field public static final int TYPE_TV_EPISODE = 3; // 0x3 + field public static final int TYPE_TV_SEASON = 2; // 0x2 + field public static final int TYPE_TV_SERIES = 1; // 0x1 } public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns { @@ -26703,10 +26734,10 @@ package android.media.tv { field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program"; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE"; - field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW"; - field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT"; - field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST"; + field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0 + field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2 + field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1 + field public static final int WATCH_NEXT_TYPE_WATCHLIST = 3; // 0x3 } public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns { @@ -40449,6 +40480,36 @@ package android.service.quicksettings { } +package android.service.resolver { + + public abstract class ResolverRankerService extends android.app.Service { + ctor public ResolverRankerService(); + method public android.os.IBinder onBind(android.content.Intent); + method public void onPredictSharingProbabilities(java.util.List<android.service.resolver.ResolverTarget>); + method public void onTrainRankingModel(java.util.List<android.service.resolver.ResolverTarget>, int); + field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE"; + field public static final java.lang.String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService"; + } + + public final class ResolverTarget implements android.os.Parcelable { + ctor public ResolverTarget(); + method public int describeContents(); + method public float getChooserScore(); + method public float getLaunchScore(); + method public float getRecencyScore(); + method public float getSelectProbability(); + method public float getTimeSpentScore(); + method public void setChooserScore(float); + method public void setLaunchScore(float); + method public void setRecencyScore(float); + method public void setSelectProbability(float); + method public void setTimeSpentScore(float); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.resolver.ResolverTarget> CREATOR; + } + +} + package android.service.restrictions { public abstract class RestrictionsReceiver extends android.content.BroadcastReceiver { @@ -43399,7 +43460,7 @@ package android.telephony { method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String); method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String); method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String); - method public boolean isConcurrentVoiceAndDataAllowed(); + method public boolean isConcurrentVoiceAndDataSupported(); method public boolean isDataConnectivityPossible(); method public boolean isDataEnabled(); method public boolean isHearingAidCompatibilitySupported(); @@ -43420,7 +43481,7 @@ package android.telephony { method public deprecated boolean sendDialerCode(java.lang.String); method public void sendDialerSpecialCode(java.lang.String); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); - method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); + method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); method public void setDataEnabled(boolean); method public void setDataEnabled(int, boolean); @@ -43512,14 +43573,17 @@ package android.telephony { field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3 field public static final int SIM_STATE_READY = 5; // 0x5 field public static final int SIM_STATE_UNKNOWN = 0; // 0x0 + field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe + field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff + field public static final int USSD_RETURN_SUCCESS = 100; // 0x64 field public static final java.lang.String VVM_TYPE_CVVM = "vvm_type_cvvm"; field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp"; } - public static abstract class TelephonyManager.OnReceiveUssdResponseCallback { - ctor public TelephonyManager.OnReceiveUssdResponseCallback(); - method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence); - method public void onReceiveUssdResponseFailed(java.lang.String, int); + public static abstract class TelephonyManager.UssdResponseCallback { + ctor public TelephonyManager.UssdResponseCallback(); + method public void onReceiveUssdResponse(android.telephony.TelephonyManager, java.lang.String, java.lang.CharSequence); + method public void onReceiveUssdResponseFailed(android.telephony.TelephonyManager, java.lang.String, int); } public abstract class VisualVoicemailService extends android.app.Service { @@ -44495,65 +44559,6 @@ package android.text { method public android.text.Editable newEditable(java.lang.CharSequence); } - public final class FontConfig implements android.os.Parcelable { - ctor public FontConfig(android.text.FontConfig.Family[], android.text.FontConfig.Alias[]); - method public int describeContents(); - method public android.text.FontConfig.Alias[] getAliases(); - method public android.text.FontConfig.Family[] getFamilies(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR; - } - - public static final class FontConfig.Alias implements android.os.Parcelable { - ctor public FontConfig.Alias(java.lang.String, java.lang.String, int); - method public int describeContents(); - method public java.lang.String getName(); - method public java.lang.String getToName(); - method public int getWeight(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR; - } - - public static final class FontConfig.Axis implements android.os.Parcelable { - ctor public FontConfig.Axis(int, float); - ctor public FontConfig.Axis(java.lang.String, float); - method public int describeContents(); - method public float getStyleValue(); - method public int getTag(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR; - } - - public static final class FontConfig.Family implements android.os.Parcelable { - ctor public FontConfig.Family(java.lang.String, android.text.FontConfig.Font[], java.lang.String, int); - method public int describeContents(); - method public android.text.FontConfig.Font[] getFonts(); - method public java.lang.String getLanguage(); - method public java.lang.String getName(); - method public int getVariant(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR; - field public static final int VARIANT_COMPACT = 1; // 0x1 - field public static final int VARIANT_DEFAULT = 0; // 0x0 - field public static final int VARIANT_ELEGANT = 2; // 0x2 - } - - public static final class FontConfig.Font implements android.os.Parcelable { - method public int describeContents(); - method public android.text.FontConfig.Axis[] getAxes(); - method public java.lang.String getFontName(); - method public int getTtcIndex(); - method public android.net.Uri getUri(); - method public int getWeight(); - method public boolean isItalic(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR; - } - - public final class FontManager { - method public android.text.FontConfig getSystemFonts(); - } - public abstract interface GetChars implements java.lang.CharSequence { method public abstract void getChars(int, int, char[], int); } @@ -44701,6 +44706,8 @@ package android.text { field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2 field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0 field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1 + field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1 + field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0 } public static final class Layout.Alignment extends java.lang.Enum { @@ -44902,7 +44909,7 @@ package android.text { method public android.text.StaticLayout.Builder setHyphenationFrequency(int); method public android.text.StaticLayout.Builder setIncludePad(boolean); method public android.text.StaticLayout.Builder setIndents(int[], int[]); - method public android.text.StaticLayout.Builder setJustify(boolean); + method public android.text.StaticLayout.Builder setJustificationMode(int); method public android.text.StaticLayout.Builder setLineSpacing(float, float); method public android.text.StaticLayout.Builder setMaxLines(int); method public android.text.StaticLayout.Builder setText(java.lang.CharSequence); @@ -55080,7 +55087,7 @@ package android.widget { method public boolean getIncludeFontPadding(); method public android.os.Bundle getInputExtras(boolean); method public int getInputType(); - method public boolean getJustify(); + method public int getJustificationMode(); method public final android.text.method.KeyListener getKeyListener(); method public final android.text.Layout getLayout(); method public float getLetterSpacing(); @@ -55175,7 +55182,7 @@ package android.widget { method public void setExtractedText(android.view.inputmethod.ExtractedText); method public void setFilters(android.text.InputFilter[]); method public void setFontFeatureSettings(java.lang.String); - method public boolean setFontVariationSettings(java.lang.String); + method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method protected boolean setFrame(int, int, int, int); method public void setFreezesText(boolean); method public void setGravity(int); @@ -55193,7 +55200,7 @@ package android.widget { method public void setIncludeFontPadding(boolean); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void setInputType(int); - method public void setJustify(boolean); + method public void setJustificationMode(int); method public void setKeyListener(android.text.method.KeyListener); method public void setLetterSpacing(float); method public void setLineSpacing(float, float); diff --git a/api/test-current.txt b/api/test-current.txt index 414c4b31fbf0..f0bfb5cc911f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6251,6 +6251,11 @@ package android.app.admin { field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE"; } + public class DeviceAdminService extends android.app.Service { + ctor public DeviceAdminService(); + method public final android.os.IBinder onBind(android.content.Intent); + } + public class DevicePolicyManager { method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int); method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); @@ -6426,6 +6431,7 @@ package android.app.admin { field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED"; field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"; field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED"; + field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE"; field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED"; field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL"; @@ -8915,7 +8921,6 @@ package android.content { field public static final java.lang.String DOWNLOAD_SERVICE = "download"; field public static final java.lang.String DROPBOX_SERVICE = "dropbox"; field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint"; - field public static final java.lang.String FONT_SERVICE = "font"; field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties"; field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method"; field public static final java.lang.String INPUT_SERVICE = "input"; @@ -9303,6 +9308,8 @@ 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_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED"; + field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED"; 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"; @@ -9502,8 +9509,9 @@ package android.content { field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT"; field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME"; field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"; - field public static final deprecated java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM"; + field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM"; field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT"; + field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX"; field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE"; field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT"; field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE"; @@ -9862,6 +9870,7 @@ package android.content { } public abstract interface ServiceConnection { + method public default void onBindingDead(android.content.ComponentName); method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder); method public abstract void onServiceDisconnected(android.content.ComponentName); } @@ -10369,12 +10378,12 @@ package android.content.pm { ctor public LauncherApps.ShortcutQuery(); method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName); method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long); - method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent); + method public deprecated android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent); method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String); method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int); method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>); field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4 - field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10 + field public static final deprecated int FLAG_MATCH_CHOOSER = 16; // 0x10 field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1 field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8 field public static final int FLAG_MATCH_PINNED = 2; // 0x2 @@ -10674,6 +10683,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen"; field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods"; field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback"; + field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv"; field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper"; field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location"; @@ -10928,9 +10938,9 @@ package android.content.pm { method public int describeContents(); method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); - method public android.content.ComponentName[] getChooserComponentNames(); - method public android.os.PersistableBundle getChooserExtras(); - method public android.content.IntentFilter[] getChooserIntentFilters(); + method public deprecated android.content.ComponentName[] getChooserComponentNames(); + method public deprecated android.os.PersistableBundle getChooserExtras(); + method public deprecated android.content.IntentFilter[] getChooserIntentFilters(); method public java.lang.CharSequence getDisabledMessage(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); @@ -10943,7 +10953,7 @@ package android.content.pm { method public java.lang.CharSequence getShortLabel(); method public android.os.UserHandle getUserHandle(); method public boolean hasKeyFieldsOnly(); - method public boolean isChooser(); + method public deprecated boolean isChooser(); method public boolean isDeclaredInManifest(); method public boolean isDynamic(); method public boolean isEnabled(); @@ -10956,11 +10966,11 @@ package android.content.pm { public static class ShortcutInfo.Builder { ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String); - method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName); + method public deprecated android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName); method public android.content.pm.ShortcutInfo build(); method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName); method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>); - method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle); + method public deprecated android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence); method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle); method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon); @@ -12743,7 +12753,7 @@ package android.graphics { enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP; } - public final class Color { + public class Color { ctor public Color(); method public static int HSVToColor(float[]); method public static int HSVToColor(int, float[]); @@ -13282,7 +13292,7 @@ package android.graphics { method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(java.lang.String); - method public boolean setFontVariationSettings(java.lang.String); + method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method public void setHinting(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); @@ -13816,8 +13826,8 @@ package android.graphics { method public static android.graphics.Typeface.Builder obtain(); method public void recycle(); method public void reset(); - method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String); - method public android.graphics.Typeface.Builder setFontVariationSettings(android.text.FontConfig.Axis[]); + method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); method public android.graphics.Typeface.Builder setItalic(int); method public android.graphics.Typeface.Builder setSourceFromAsset(android.content.res.AssetManager, java.lang.String); method public android.graphics.Typeface.Builder setSourceFromFile(java.io.File); @@ -14428,6 +14438,21 @@ package android.graphics.fonts { field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR; } + public final class FontVariationAxis implements android.os.Parcelable { + ctor public FontVariationAxis(java.lang.String, float) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public int describeContents(); + method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; + method public float getStyleValue(); + method public java.lang.String getTag(); + method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontVariationAxis> CREATOR; + } + + public static class FontVariationAxis.InvalidFormatException extends java.lang.Exception { + ctor public FontVariationAxis.InvalidFormatException(java.lang.String); + } + } package android.graphics.pdf { @@ -16027,11 +16052,11 @@ package android.hardware.usb { ctor public UsbRequest(); method public boolean cancel(); method public void close(); - method public boolean enqueue(java.nio.ByteBuffer); method public java.lang.Object getClientData(); method public android.hardware.usb.UsbEndpoint getEndpoint(); method public boolean initialize(android.hardware.usb.UsbDeviceConnection, android.hardware.usb.UsbEndpoint); method public deprecated boolean queue(java.nio.ByteBuffer, int); + method public boolean queue(java.nio.ByteBuffer); method public void setClientData(java.lang.Object); } @@ -23102,6 +23127,7 @@ package android.media { method public void setProfile(android.media.CamcorderProfile); method public void setVideoEncoder(int) throws java.lang.IllegalStateException; method public void setVideoEncodingBitRate(int); + method public void setVideoEncodingProfileLevel(int, int); method public void setVideoFrameRate(int) throws java.lang.IllegalStateException; method public void setVideoSize(int, int) throws java.lang.IllegalStateException; method public void setVideoSource(int) throws java.lang.IllegalStateException; @@ -24644,19 +24670,19 @@ package android.media.tv { } public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns { - field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9"; - field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1"; - field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3"; - field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2"; - field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE"; - field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION"; - field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT"; - field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri"; + field public static final int ASPECT_RATIO_16_9 = 0; // 0x0 + field public static final int ASPECT_RATIO_1_1 = 2; // 0x2 + field public static final int ASPECT_RATIO_2_3 = 3; // 0x3 + field public static final int ASPECT_RATIO_3_2 = 1; // 0x1 + field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0 + field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1 + field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2 field public static final java.lang.String COLUMN_AUTHOR = "author"; field public static final java.lang.String COLUMN_AVAILABILITY = "availability"; field public static final java.lang.String COLUMN_BROWSABLE = "browsable"; field public static final java.lang.String COLUMN_CONTENT_ID = "content_id"; field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis"; + field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri"; field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count"; field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type"; field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"; @@ -24674,28 +24700,28 @@ package android.media.tv { field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio"; field public static final java.lang.String COLUMN_TRANSIENT = "transient"; field public static final java.lang.String COLUMN_TYPE = "type"; - field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS"; - field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS"; - field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES"; - field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS"; - field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS"; - field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS"; - field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS"; - field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE"; - field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS"; - field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN"; - field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM"; - field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST"; - field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL"; - field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP"; - field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT"; - field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE"; - field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST"; - field public static final java.lang.String TYPE_STATION = "TYPE_STATION"; - field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK"; - field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE"; - field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON"; - field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES"; + field public static final int INTERACTION_TYPE_FANS = 3; // 0x3 + field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2 + field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4 + field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1 + field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5 + field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6 + field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0 + field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2 + field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0 + field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1 + field public static final int TYPE_ALBUM = 8; // 0x8 + field public static final int TYPE_ARTIST = 9; // 0x9 + field public static final int TYPE_CHANNEL = 6; // 0x6 + field public static final int TYPE_CLIP = 4; // 0x4 + field public static final int TYPE_EVENT = 5; // 0x5 + field public static final int TYPE_MOVIE = 0; // 0x0 + field public static final int TYPE_PLAYLIST = 10; // 0xa + field public static final int TYPE_STATION = 11; // 0xb + field public static final int TYPE_TRACK = 7; // 0x7 + field public static final int TYPE_TV_EPISODE = 3; // 0x3 + field public static final int TYPE_TV_SEASON = 2; // 0x2 + field public static final int TYPE_TV_SERIES = 1; // 0x1 } public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns { @@ -24874,10 +24900,10 @@ package android.media.tv { field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program"; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE"; - field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW"; - field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT"; - field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST"; + field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0 + field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2 + field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1 + field public static final int WATCH_NEXT_TYPE_WATCHLIST = 3; // 0x3 } public final class TvInputInfo implements android.os.Parcelable { @@ -37528,6 +37554,7 @@ package android.service.quicksettings { ctor public TileService(); method public final android.service.quicksettings.Tile getQsTile(); method public final boolean isLocked(); + method public static boolean isQuickSettingsSupported(); method public final boolean isSecure(); method public android.os.IBinder onBind(android.content.Intent); method public void onClick(); @@ -40200,7 +40227,7 @@ package android.telephony { method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String); method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String); method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String); - method public boolean isConcurrentVoiceAndDataAllowed(); + method public boolean isConcurrentVoiceAndDataSupported(); method public boolean isDataEnabled(); method public boolean isHearingAidCompatibilitySupported(); method public boolean isNetworkRoaming(); @@ -40213,7 +40240,7 @@ package android.telephony { method public deprecated boolean sendDialerCode(java.lang.String); method public void sendDialerSpecialCode(java.lang.String); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); - method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); + method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public void setDataEnabled(boolean); method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String); method public boolean setOperatorBrandOverride(java.lang.String); @@ -40289,14 +40316,17 @@ package android.telephony { field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3 field public static final int SIM_STATE_READY = 5; // 0x5 field public static final int SIM_STATE_UNKNOWN = 0; // 0x0 + field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe + field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff + field public static final int USSD_RETURN_SUCCESS = 100; // 0x64 field public static final java.lang.String VVM_TYPE_CVVM = "vvm_type_cvvm"; field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp"; } - public static abstract class TelephonyManager.OnReceiveUssdResponseCallback { - ctor public TelephonyManager.OnReceiveUssdResponseCallback(); - method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence); - method public void onReceiveUssdResponseFailed(java.lang.String, int); + public static abstract class TelephonyManager.UssdResponseCallback { + ctor public TelephonyManager.UssdResponseCallback(); + method public void onReceiveUssdResponse(android.telephony.TelephonyManager, java.lang.String, java.lang.CharSequence); + method public void onReceiveUssdResponseFailed(android.telephony.TelephonyManager, java.lang.String, int); } public abstract class VisualVoicemailService extends android.app.Service { @@ -41244,65 +41274,6 @@ package android.text { method public android.text.Editable newEditable(java.lang.CharSequence); } - public final class FontConfig implements android.os.Parcelable { - ctor public FontConfig(android.text.FontConfig.Family[], android.text.FontConfig.Alias[]); - method public int describeContents(); - method public android.text.FontConfig.Alias[] getAliases(); - method public android.text.FontConfig.Family[] getFamilies(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR; - } - - public static final class FontConfig.Alias implements android.os.Parcelable { - ctor public FontConfig.Alias(java.lang.String, java.lang.String, int); - method public int describeContents(); - method public java.lang.String getName(); - method public java.lang.String getToName(); - method public int getWeight(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR; - } - - public static final class FontConfig.Axis implements android.os.Parcelable { - ctor public FontConfig.Axis(int, float); - ctor public FontConfig.Axis(java.lang.String, float); - method public int describeContents(); - method public float getStyleValue(); - method public int getTag(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR; - } - - public static final class FontConfig.Family implements android.os.Parcelable { - ctor public FontConfig.Family(java.lang.String, android.text.FontConfig.Font[], java.lang.String, int); - method public int describeContents(); - method public android.text.FontConfig.Font[] getFonts(); - method public java.lang.String getLanguage(); - method public java.lang.String getName(); - method public int getVariant(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR; - field public static final int VARIANT_COMPACT = 1; // 0x1 - field public static final int VARIANT_DEFAULT = 0; // 0x0 - field public static final int VARIANT_ELEGANT = 2; // 0x2 - } - - public static final class FontConfig.Font implements android.os.Parcelable { - method public int describeContents(); - method public android.text.FontConfig.Axis[] getAxes(); - method public java.lang.String getFontName(); - method public int getTtcIndex(); - method public android.net.Uri getUri(); - method public int getWeight(); - method public boolean isItalic(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR; - } - - public final class FontManager { - method public android.text.FontConfig getSystemFonts(); - } - public abstract interface GetChars implements java.lang.CharSequence { method public abstract void getChars(int, int, char[], int); } @@ -41450,6 +41421,8 @@ package android.text { field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2 field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0 field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1 + field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1 + field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0 } public static final class Layout.Alignment extends java.lang.Enum { @@ -41651,7 +41624,7 @@ package android.text { method public android.text.StaticLayout.Builder setHyphenationFrequency(int); method public android.text.StaticLayout.Builder setIncludePad(boolean); method public android.text.StaticLayout.Builder setIndents(int[], int[]); - method public android.text.StaticLayout.Builder setJustify(boolean); + method public android.text.StaticLayout.Builder setJustificationMode(int); method public android.text.StaticLayout.Builder setLineSpacing(float, float); method public android.text.StaticLayout.Builder setMaxLines(int); method public android.text.StaticLayout.Builder setText(java.lang.CharSequence); @@ -51644,7 +51617,7 @@ package android.widget { method public boolean getIncludeFontPadding(); method public android.os.Bundle getInputExtras(boolean); method public int getInputType(); - method public boolean getJustify(); + method public int getJustificationMode(); method public final android.text.method.KeyListener getKeyListener(); method public final android.text.Layout getLayout(); method public float getLetterSpacing(); @@ -51739,7 +51712,7 @@ package android.widget { method public void setExtractedText(android.view.inputmethod.ExtractedText); method public void setFilters(android.text.InputFilter[]); method public void setFontFeatureSettings(java.lang.String); - method public boolean setFontVariationSettings(java.lang.String); + method public boolean setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method protected boolean setFrame(int, int, int, int); method public void setFreezesText(boolean); method public void setGravity(int); @@ -51757,7 +51730,7 @@ package android.widget { method public void setIncludeFontPadding(boolean); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void setInputType(int); - method public void setJustify(boolean); + method public void setJustificationMode(int); method public void setKeyListener(android.text.method.KeyListener); method public void setLetterSpacing(float); method public void setLineSpacing(float, float); diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 3a92b9e74144..0e2c13ee1719 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -26,7 +26,8 @@ LOCAL_SHARED_LIBRARIES := \ libGLESv1_CM \ libgui \ libOpenSLES \ - libtinyalsa + libtinyalsa \ + libbase LOCAL_MODULE:= bootanimation diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index a6d2986e185a..2435ffadd879 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -38,6 +38,8 @@ #include <utils/Log.h> #include <utils/SystemClock.h> +#include <android-base/properties.h> + #include <ui/PixelFormat.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -67,6 +69,9 @@ namespace android { static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip"; static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip"; static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip"; +static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip"; +static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip"; + static const char SYSTEM_DATA_DIR_PATH[] = "/data/system"; static const char SYSTEM_TIME_DIR_NAME[] = "time"; static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time"; @@ -106,7 +111,13 @@ BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccu mSession = new SurfaceComposerClient(); // If the system has already booted, the animation is not being used for a boot. - mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0); + mSystemBoot = !android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false); + std::string powerCtl = android::base::GetProperty("sys.powerctl", ""); + if (powerCtl.empty()) { + mShuttingDown = false; + } else { + mShuttingDown = true; + } } void BootAnimation::onFirstRef() { @@ -314,16 +325,23 @@ status_t BootAnimation::readyToRun() { char decrypt[PROPERTY_VALUE_MAX]; property_get("vold.decrypt", decrypt, ""); - bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt); + bool encryptedAnimation = atoi(decrypt) != 0 || + !strcmp("trigger_restart_min_framework", decrypt); - if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) { + if (!mShuttingDown && encryptedAnimation && + (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) { mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE; + return NO_ERROR; } - else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) { - mZipFileName = OEM_BOOTANIMATION_FILE; - } - else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) { - mZipFileName = SYSTEM_BOOTANIMATION_FILE; + static const char* bootFiles[] = {OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE}; + static const char* shutdownFiles[] = + {OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE}; + + for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) { + if (access(f, R_OK) == 0) { + mZipFileName = f; + return NO_ERROR; + } } return NO_ERROR; } @@ -1047,7 +1065,9 @@ bool BootAnimation::playSoundsAllowed() const { if (!mSystemBoot) { return false; } - + if (mShuttingDown) { // no audio while shutting down + return false; + } // Read the system property to see if we should play the sound. // If it's not present, default to allowed. if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) { @@ -1073,7 +1093,7 @@ bool BootAnimation::updateIsTimeAccurate() { if (mTimeIsAccurate) { return true; } - + if (mShuttingDown) return true; struct stat statResult; if(stat(TIME_FORMAT_12_HOUR_FLAG_FILE_PATH, &statResult) == 0) { diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index f1fc98e10c1e..181ef1c596d1 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -163,6 +163,7 @@ private: bool mTimeIsAccurate; bool mTimeFormat12Hour; bool mSystemBoot; + bool mShuttingDown; String8 mZipFileName; SortedVector<String8> mLoadedFiles; sp<TimeCheckThread> mTimeCheckThread = nullptr; diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc index 7344ba74f70b..469c9646a4aa 100644 --- a/cmds/bootanimation/bootanim.rc +++ b/cmds/bootanimation/bootanim.rc @@ -1,7 +1,7 @@ service bootanim /system/bin/bootanimation - class core + class core animation user graphics group graphics audio disabled oneshot - writepid /dev/stune/top-app/tasks
\ No newline at end of file + writepid /dev/stune/top-app/tasks diff --git a/compiled-classes-phone b/compiled-classes-phone index ea8f4a4d87fa..1a19b2ce2de5 100644 --- a/compiled-classes-phone +++ b/compiled-classes-phone @@ -4061,7 +4061,6 @@ android.text.FontConfig$Family android.text.FontConfig$Family$1 android.text.FontConfig$Font android.text.FontConfig$Font$1 -android.text.FontManager android.text.GetChars android.text.GraphicsOperations android.text.Html @@ -5501,8 +5500,6 @@ com.android.internal.content.PackageHelper com.android.internal.content.PackageMonitor com.android.internal.content.ReferrerIntent com.android.internal.content.ReferrerIntent$1 -com.android.internal.font.IFontManager -com.android.internal.font.IFontManager$Stub com.android.internal.graphics.drawable.AnimationScaleListDrawable com.android.internal.graphics.drawable.AnimationScaleListDrawable$AnimationScaleListState com.android.internal.hardware.AmbientDisplayConfiguration diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 5c7a12cf5eb9..fe496e398988 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -431,12 +431,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // Force all the animations to end when the duration scale is 0. private void forceToEnd() { - // TODO: Below is commented out to temp work around b/36241584, uncomment this when it's - // fixed. -// if (mEndCanBeCalled) { -// end(); -// return; -// } + if (mEndCanBeCalled) { + end(); + return; + } // Note: we don't want to combine this case with the end() method below because in // the case of developer calling end(), we still need to make sure end() is explicitly diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index dbf81f95d5c8..d432160ccfbf 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4159,14 +4159,25 @@ public class Activity extends ContextThemeWrapper mTaskDescription.setPrimaryColor(colorPrimary); } } - // For dev-preview only. - if (mTaskDescription.getBackgroundColor() == 0) { - int colorBackground = a.getColor( - com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0); - if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) { - mTaskDescription.setBackgroundColor(colorBackground); - } + + int colorBackground = a.getColor( + com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0); + if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) { + mTaskDescription.setBackgroundColor(colorBackground); + } + + final int statusBarColor = a.getColor( + com.android.internal.R.styleable.ActivityTaskDescription_statusBarColor, 0); + if (statusBarColor != 0) { + mTaskDescription.setStatusBarColor(statusBarColor); } + + final int navigationBarColor = a.getColor( + com.android.internal.R.styleable.ActivityTaskDescription_navigationBarColor, 0); + if (navigationBarColor != 0) { + mTaskDescription.setNavigationBarColor(navigationBarColor); + } + a.recycle(); setTaskDescription(mTaskDescription); } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4004bd6686b1..aede1bb67f80 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1145,6 +1145,8 @@ public class ActivityManager { private String mIconFilename; private int mColorPrimary; private int mColorBackground; + private int mStatusBarColor; + private int mNavigationBarColor; /** * Creates the TaskDescription to the specified values. @@ -1155,7 +1157,7 @@ public class ActivityManager { * opaque. */ public TaskDescription(String label, Bitmap icon, int colorPrimary) { - this(label, icon, null, colorPrimary, 0); + this(label, icon, null, colorPrimary, 0, 0, 0); if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) { throw new RuntimeException("A TaskDescription's primary color should be opaque"); } @@ -1168,7 +1170,7 @@ public class ActivityManager { * @param icon An icon that represents the current state of this activity. */ public TaskDescription(String label, Bitmap icon) { - this(label, icon, null, 0, 0); + this(label, icon, null, 0, 0, 0, 0); } /** @@ -1177,24 +1179,26 @@ public class ActivityManager { * @param label A label and description of the current state of this activity. */ public TaskDescription(String label) { - this(label, null, null, 0, 0); + this(label, null, null, 0, 0, 0, 0); } /** * Creates an empty TaskDescription. */ public TaskDescription() { - this(null, null, null, 0, 0); + this(null, null, null, 0, 0, 0, 0); } /** @hide */ public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary, - int colorBackground) { + int colorBackground, int statusBarColor, int navigationBarColor) { mLabel = label; mIcon = icon; mIconFilename = iconFilename; mColorPrimary = colorPrimary; mColorBackground = colorBackground; + mStatusBarColor = statusBarColor; + mNavigationBarColor = navigationBarColor; } /** @@ -1214,6 +1218,8 @@ public class ActivityManager { mIconFilename = other.mIconFilename; mColorPrimary = other.mColorPrimary; mColorBackground = other.mColorBackground; + mStatusBarColor = other.mStatusBarColor; + mNavigationBarColor = other.mNavigationBarColor; } private TaskDescription(Parcel source) { @@ -1253,6 +1259,20 @@ public class ActivityManager { } /** + * @hide + */ + public void setStatusBarColor(int statusBarColor) { + mStatusBarColor = statusBarColor; + } + + /** + * @hide + */ + public void setNavigationBarColor(int navigationBarColor) { + mNavigationBarColor = navigationBarColor; + } + + /** * Sets the icon for this task description. * @hide */ @@ -1325,6 +1345,20 @@ public class ActivityManager { return mColorBackground; } + /** + * @hide + */ + public int getStatusBarColor() { + return mStatusBarColor; + } + + /** + * @hide + */ + public int getNavigationBarColor() { + return mNavigationBarColor; + } + /** @hide */ public void saveToXml(XmlSerializer out) throws IOException { if (mLabel != null) { @@ -1377,6 +1411,8 @@ public class ActivityManager { } dest.writeInt(mColorPrimary); dest.writeInt(mColorBackground); + dest.writeInt(mStatusBarColor); + dest.writeInt(mNavigationBarColor); if (mIconFilename == null) { dest.writeInt(0); } else { @@ -1390,6 +1426,8 @@ public class ActivityManager { mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null; mColorPrimary = source.readInt(); mColorBackground = source.readInt(); + mStatusBarColor = source.readInt(); + mNavigationBarColor = source.readInt(); mIconFilename = source.readInt() > 0 ? source.readString() : null; } @@ -1407,7 +1445,9 @@ public class ActivityManager { public String toString() { return "TaskDescription Label: " + mLabel + " Icon: " + mIcon + " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary + - " colorBackground: " + mColorBackground; + " colorBackground: " + mColorBackground + + " statusBarColor: " + mColorBackground + + " navigationBarColor: " + mNavigationBarColor; } } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e49aad2cd607..d1d462c2fbe8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -221,6 +221,7 @@ public final class ActivityThread { private long mNetworkBlockSeq = INVALID_PROC_STATE_SEQ; private ContextImpl mSystemContext; + private ContextImpl mSystemUiContext; static volatile IPackageManager sPackageManager; @@ -2190,9 +2191,19 @@ public final class ActivityThread { } } + public ContextImpl getSystemUiContext() { + synchronized (this) { + if (mSystemUiContext == null) { + mSystemUiContext = ContextImpl.createSystemUiContext(this); + } + return mSystemUiContext; + } + } + public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { synchronized (this) { getSystemContext().installSystemApplicationInfo(info, classLoader); + getSystemUiContext().installSystemApplicationInfo(info, classLoader); // give ourselves a default profiler mProfiler = new Profiler(); @@ -5031,6 +5042,11 @@ public final class ActivityThread { if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { systemTheme.rebase(); } + + final Theme systemUiTheme = getSystemUiContext().getTheme(); + if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) { + systemUiTheme.rebase(); + } } ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config); @@ -5086,9 +5102,10 @@ public final class ActivityThread { // Trigger a regular Configuration change event, only with a different assetsSeq number // so that we actually call through to all components. + // TODO(adamlesinski): Change this to make use of ActivityManager's upcoming ability to + // store configurations per-process. Configuration newConfig = new Configuration(); - newConfig.unset(); - newConfig.assetsSeq = mConfiguration.assetsSeq + 1; + newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1; handleConfigurationChanged(newConfig, null); // Schedule all activities to reload diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 461f9cc35125..a6838f8bbf0a 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1352,7 +1352,7 @@ public class ApplicationPackageManager extends PackageManager { public Resources getResourcesForApplication(@NonNull ApplicationInfo app) throws NameNotFoundException { if (app.packageName.equals("system")) { - return mContext.mMainThread.getSystemContext().getResources(); + return mContext.mMainThread.getSystemUiContext().getResources(); } final boolean sameUid = (app.uid == Process.myUid()); final Resources r = mContext.mMainThread.getTopLevelResources( @@ -1383,7 +1383,7 @@ public class ApplicationPackageManager extends PackageManager { "Call does not support special user #" + userId); } if ("system".equals(appPackageName)) { - return mContext.mMainThread.getSystemContext().getResources(); + return mContext.mMainThread.getSystemUiContext().getResources(); } try { ApplicationInfo ai = mPM.getApplicationInfo(appPackageName, sDefaultFlags, userId); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 5a7246a4ed38..75f9d671fbad 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2218,6 +2218,18 @@ class ContextImpl extends Context { return context; } + /** + * System Context to be used for UI. This Context has resources that can be themed. + */ + static ContextImpl createSystemUiContext(ActivityThread mainThread) { + LoadedApk packageInfo = new LoadedApk(mainThread); + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, + null); + context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null, + packageInfo.getCompatibilityInfo())); + return context; + } + static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 279b9003f8c0..399987fe1c41 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1128,8 +1128,13 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate newState = Fragment.CREATED; } if (f.mRemoving && newState > f.mState) { - // While removing a fragment, we can't change it to a higher state. - newState = f.mState; + if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) { + // Allow the fragment to be created so that it can be saved later. + newState = Fragment.CREATED; + } else { + // While removing a fragment, we can't change it to a higher state. + newState = f.mState; + } } // Defer start if requested; don't allow it to move to STARTED or higher // if it's not already started. diff --git a/core/java/android/app/IServiceConnection.aidl b/core/java/android/app/IServiceConnection.aidl index 6804071f26eb..97042aa2919f 100644 --- a/core/java/android/app/IServiceConnection.aidl +++ b/core/java/android/app/IServiceConnection.aidl @@ -21,6 +21,6 @@ import android.content.ComponentName; /** @hide */ oneway interface IServiceConnection { - void connected(in ComponentName name, IBinder service); + void connected(in ComponentName name, IBinder service, boolean dead); } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index dbed1beb4cf7..4205db098ef6 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -88,8 +88,8 @@ final class ServiceConnectionLeaked extends AndroidRuntimeException { * @hide */ public final class LoadedApk { - - private static final String TAG = "LoadedApk"; + static final String TAG = "LoadedApk"; + static final boolean DEBUG = false; private final ActivityThread mActivityThread; final String mPackageName; @@ -641,8 +641,7 @@ public final class LoadedApk { final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) : TextUtils.join(File.pathSeparator, zipPaths); - if (ActivityThread.localLOGV) - Slog.v(ActivityThread.TAG, "Class path: " + zip + + if (DEBUG) Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + librarySearchPath); boolean needToSetupJitProfiles = false; @@ -1371,12 +1370,14 @@ public final class LoadedApk { LoadedApk.ServiceDispatcher sd = null; ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); if (map != null) { + if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c); sd = map.get(c); } if (sd == null) { sd = new ServiceDispatcher(c, context, handler, flags); + if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c); if (map == null) { - map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); + map = new ArrayMap<>(); mServices.put(context, map); } map.put(c, sd); @@ -1396,6 +1397,7 @@ public final class LoadedApk { if (map != null) { sd = map.get(c); if (sd != null) { + if (DEBUG) Slog.d(TAG, "Removing dispatcher " + sd + " for conn " + c); map.remove(c); sd.doForget(); if (map.size() == 0) { @@ -1461,10 +1463,11 @@ public final class LoadedApk { mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); } - public void connected(ComponentName name, IBinder service) throws RemoteException { + public void connected(ComponentName name, IBinder service, boolean dead) + throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd != null) { - sd.connected(name, service); + sd.connected(name, service, dead); } } } @@ -1533,23 +1536,23 @@ public final class LoadedApk { return mUnbindLocation; } - public void connected(ComponentName name, IBinder service) { + public void connected(ComponentName name, IBinder service, boolean dead) { if (mActivityThread != null) { - mActivityThread.post(new RunConnection(name, service, 0)); + mActivityThread.post(new RunConnection(name, service, 0, dead)); } else { - doConnected(name, service); + doConnected(name, service, dead); } } public void death(ComponentName name, IBinder service) { if (mActivityThread != null) { - mActivityThread.post(new RunConnection(name, service, 1)); + mActivityThread.post(new RunConnection(name, service, 1, false)); } else { doDeath(name, service); } } - public void doConnected(ComponentName name, IBinder service) { + public void doConnected(ComponentName name, IBinder service, boolean dead) { ServiceDispatcher.ConnectionInfo old; ServiceDispatcher.ConnectionInfo info; @@ -1594,6 +1597,9 @@ public final class LoadedApk { if (old != null) { mConnection.onServiceDisconnected(name); } + if (dead) { + mConnection.onBindingDead(name); + } // If there is a new service, it is now connected. if (service != null) { mConnection.onServiceConnected(name, service); @@ -1616,15 +1622,16 @@ public final class LoadedApk { } private final class RunConnection implements Runnable { - RunConnection(ComponentName name, IBinder service, int command) { + RunConnection(ComponentName name, IBinder service, int command, boolean dead) { mName = name; mService = service; mCommand = command; + mDead = dead; } public void run() { if (mCommand == 0) { - doConnected(mName, mService); + doConnected(mName, mService, mDead); } else if (mCommand == 1) { doDeath(mName, mService); } @@ -1633,6 +1640,7 @@ public final class LoadedApk { final ComponentName mName; final IBinder mService; final int mCommand; + final boolean mDead; } private final class DeathMonitor implements IBinder.DeathRecipient diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index b42df5e2e0fb..489a0f0975ae 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -984,7 +984,7 @@ public class ResourcesManager { final ResourcesKey key = mResourceImpls.keyAt(i); final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; - if (impl != null && key.mResDir != null && key.mResDir.equals(baseCodePath)) { + if (impl != null && (key.mResDir == null || key.mResDir.equals(baseCodePath))) { updatedResourceKeys.put(impl, new ResourcesKey( key.mResDir, key.mSplitResDirs, diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index f719749cc9f9..6b05bdff5d1e 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -125,7 +125,6 @@ import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.text.FontManager; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; @@ -141,7 +140,6 @@ import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.internal.app.ISoundTriggerService; import com.android.internal.appwidget.IAppWidgetService; -import com.android.internal.font.IFontManager; import com.android.internal.os.IDropBoxManagerService; import com.android.internal.policy.PhoneLayoutInflater; @@ -820,14 +818,6 @@ final class SystemServiceRegistry { return new IncidentManager(ctx); }}); - registerService(Context.FONT_SERVICE, FontManager.class, - new CachedServiceFetcher<FontManager>() { - @Override - public FontManager createService(ContextImpl ctx) - throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.FONT_SERVICE); - return new FontManager(IFontManager.Stub.asInterface(b)); - }}); registerService(Context.AUTOFILL_MANAGER_SERVICE, AutofillManager.class, new CachedServiceFetcher<AutofillManager>() { @Override diff --git a/core/java/android/app/admin/DeviceAdminService.java b/core/java/android/app/admin/DeviceAdminService.java new file mode 100644 index 000000000000..cd0b1bf3d0a8 --- /dev/null +++ b/core/java/android/app/admin/DeviceAdminService.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 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.app.admin; + +import android.app.Service; +import android.content.ComponentName; +import android.content.Intent; +import android.os.IBinder; + +/** + * Base class for a service that device owner/profile owners can optionally have. + * + * <p>The system searches for it with an intent filter with the + * {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} action, and tries to keep a bound + * connection as long as the hosting user is running, so that the device/profile owner is always + * considered to be in the foreground. + * + * <p>Device/profile owners can use + * {@link android.content.pm.PackageManager#setComponentEnabledSetting(ComponentName, int, int)} + * to disable/enable its own service. For example, when a device/profile owner no longer needs + * to be in the foreground, it can (and should) disable its service. + * + * <p>The service must not be exported. + * + * <p>TODO: Describe how the system handles crashes in DO/PO. + */ +public class DeviceAdminService extends Service { + private final IDeviceAdminServiceImpl mImpl; + + public DeviceAdminService() { + mImpl = new IDeviceAdminServiceImpl(); + } + + @Override + public final IBinder onBind(Intent intent) { + return mImpl.asBinder(); + } + + private class IDeviceAdminServiceImpl extends IDeviceAdminService.Stub { + } + + // So far, we have no methods in this class. +} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 6d8d5e93c1ee..2f0a630bcd04 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1515,6 +1515,16 @@ public class DevicePolicyManager { public @interface ProvisioningPreCondition {} /** + * Service action: Action for a service that device owner and profile owner can optionally + * own. If a device owner or a profile owner has such a service, the system tries to keep + * a bound connection to it, in order to keep their process always running. + * The service must not be exported. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String ACTION_DEVICE_ADMIN_SERVICE + = "android.app.action.DEVICE_ADMIN_SERVICE"; + + /** * Return true if the given administrator component is currently active (enabled) in the system. * * @param admin The administrator component to check for. diff --git a/core/java/com/android/internal/font/IFontManager.aidl b/core/java/android/app/admin/IDeviceAdminService.aidl index 52a626288caf..5276ed599226 100644 --- a/core/java/com/android/internal/font/IFontManager.aidl +++ b/core/java/android/app/admin/IDeviceAdminService.aidl @@ -14,14 +14,10 @@ * limitations under the License. */ -package com.android.internal.font; - -import android.text.FontConfig; +package android.app.admin; /** - * Interface to the font manager. * @hide */ -interface IFontManager { - FontConfig getSystemFonts(); +interface IDeviceAdminService { } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index dbbfe308868c..368c7b8106b3 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3870,11 +3870,6 @@ public abstract class Context { public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers"; /** - * Service that provides System font data. - */ - public static final String FONT_SERVICE = "font"; - - /** * Service to report a system health "incident" * @hide */ @@ -4631,4 +4626,18 @@ public abstract class Context { public Handler getMainThreadHandler() { throw new RuntimeException("Not implemented. Must override in a subclass."); } + + /** + * Throws an exception if the Context is using system resources, + * which are non-runtime-overlay-themable and may show inconsistent UI. + * @hide + */ + public void assertRuntimeOverlayThemable() { + // Resources.getSystem() is a singleton and the only Resources not managed by + // ResourcesManager; therefore Resources.getSystem() is not themable. + if (getResources() == Resources.getSystem()) { + throw new IllegalArgumentException("Non-UI context used to display UI; " + + "get a UI context from ActivityThread#getSystemUiContext()"); + } + } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 81aea8d178d5..da887af52b2a 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -16,8 +16,6 @@ package android.content; -import static android.content.ContentProvider.maybeAddUserId; - import android.annotation.AnyRes; import android.annotation.BroadcastBehavior; import android.annotation.IntDef; @@ -43,6 +41,7 @@ import android.os.ResultReceiver; import android.os.ShellCommand; import android.os.StrictMode; import android.os.UserHandle; +import android.os.storage.StorageManager; import android.provider.DocumentsContract; import android.provider.DocumentsProvider; import android.provider.MediaStore; @@ -50,9 +49,7 @@ import android.provider.OpenableColumns; import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; - import com.android.internal.util.XmlUtils; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -70,6 +67,8 @@ import java.util.Locale; import java.util.Objects; import java.util.Set; +import static android.content.ContentProvider.maybeAddUserId; + /** * An intent is an abstract description of an operation to be performed. It * can be used with {@link Context#startActivity(Intent) startActivity} to @@ -3353,6 +3352,32 @@ public class Intent implements Parcelable, Cloneable { ACTION_DYNAMIC_SENSOR_CHANGED = "android.intent.action.DYNAMIC_SENSOR_CHANGED"; /** + * Broadcast Action: The default subscription has changed. This has the following + * extra values:</p> + * The {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default subscription index + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED + = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED"; + + /** + * Broadcast Action: The default sms subscription has changed. This has the following + * extra values:</p> + * {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default sms + * subscription index + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED + = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED"; + + /** + * Integer extra used with {@link #ACTION_DEFAULT_SUBSCRIPTION_CHANGED} and + * {@link #ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED} to indicate the subscription + * which has changed. + */ + public static final String EXTRA_SUBSCRIPTION_INDEX = "android.intent.extra.SUBSCRIPTION_INDEX"; + + /** * Deprecated - use {@link #ACTION_FACTORY_RESET} instead. * * {@hide} @@ -3872,23 +3897,9 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT"; /** - * A content: URI holding a stream of data associated with the Intent, used - * with {@link #ACTION_SEND} to supply the data being sent. - * <p> - * Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN} this value - * will be automatically promoted to {@link Intent#setClipData(ClipData)} - * when that value is not already defined. - * <p> - * Starting in {@link android.os.Build.VERSION_CODES#O} this value will be - * automatically demoted from {@link Intent#getClipData()} when this value - * is not already defined. - * - * @deprecated apps should use {@link Intent#setClipData(ClipData)} and - * {@link Intent#getClipData()} instead of this extra, since - * only those APIs can extend temporary permission grants to the - * underlying resource. + * A content: URI holding a stream of data associated with the Intent, + * used with {@link #ACTION_SEND} to supply the data being sent. */ - @Deprecated public static final String EXTRA_STREAM = "android.intent.extra.STREAM"; /** @@ -9433,21 +9444,6 @@ public class Intent implements Parcelable, Cloneable { mContentUserHint = UserHandle.USER_CURRENT; } } - - // If someone is sending us ClipData, but not EXTRA_STREAM, offer to - // downgrade that content for older apps to find - if (mClipData != null && mClipData.getItemCount() > 0 && !hasExtra(EXTRA_STREAM)) { - final String action = getAction(); - if (ACTION_SEND.equals(action)) { - putExtra(EXTRA_STREAM, mClipData.getItemAt(0).getUri()); - } else if (ACTION_SEND_MULTIPLE.equals(action)) { - final ArrayList<Uri> list = new ArrayList<>(); - for (int i = 0; i < mClipData.getItemCount(); i++) { - list.add(mClipData.getItemAt(i).getUri()); - } - putExtra(EXTRA_STREAM, list); - } - } } /** diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java index d115ce43e93d..8e428f9e9b3d 100644 --- a/core/java/android/content/ServiceConnection.java +++ b/core/java/android/content/ServiceConnection.java @@ -37,7 +37,7 @@ public interface ServiceConnection { * @param service The IBinder of the Service's communication channel, * which you can now make calls on. */ - public void onServiceConnected(ComponentName name, IBinder service); + void onServiceConnected(ComponentName name, IBinder service); /** * Called when a connection to the Service has been lost. This typically @@ -49,5 +49,18 @@ public interface ServiceConnection { * @param name The concrete component name of the service whose * connection has been lost. */ - public void onServiceDisconnected(ComponentName name); + void onServiceDisconnected(ComponentName name); + + /** + * Called when the binding to this connection is dead. This means the + * interface will never receive another connection. The application will + * need to unbind and rebind the connection to activate it again. This may + * happen, for example, if the application hosting the service it is bound to + * has been updated. + * + * @param name The concrete component name of the service whose + * connection is dead. + */ + default void onBindingDead(ComponentName name) { + } } diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 41311eb04837..c08bd1db8302 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -55,8 +55,7 @@ interface ILauncherApps { String callingPackage, String packageName, int flags, in UserHandle user); ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName, - in List shortcutIds, in ComponentName componentName, in Intent intent, int flags, - in UserHandle user); + in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user); void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, in UserHandle user); boolean startShortcut(String callingPackage, String packageName, String id, diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index abdef084aacc..4d767555e3b3 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -275,11 +275,8 @@ public class LauncherApps { @Deprecated public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST; - /** - * Include chooser shortcuts in the result. - * STOPSHIP TODO: Unless explicitly requesting chooser fields, we should strip out chooser - * relevant fields from the Shortcut. This should also be adequately documented. - */ + /** @deprecated punted, don't use. */ + @Deprecated public static final int FLAG_MATCH_CHOOSER = 1 << 4; /** @@ -319,7 +316,6 @@ public class LauncherApps { FLAG_MATCH_DYNAMIC, FLAG_MATCH_PINNED, FLAG_MATCH_MANIFEST, - FLAG_MATCH_CHOOSER, FLAG_GET_KEY_FIELDS_ONLY, }) @Retention(RetentionPolicy.SOURCE) @@ -336,9 +332,6 @@ public class LauncherApps { @Nullable ComponentName mActivity; - @Nullable - Intent mIntent; - @QueryFlags int mQueryFlags; @@ -382,11 +375,9 @@ public class LauncherApps { return this; } - /** - * If non-null, returns only shortcuts with intent filters that match this intent. - */ + /** @deprecated punted, don't use. */ + @Deprecated public ShortcutQuery setIntent(@Nullable Intent intent) { - mIntent = intent; return this; } @@ -428,7 +419,7 @@ public class LauncherApps { */ private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) { if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) { - Log.e(TAG, "Accessing other profiles/users from managed profile is no longer allowed."); + Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed."); } } @@ -704,7 +695,7 @@ public class LauncherApps { try { return mService.getShortcuts(mContext.getPackageName(), query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity, - query.mIntent, query.mQueryFlags, user) + query.mQueryFlags, user) .getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 136c13b6f37d..a493f33cfcb1 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2158,7 +2158,6 @@ public abstract class PackageManager { * {@link #hasSystemFeature}: The device supports only leanback UI. Only * applications designed for this experience should be run, though this is * not enforced by the system. - * @hide */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 520169499718..3f4a09072540 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.TaskStackBuilder; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -40,12 +39,10 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -99,14 +96,6 @@ public final class ShortcutInfo implements Parcelable { public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9; /** @hide */ - public static final int FLAG_CHOOSER = 1 << 10; - - /** - * TODO: Add FLAG_CHOOSER_INFO_OMITTED to reflect that chooser info was omitted in the Shortcut - * due to the context in which it was retrieved. - * TODO: Add a FLAG_LAUNCHABLE to reflect whether or not the Shortcut has a launchable intent - * @hide - */ @IntDef(flag = true, value = { FLAG_DYNAMIC, @@ -119,7 +108,6 @@ public final class ShortcutInfo implements Parcelable { FLAG_STRINGS_RESOLVED, FLAG_IMMUTABLE, FLAG_ADAPTIVE_BITMAP, - FLAG_CHOOSER, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} @@ -214,24 +202,6 @@ public final class ShortcutInfo implements Parcelable { @Nullable private PersistableBundle[] mIntentPersistableExtrases; - /** - * If used in a chooser, extras that should be added into the intent passed through. - */ - @Nullable - private PersistableBundle mChooserExtras; - - /** - * Intent filters to be used if the shortcut is to be used in a chooser context. - */ - @Nullable - private IntentFilter[] mChooserIntentFilters; - - /** - * Component names corresponding to the above intent filters. - */ - @Nullable - private ComponentName[] mChooserComponentNames; - private int mRank; /** @@ -281,13 +251,6 @@ public final class ShortcutInfo implements Parcelable { mDisabledMessageResId = b.mDisabledMessageResId; mCategories = cloneCategories(b.mCategories); mIntents = cloneIntents(b.mIntents); - if (b.mChooserIntentFilters != null) { - mChooserIntentFilters = b.mChooserIntentFilters.toArray(new IntentFilter[0]); - } - if (b.mChooserComponentNames != null) { - mChooserComponentNames = b.mChooserComponentNames.toArray(new ComponentName[0]); - } - mChooserExtras = b.mChooserExtras; fixUpIntentExtras(); mRank = b.mRank; mExtras = b.mExtras; @@ -368,28 +331,8 @@ public final class ShortcutInfo implements Parcelable { if (mTitle == null && mTitleResId == 0) { throw new IllegalArgumentException("Short label must be provided"); } - - // For a shortcut to be valid, there should either be an Intent, or a non-empty set of - // intent filters. - if (mIntents == null || mIntents.length == 0) { - Preconditions.checkNotNull(mChooserIntentFilters, - "Intent must be provided if not a chooser target"); - Preconditions.checkNotNull(mChooserComponentNames, - "Intent must be provided if not a chooser target"); - } - - // If ChooserIntentFilter are provided, they should match the length of the provided - // component names. - if (mChooserIntentFilters != null) { - if (mChooserComponentNames == null - || mChooserIntentFilters.length != mChooserComponentNames.length) { - throw new IllegalArgumentException("Inconsistent intent filters and " - + "component names given"); - } - if (mChooserIntentFilters.length == 0 || mChooserComponentNames.length == 0) { - throw new IllegalArgumentException("Empty intent filter and component names given"); - } - } + Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided"); + Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided"); } /** @@ -434,10 +377,6 @@ public final class ShortcutInfo implements Parcelable { mDisabledMessageResName = source.mDisabledMessageResName; mIconResName = source.mIconResName; } - // TODO: Omit these by default and add a new clone flag. - mChooserIntentFilters = source.mChooserIntentFilters; - mChooserComponentNames = source.mChooserComponentNames; - mChooserExtras = source.mChooserExtras; } else { // Set this bit. mFlags |= FLAG_KEY_FIELDS_ONLY; @@ -565,25 +504,6 @@ public final class ShortcutInfo implements Parcelable { } /** - * Whether the shortcut has any intentFilter matching the passed in one. - * @hide - */ - @VisibleForTesting - public boolean hasMatchingFilter(ContentResolver resolver, Intent intent) { - if (mChooserIntentFilters == null) { - return false; - } - for (IntentFilter filter : mChooserIntentFilters) { - int match = filter.match(resolver, intent, false, TAG); - if (match > 0) { - return true; - } - } - return false; - } - - - /** * Extract the entry name from a fully-donated resource name. * e.g. "com.android.app1:drawable/icon1" -> "icon1" * @hide @@ -766,15 +686,6 @@ public final class ShortcutInfo implements Parcelable { if (source.mExtras != null) { mExtras = source.mExtras; } - if (source.mChooserExtras != null) { - mChooserExtras = source.mChooserExtras; - } - if (source.mChooserIntentFilters != null) { - mChooserIntentFilters = source.mChooserIntentFilters; - } - if (source.mChooserComponentNames != null) { - mChooserComponentNames = source.mChooserComponentNames; - } } /** @@ -836,12 +747,6 @@ public final class ShortcutInfo implements Parcelable { private PersistableBundle mExtras; - private PersistableBundle mChooserExtras; - - private List<IntentFilter> mChooserIntentFilters; - - private List<ComponentName> mChooserComponentNames; - /** * Old style constructor. * @hide @@ -1127,37 +1032,17 @@ public final class ShortcutInfo implements Parcelable { return this; } - /** - * Extras that can be added which will be added to the Intent used to launch the app if - * launched from a chooser context. - */ + /** @deprecated punted, don't use. */ + @Deprecated @NonNull public Builder setChooserExtras(@NonNull PersistableBundle extras) { - mChooserExtras = extras; return this; } - /** - * IntentFilters and the components that should resolve a match for a given chooser target. - * If multiple matches are found, the component corresponding to the closest match will be - * used. - * - * @param filter IntendFilter that if matched will have the intent forwarded to the given - * component - * @param name The component that an intent that passes this filter will resolve to. - */ + /** @deprecated punted, don't use. */ + @Deprecated public Builder addChooserIntentFilter(@NonNull IntentFilter filter, @NonNull ComponentName name) { - Preconditions.checkNotNull(filter, "intent filter cannot be null"); - Preconditions.checkNotNull(name, "component name cannot be null"); - - if (mChooserIntentFilters == null || mChooserComponentNames == null) { - mChooserIntentFilters = new ArrayList<>(); - mChooserComponentNames = new ArrayList<>(); - } - - mChooserIntentFilters.add(filter); - mChooserComponentNames.add(name); return this; } @@ -1361,28 +1246,25 @@ public final class ShortcutInfo implements Parcelable { return mIntentPersistableExtrases; } - /** - * Retrieve the extras that will be added in to any intent launched through the chooser. - */ + /** @deprecated punted, don't use. */ + @Deprecated @NonNull public PersistableBundle getChooserExtras() { - return mChooserExtras; + return new PersistableBundle(); } - /** - * Retrieve the list of intent filters for chooser targets. - */ + /** @deprecated punted, don't use. */ + @Deprecated @NonNull public IntentFilter[] getChooserIntentFilters() { - return mChooserIntentFilters; + return new IntentFilter[0]; } - /** - * Retrieve the list of component names corresponding to the above intent filters. - */ + /** @deprecated punted, don't use. */ + @Deprecated @NonNull public ComponentName[] getChooserComponentNames() { - return mChooserComponentNames; + return new ComponentName[0]; } /** @@ -1506,9 +1388,10 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_PINNED); } - /** Return whether a shortcut can be shown in the chooser. */ + /** @deprecated punted, don't use. */ + @Deprecated public boolean isChooser() { - return hasFlags(FLAG_CHOOSER); + return false; } /** @@ -1539,14 +1422,6 @@ public final class ShortcutInfo implements Parcelable { return isPinned() && !(isDynamic() || isManifestShortcut()); } - /** - * @return true if pinned but neither static nor dynamic. - * @hide - */ - public boolean isDynamicOrChooser() { - return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_CHOOSER); - } - /** @hide */ public boolean isOriginallyFromManifest() { return hasFlags(FLAG_IMMUTABLE); @@ -1829,19 +1704,6 @@ public final class ShortcutInfo implements Parcelable { mCategories.add(source.readString().intern()); } } - - // We put a placeholder empty array in to keep the parcelable order, but can do away with - // them at this point if they're empty. - mChooserComponentNames = source.readParcelableArray(cl, ComponentName.class); - if (mChooserComponentNames.length == 0) { - mChooserComponentNames = null; - } - - mChooserIntentFilters = source.readParcelableArray(cl, IntentFilter.class); - if (mChooserIntentFilters.length == 0) { - mChooserIntentFilters = null; - } - mChooserExtras = source.readPersistableBundle(cl); } @Override @@ -1888,17 +1750,6 @@ public final class ShortcutInfo implements Parcelable { } else { dest.writeInt(0); } - if (mChooserComponentNames != null) { - dest.writeParcelableArray(mChooserComponentNames, flags); - } else { - dest.writeParcelableArray(new ComponentName[0], flags); - } - if (mChooserIntentFilters != null) { - dest.writeParcelableArray(mChooserIntentFilters, flags); - } else { - dest.writeParcelableArray(new IntentFilter[0], flags); - } - dest.writePersistableBundle(mChooserExtras); } public static final Creator<ShortcutInfo> CREATOR = diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java index 3de19d19bfc3..7b7d8ae42528 100644 --- a/core/java/android/content/pm/ShortcutServiceInternal.java +++ b/core/java/android/content/pm/ShortcutServiceInternal.java @@ -45,8 +45,8 @@ public abstract class ShortcutServiceInternal { getShortcuts(int launcherUserId, @NonNull String callingPackage, long changedSince, @Nullable String packageName, @Nullable List<String> shortcutIds, - @Nullable ComponentName componentName, @Nullable Intent intent, - @ShortcutQuery.QueryFlags int flags, int userId); + @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags, + int userId); public abstract boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage, diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index b27600800cc6..e845359a35c4 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -102,6 +102,16 @@ public abstract class DisplayManagerInternal { int displayId, DisplayInfo info); /** + * Get current display info without override from WindowManager. + * Current implementation of LogicalDisplay#getDisplayInfoLocked() always returns display info + * with overrides from WM if set. This method can be used for getting real display size without + * overrides to determine if real changes to display metrics happened. + * @param displayId Id of the target display. + * @param outInfo {@link DisplayInfo} to fill. + */ + public abstract void getNonOverrideDisplayInfo(int displayId, DisplayInfo outInfo); + + /** * Called by the window manager to perform traversals while holding a * surface flinger transaction. */ diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java index badb344aabad..239a2df5e1c3 100644 --- a/core/java/android/hardware/usb/UsbRequest.java +++ b/core/java/android/hardware/usb/UsbRequest.java @@ -60,9 +60,11 @@ public class UsbRequest { // Prevent the connection from being finalized private UsbDeviceConnection mConnection; - /** Whether this buffer was {@link #enqueue enqueued (new behavior)} or {@link #queue queued - * (deprecared behavior)}. */ - private boolean mIsUsingEnqueue; + /** + * Whether this buffer was {@link #queue(ByteBuffer) queued using the new behavior} or + * {@link #queue(ByteBuffer, int) queued using the deprecated behavior}. + */ + private boolean mIsUsingNewQueue; /** Temporary buffer than might be used while buffer is enqueued */ private ByteBuffer mTempBuffer; @@ -172,7 +174,7 @@ public class UsbRequest { * * @return true if the queueing operation succeeded * - * @deprecated Use {@link #enqueue(ByteBuffer)} instead. + * @deprecated Use {@link #queue(ByteBuffer)} instead. */ @Deprecated public boolean queue(ByteBuffer buffer, int length) { @@ -219,23 +221,23 @@ public class UsbRequest { * * @return true if the queueing operation succeeded */ - public boolean enqueue(@Nullable ByteBuffer buffer) { + public boolean queue(@Nullable ByteBuffer buffer) { // Request need to be initialized Preconditions.checkState(mNativeContext != 0, "request is not initialized"); - // Request can not be currently enqueued - Preconditions.checkState(!mIsUsingEnqueue, "request is currently enqueued"); + // Request can not be currently queued + Preconditions.checkState(!mIsUsingNewQueue, "this request is currently queued"); boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT); - boolean wasEnqueued; + boolean wasQueued; synchronized (mLock) { mBuffer = buffer; if (buffer == null) { // Null buffers enqueue empty USB requests which is supported - mIsUsingEnqueue = true; - wasEnqueued = native_enqueue(null, 0, 0); + mIsUsingNewQueue = true; + wasQueued = native_queue(null, 0, 0); } else { // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE, @@ -260,18 +262,18 @@ public class UsbRequest { buffer = mTempBuffer; } - mIsUsingEnqueue = true; - wasEnqueued = native_enqueue(buffer, buffer.position(), buffer.remaining()); + mIsUsingNewQueue = true; + wasQueued = native_queue(buffer, buffer.position(), buffer.remaining()); } } - if (!wasEnqueued) { - mIsUsingEnqueue = false; + if (!wasQueued) { + mIsUsingNewQueue = false; mTempBuffer = null; mBuffer = null; } - return wasEnqueued; + return wasQueued; } /* package */ void dequeue() { @@ -279,9 +281,9 @@ public class UsbRequest { int bytesTransferred; synchronized (mLock) { - if (mIsUsingEnqueue) { + if (mIsUsingNewQueue) { bytesTransferred = native_dequeue_direct(); - mIsUsingEnqueue = false; + mIsUsingNewQueue = false; if (mBuffer == null) { // Nothing to do @@ -332,7 +334,7 @@ public class UsbRequest { private native boolean native_init(UsbDeviceConnection connection, int ep_address, int ep_attributes, int ep_max_packet_size, int ep_interval); private native void native_close(); - private native boolean native_enqueue(ByteBuffer buffer, int offset, int length); + private native boolean native_queue(ByteBuffer buffer, int offset, int length); private native boolean native_queue_array(byte[] buffer, int length, boolean out); private native int native_dequeue_array(byte[] buffer, int length, boolean out); private native boolean native_queue_direct(ByteBuffer buffer, int length, boolean out); diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 495340dc7222..63bbd96bd01d 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -38,9 +38,6 @@ interface INetworkPolicyManager { boolean isUidForeground(int uid); - /** Higher priority listener before general event dispatch */ - void setConnectivityListener(INetworkPolicyListener listener); - void registerListener(INetworkPolicyListener listener); void unregisterListener(INetworkPolicyListener listener); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e2100bd43898..660d53a91b99 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10324,6 +10324,10 @@ public final class Settings { INSTANT_APP_SETTINGS.add(DEVELOPMENT_FORCE_RTL); INSTANT_APP_SETTINGS.add(EPHEMERAL_COOKIE_MAX_SIZE_BYTES); INSTANT_APP_SETTINGS.add(AIRPLANE_MODE_ON); + INSTANT_APP_SETTINGS.add(WINDOW_ANIMATION_SCALE); + INSTANT_APP_SETTINGS.add(TRANSITION_ANIMATION_SCALE); + INSTANT_APP_SETTINGS.add(ANIMATOR_DURATION_SCALE); + INSTANT_APP_SETTINGS.add(DEBUG_VIEW_ATTRIBUTES); } /** diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java index 8e0103078a42..56b267fb2c9d 100644 --- a/core/java/android/service/quicksettings/TileService.java +++ b/core/java/android/service/quicksettings/TileService.java @@ -19,11 +19,13 @@ import android.Manifest; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.Dialog; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.graphics.drawable.Icon; import android.os.Handler; import android.os.IBinder; @@ -34,6 +36,8 @@ import android.view.View; import android.view.View.OnAttachStateChangeListener; import android.view.WindowManager; +import com.android.internal.R; + /** * A TileService provides the user a tile that can be added to Quick Settings. * Quick Settings is a space provided that allows the user to change settings and @@ -425,6 +429,15 @@ public class TileService extends Service { } /** + * @return True if the device supports quick settings and its assocated APIs. + * @hide + */ + @TestApi + public static boolean isQuickSettingsSupported() { + return Resources.getSystem().getBoolean(R.bool.config_quickSettingsSupported); + } + + /** * Requests that a tile be put in the listening state so it can send an update. * * This method is only applicable to tiles that have {@link #META_DATA_ACTIVE_TILE} defined diff --git a/core/java/android/service/resolver/IResolverRankerResult.aidl b/core/java/android/service/resolver/IResolverRankerResult.aidl new file mode 100644 index 000000000000..bda315420b7b --- /dev/null +++ b/core/java/android/service/resolver/IResolverRankerResult.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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.resolver; + +import android.service.resolver.ResolverTarget; + +/** + * @hide + */ +oneway interface IResolverRankerResult +{ + void sendResult(in List<ResolverTarget> results); +}
\ No newline at end of file diff --git a/core/java/android/service/resolver/IResolverRankerService.aidl b/core/java/android/service/resolver/IResolverRankerService.aidl new file mode 100644 index 000000000000..f0d747d974a7 --- /dev/null +++ b/core/java/android/service/resolver/IResolverRankerService.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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.resolver; + +import android.service.resolver.IResolverRankerResult; +import android.service.resolver.ResolverTarget; + +/** + * @hide + */ +oneway interface IResolverRankerService +{ + void predict(in List<ResolverTarget> targets, IResolverRankerResult result); + void train(in List<ResolverTarget> targets, int selectedPosition); +}
\ No newline at end of file diff --git a/core/java/android/service/resolver/ResolverRankerService.java b/core/java/android/service/resolver/ResolverRankerService.java new file mode 100644 index 000000000000..05067479bf45 --- /dev/null +++ b/core/java/android/service/resolver/ResolverRankerService.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2017 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.resolver; + +import android.annotation.SdkConstant; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.ComponentName; +import android.content.Intent; +import android.os.IBinder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.RemoteException; +import android.service.resolver.ResolverTarget; +import android.util.Log; + +import java.util.List; +import java.util.Map; + +/** + * A service to rank apps according to usage stats of apps, when the system is resolving targets for + * an Intent. + * + * <p>To extend this class, you must declare the service in your manifest file with the + * {@link android.Manifest.permission#BIND_RESOLVER_RANKER_SERVICE} permission, and include an + * intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> + * <pre> + * <service android:name=".MyResolverRankerService" + * android:exported="true" + * android:priority="100" + * android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE"> + * <intent-filter> + * <action android:name="android.service.resolver.ResolverRankerService" /> + * </intent-filter> + * </service> + * </pre> + * @hide + */ +@SystemApi +public abstract class ResolverRankerService extends Service { + + private static final String TAG = "ResolverRankerService"; + + private static final boolean DEBUG = false; + + /** + * The Intent action that a service must respond to. Add it to the intent filter of the service + * in its manifest. + */ + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService"; + + /** + * The permission that a service must require to ensure that only Android system can bind to it. + * If this permission is not enforced in the AndroidManifest of the service, the system will + * skip that service. + */ + public static final String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE"; + + private ResolverRankerServiceWrapper mWrapper = null; + + /** + * Called by the system to retrieve a list of probabilities to rank apps/options. To implement + * it, set selectProbability of each input {@link ResolverTarget}. The higher the + * selectProbability is, the more likely the {@link ResolverTarget} will be selected by the + * user. Override this function to provide prediction results. + * + * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked. + * + * @throws Exception when the prediction task fails. + */ + public void onPredictSharingProbabilities(final List<ResolverTarget> targets) {} + + /** + * Called by the system to train/update a ranking service, after the user makes a selection from + * the ranked list of apps. Override this function to enable model updates. + * + * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked. + * @param selectedPosition the position of the selected app in the list. + * + * @throws Exception when the training task fails. + */ + public void onTrainRankingModel( + final List<ResolverTarget> targets, final int selectedPosition) {} + + private static final String HANDLER_THREAD_NAME = "RESOLVER_RANKER_SERVICE"; + private volatile Handler mHandler; + private HandlerThread mHandlerThread; + + @Override + public IBinder onBind(Intent intent) { + if (DEBUG) Log.d(TAG, "onBind " + intent); + if (!SERVICE_INTERFACE.equals(intent.getAction())) { + if (DEBUG) Log.d(TAG, "bad intent action " + intent.getAction() + "; returning null"); + return null; + } + if (mHandlerThread == null) { + mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } + if (mWrapper == null) { + mWrapper = new ResolverRankerServiceWrapper(); + } + return mWrapper; + } + + @Override + public void onDestroy() { + mHandler = null; + if (mHandlerThread != null) { + mHandlerThread.quitSafely(); + } + super.onDestroy(); + } + + private static void sendResult(List<ResolverTarget> targets, IResolverRankerResult result) { + try { + result.sendResult(targets); + } catch (Exception e) { + Log.e(TAG, "failed to send results: " + e); + } + } + + private class ResolverRankerServiceWrapper extends IResolverRankerService.Stub { + + @Override + public void predict(final List<ResolverTarget> targets, final IResolverRankerResult result) + throws RemoteException { + Runnable predictRunnable = new Runnable() { + @Override + public void run() { + try { + if (DEBUG) { + Log.d(TAG, "predict calls onPredictSharingProbabilities."); + } + onPredictSharingProbabilities(targets); + sendResult(targets, result); + } catch (Exception e) { + Log.e(TAG, "onPredictSharingProbabilities failed; send null results: " + e); + sendResult(null, result); + } + } + }; + final Handler h = mHandler; + if (h != null) { + h.post(predictRunnable); + } + } + + @Override + public void train(final List<ResolverTarget> targets, final int selectedPosition) + throws RemoteException { + Runnable trainRunnable = new Runnable() { + @Override + public void run() { + try { + if (DEBUG) { + Log.d(TAG, "train calls onTranRankingModel"); + } + onTrainRankingModel(targets, selectedPosition); + } catch (Exception e) { + Log.e(TAG, "onTrainRankingModel failed; skip train: " + e); + } + } + }; + final Handler h = mHandler; + if (h != null) { + h.post(trainRunnable); + } + } + } +} diff --git a/core/java/android/service/resolver/ResolverTarget.aidl b/core/java/android/service/resolver/ResolverTarget.aidl new file mode 100644 index 000000000000..6cab2d4df908 --- /dev/null +++ b/core/java/android/service/resolver/ResolverTarget.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 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.resolver; + +/** + * @hide + */ +parcelable ResolverTarget; diff --git a/core/java/android/service/resolver/ResolverTarget.java b/core/java/android/service/resolver/ResolverTarget.java new file mode 100644 index 000000000000..fb3e2d738469 --- /dev/null +++ b/core/java/android/service/resolver/ResolverTarget.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2017 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.resolver; + +import android.annotation.SystemApi; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArrayMap; + +import java.util.Map; + +/** + * A ResolverTarget contains features by which an app or option will be ranked, in + * {@link ResolverRankerService}. + * @hide + */ +@SystemApi +public final class ResolverTarget implements Parcelable { + private static final String TAG = "ResolverTarget"; + + /** + * a float score for recency of last use. + */ + private float mRecencyScore; + + /** + * a float score for total time spent. + */ + private float mTimeSpentScore; + + /** + * a float score for number of launches. + */ + private float mLaunchScore; + + /** + * a float score for number of selected. + */ + private float mChooserScore; + + /** + * a float score for the probability to be selected. + */ + private float mSelectProbability; + + // constructor for the class. + public ResolverTarget() {} + + ResolverTarget(Parcel in) { + mRecencyScore = in.readFloat(); + mTimeSpentScore = in.readFloat(); + mLaunchScore = in.readFloat(); + mChooserScore = in.readFloat(); + mSelectProbability = in.readFloat(); + } + + /** + * Gets the score for how recently the target was used in the foreground. + * + * @return a float score whose range is [0, 1]. The higher the score is, the more recently the + * target was used. + */ + public float getRecencyScore() { + return mRecencyScore; + } + + /** + * Sets the score for how recently the target was used in the foreground. + * + * @param recencyScore a float score whose range is [0, 1]. The higher the score is, the more + * recently the target was used. + */ + public void setRecencyScore(float recencyScore) { + this.mRecencyScore = recencyScore; + } + + /** + * Gets the score for how long the target has been used in the foreground. + * + * @return a float score whose range is [0, 1]. The higher the score is, the longer the target + * has been used for. + */ + public float getTimeSpentScore() { + return mTimeSpentScore; + } + + /** + * Sets the score for how long the target has been used in the foreground. + * + * @param timeSpentScore a float score whose range is [0, 1]. The higher the score is, the + * longer the target has been used for. + */ + public void setTimeSpentScore(float timeSpentScore) { + this.mTimeSpentScore = timeSpentScore; + } + + /** + * Gets the score for how many times the target has been launched to the foreground. + * + * @return a float score whose range is [0, 1]. The higher the score is, the more times the + * target has been launched. + */ + public float getLaunchScore() { + return mLaunchScore; + } + + /** + * Sets the score for how many times the target has been launched to the foreground. + * + * @param launchScore a float score whose range is [0, 1]. The higher the score is, the more + * times the target has been launched. + */ + public void setLaunchScore(float launchScore) { + this.mLaunchScore = launchScore; + } + + /** + * Gets the score for how many times the target has been selected by the user to share the same + * types of content. + * + * @return a float score whose range is [0, 1]. The higher the score is, the + * more times the target has been selected by the user to share the same types of content for. + */ + public float getChooserScore() { + return mChooserScore; + } + + /** + * Sets the score for how many times the target has been selected by the user to share the same + * types of content. + * + * @param chooserScore a float score whose range is [0, 1]. The higher the score is, the more + * times the target has been selected by the user to share the same types + * of content for. + */ + public void setChooserScore(float chooserScore) { + this.mChooserScore = chooserScore; + } + + /** + * Gets the probability of how likely this target will be selected by the user. + * + * @return a float score whose range is [0, 1]. The higher the score is, the more likely the + * user is going to select this target. + */ + public float getSelectProbability() { + return mSelectProbability; + } + + /** + * Sets the probability for how like this target will be selected by the user. + * + * @param selectProbability a float score whose range is [0, 1]. The higher the score is, the + * more likely tht user is going to select this target. + */ + public void setSelectProbability(float selectProbability) { + this.mSelectProbability = selectProbability; + } + + // serialize the class to a string. + @Override + public String toString() { + return "ResolverTarget{" + + mRecencyScore + ", " + + mTimeSpentScore + ", " + + mLaunchScore + ", " + + mChooserScore + ", " + + mSelectProbability + "}"; + } + + // describes the kinds of special objects contained in this Parcelable instance's marshaled + // representation. + @Override + public int describeContents() { + return 0; + } + + // flattens this object in to a Parcel. + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeFloat(mRecencyScore); + dest.writeFloat(mTimeSpentScore); + dest.writeFloat(mLaunchScore); + dest.writeFloat(mChooserScore); + dest.writeFloat(mSelectProbability); + } + + // creator definition for the class. + public static final Creator<ResolverTarget> CREATOR + = new Creator<ResolverTarget>() { + @Override + public ResolverTarget createFromParcel(Parcel source) { + return new ResolverTarget(source); + } + + @Override + public ResolverTarget[] newArray(int size) { + return new ResolverTarget[size]; + } + }; +} diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 1e9deebd8dcf..6208c532295a 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -85,7 +85,7 @@ public class DynamicLayout extends Layout this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR, spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE, StaticLayout.HYPHENATION_FREQUENCY_NONE, - false /* justify */, ellipsize, ellipsizedWidth); + Layout.JUSTIFICATION_MODE_NONE, ellipsize, ellipsizedWidth); } /** @@ -102,7 +102,7 @@ public class DynamicLayout extends Layout int width, Alignment align, TextDirectionHeuristic textDir, float spacingmult, float spacingadd, boolean includepad, int breakStrategy, int hyphenationFrequency, - boolean justify, TextUtils.TruncateAt ellipsize, + int justificationMode, TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { super((ellipsize == null) ? display @@ -128,7 +128,7 @@ public class DynamicLayout extends Layout mIncludePad = includepad; mBreakStrategy = breakStrategy; - mJustify = justify; + mJustificationMode = justificationMode; mHyphenationFrequency = hyphenationFrequency; /* @@ -303,7 +303,7 @@ public class DynamicLayout extends Layout .setEllipsize(mEllipsizeAt) .setBreakStrategy(mBreakStrategy) .setHyphenationFrequency(mHyphenationFrequency) - .setJustify(mJustify); + .setJustificationMode(mJustificationMode); reflowed.generate(b, false, true); int n = reflowed.getLineCount(); // If the new layout has a blank line at the end, but it is not @@ -811,7 +811,7 @@ public class DynamicLayout extends Layout private TextUtils.TruncateAt mEllipsizeAt; private int mBreakStrategy; private int mHyphenationFrequency; - private boolean mJustify; + private int mJustificationMode; private PackedIntVector mInts; private PackedObjectVector<Directions> mObjects; diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java index 14d3ad790b1d..8537d8f1ea84 100644 --- a/core/java/android/text/FontConfig.java +++ b/core/java/android/text/FontConfig.java @@ -21,7 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.graphics.FontListParser; +import android.graphics.fonts.FontVariationAxis; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -31,6 +31,7 @@ import java.lang.annotation.Retention; /** * Font configuration descriptions for System fonts. + * @hide */ public final class FontConfig implements Parcelable { private final @NonNull Family[] mFamilies; @@ -84,78 +85,12 @@ public final class FontConfig implements Parcelable { }; /** - * Class that holds information about a Font axis. - */ - public static final class Axis implements Parcelable { - private final int mTag; - private final float mStyleValue; - - public Axis(int tag, float styleValue) { - mTag = tag; - mStyleValue = styleValue; - } - - public Axis(@NonNull String tagString, float styleValue) { - if (!FontListParser.isValidTag(tagString)) { - throw new IllegalArgumentException("Invalid tag pattern: " + tagString); - } - mTag = FontListParser.makeTag(tagString); - mStyleValue = styleValue; - } - - /** - * Returns the variable font axis tag associated to this axis. - */ - public int getTag() { - return mTag; - } - - /** - * Returns the style value associated to the given axis for this font. - */ - public float getStyleValue() { - return mStyleValue; - } - - /** - * @hide - */ - public Axis(Parcel in) { - mTag = in.readInt(); - mStyleValue = in.readFloat(); - } - - @Override - public void writeToParcel(Parcel out, int flag) { - out.writeInt(mTag); - out.writeFloat(mStyleValue); - } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator<Axis> CREATOR = new Creator<Axis>() { - @Override - public Axis createFromParcel(Parcel in) { - return new Axis(in); - } - - @Override - public Axis[] newArray(int size) { - return new Axis[size]; - } - }; - } - - /** * Class that holds information about a Font. */ public static final class Font implements Parcelable { private final @NonNull String mFontName; private final int mTtcIndex; - private final @NonNull Axis[] mAxes; + private final @NonNull FontVariationAxis[] mAxes; private final int mWeight; private final boolean mIsItalic; private Uri mUri; @@ -163,8 +98,8 @@ public final class FontConfig implements Parcelable { /** * @hide */ - public Font(@NonNull String fontName, int ttcIndex, @NonNull Axis[] axes, int weight, - boolean isItalic) { + public Font(@NonNull String fontName, int ttcIndex, @NonNull FontVariationAxis[] axes, + int weight, boolean isItalic) { mFontName = fontName; mTtcIndex = ttcIndex; mAxes = axes; @@ -189,7 +124,7 @@ public final class FontConfig implements Parcelable { /** * Returns the list of axes associated to this font. */ - public @NonNull Axis[] getAxes() { + public @NonNull FontVariationAxis[] getAxes() { return mAxes; } @@ -230,7 +165,7 @@ public final class FontConfig implements Parcelable { public Font(Parcel in) { mFontName = in.readString(); mTtcIndex = in.readInt(); - mAxes = in.createTypedArray(Axis.CREATOR); + mAxes = in.createTypedArray(FontVariationAxis.CREATOR); mWeight = in.readInt(); mIsItalic = in.readInt() == 1; mUri = in.readTypedObject(Uri.CREATOR); diff --git a/core/java/android/text/FontManager.java b/core/java/android/text/FontManager.java deleted file mode 100644 index b61cbf3018ef..000000000000 --- a/core/java/android/text/FontManager.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2017 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.text; - -import android.os.RemoteException; - -import com.android.internal.font.IFontManager; - -/** - * Interact with the Font service. - */ -public final class FontManager { - private static final String TAG = "FontManager"; - - private final IFontManager mService; - - /** - * @hide - */ - public FontManager(IFontManager service) { - mService = service; - } - - /** - * Retrieve the system fonts data. This loads the fonts.xml data if needed and loads all system - * fonts in to memory, providing file descriptors for them. - */ - public FontConfig getSystemFonts() { - try { - return mService.getSystemFonts(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } -} diff --git a/core/java/android/text/FontVariationAxis.aidl b/core/java/android/text/FontVariationAxis.aidl new file mode 100644 index 000000000000..d5d52c26024f --- /dev/null +++ b/core/java/android/text/FontVariationAxis.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2017, 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.text; + +parcelable FontVariationAxis; diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 53564f093b37..b47fce89b0ff 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -103,6 +103,21 @@ public abstract class Layout { private static final ParagraphStyle[] NO_PARA_SPANS = ArrayUtils.emptyArray(ParagraphStyle.class); + /** @hide */ + @IntDef({JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD}) + @Retention(RetentionPolicy.SOURCE) + public @interface JustificationMode {} + + /** + * Value for justification mode indicating no justification. + */ + public static final int JUSTIFICATION_MODE_NONE = 0; + + /** + * Value for justification mode indicating the text is justified by stretching word spacing. + */ + public static final int JUSTIFICATION_MODE_INTER_WORD = 1; + /** * Return how wide a layout must be in order to display the specified text with one line per * paragraph. @@ -219,8 +234,8 @@ public abstract class Layout { } /** @hide */ - protected void setJustify(boolean justify) { - mJustify = justify; + protected void setJustificationMode(@JustificationMode int justificationMode) { + mJustificationMode = justificationMode; } /** @@ -272,7 +287,7 @@ public abstract class Layout { } private boolean isJustificationRequired(int lineNum) { - if (!mJustify) return false; + if (mJustificationMode == JUSTIFICATION_MODE_NONE) return false; final int lineEnd = getLineEnd(lineNum); return lineEnd < mText.length() && mText.charAt(lineEnd - 1) != '\n'; } @@ -2229,7 +2244,7 @@ public abstract class Layout { private boolean mSpannedText; private TextDirectionHeuristic mTextDir; private SpanSet<LineBackgroundSpan> mLineBackgroundSpans; - private boolean mJustify; + private int mJustificationMode; public static final int DIR_LEFT_TO_RIGHT = 1; public static final int DIR_RIGHT_TO_LEFT = -1; diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 9a2e0bb9a0b8..74ff6dc0ec7f 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -94,7 +94,7 @@ public class StaticLayout extends Layout { b.mMaxLines = Integer.MAX_VALUE; b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE; b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE; - b.mJustify = false; + b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE; b.mMeasuredText = MeasuredText.obtain(); return b; @@ -321,15 +321,15 @@ public class StaticLayout extends Layout { } /** - * Enables or disables paragraph justification. The default value is disabled (false). - * If the last line is too short for justification, the last line will be displayed with - * the alignment set by {@link #setAlignment}. + * Set paragraph justification mode. The default value is + * {@link Layout#JUSTIFICATION_MODE_NONE}. If the last line is too short for justification, + * the last line will be displayed with the alignment set by {@link #setAlignment}. * - * @param justify true for enabling and false for disabling paragraph justification. + * @param justificationMode justification mode for the paragraph. * @return this builder, useful for chaining. */ - public Builder setJustify(boolean justify) { - mJustify = justify; + public Builder setJustificationMode(@JustificationMode int justificationMode) { + mJustificationMode = justificationMode; return this; } @@ -418,7 +418,7 @@ public class StaticLayout extends Layout { int mHyphenationFrequency; int[] mLeftIndents; int[] mRightIndents; - boolean mJustify; + int mJustificationMode; Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt(); @@ -572,7 +572,7 @@ public class StaticLayout extends Layout { mLeftIndents = b.mLeftIndents; mRightIndents = b.mRightIndents; - setJustify(b.mJustify); + setJustificationMode(b.mJustificationMode); generate(b, b.mIncludePad, b.mIncludePad); } @@ -693,7 +693,8 @@ public class StaticLayout extends Layout { nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart, firstWidth, firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency, - b.mJustify); + // TODO: Support more justification mode, e.g. letter spacing, stretching. + b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE); if (mLeftIndents != null || mRightIndents != null) { // TODO(raph) performance: it would be better to do this once per layout rather // than once per paragraph, but that would require a change to the native diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 3316f3aeb60b..aac5baacdb11 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -529,6 +529,18 @@ public final class Choreographer { } } + /** + * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter + * whether callbacks are currently running. + * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base. + * @hide + */ + public long getLastFrameTimeNanos() { + synchronized (mLock) { + return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime(); + } + } + private void scheduleFrameLocked(long now) { if (!mFrameScheduled) { mFrameScheduled = true; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 5494377ceebd..6dedbde01995 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -50,7 +50,7 @@ import java.util.Arrays; * <li>The real display area specifies the part of the display that contains content * including the system decorations. Even so, the real display area may be smaller than the * physical size of the display if the window manager is emulating a smaller display - * using (adb shell am display-size). Use the following methods to query the + * using (adb shell wm size). Use the following methods to query the * real display area: {@link #getRealSize}, {@link #getRealMetrics}.</li> * </ul> * </p><p> @@ -947,7 +947,7 @@ public final class Display { * The size is adjusted based on the current rotation of the display. * </p><p> * The real size may be smaller than the physical size of the screen when the - * window manager is emulating a smaller display (using adb shell am display-size). + * window manager is emulating a smaller display (using adb shell wm size). * </p> * * @param outSize Set to the real size of the display. diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java index ae1ee42c8720..d25e5f04fad2 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -118,7 +118,7 @@ public class FocusFinder { * @return the "effective" root of {@param focused} */ private ViewGroup getEffectiveRoot(ViewGroup root, View focused) { - if (focused == null) { + if (focused == null || focused == root) { return root; } ViewParent effective = focused.getParent(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 884283dee789..b12a7676dd7f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -25523,7 +25523,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p> * The tooltip will be displayed: * <ul> - * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context + * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context * menu). </li> * <li>On hover, after a brief delay since the pointer has stopped moving </li> * </ul> diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index c250226ae713..830f5496160b 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -7344,6 +7344,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** @hide */ protected void onSetLayoutParams(View child, LayoutParams layoutParams) { + requestLayout(); } /** @hide */ diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 79b0420a77e3..958d76109a9e 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1018,9 +1018,20 @@ public final class InputMethodManager { } } - /** @hide */ + /** + * This method is still kept for a while until android.support.v7.widget.SearchView ver. 26.0 + * is publicly released because previous implementations of that class had relied on this method + * via reflection. + * + * @deprecated This is a hidden API. You should never use this. + * @hide + */ + @Deprecated public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) { try { + Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed " + + "soon. If you are using android.support.v7.widget.SearchView, please update " + + "to version 26.0 or newer version."); mService.showSoftInput(mClient, flags, resultReceiver); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 6f8df36b7bf5..1b60ebc6fc27 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -56,6 +56,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.graphics.fonts.FontVariationAxis; import android.os.AsyncTask; import android.os.Bundle; import android.os.LocaleList; @@ -609,7 +610,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mBreakStrategy; private int mHyphenationFrequency; - private boolean mJustify; + private int mJustificationMode; private int mMaximum = Integer.MAX_VALUE; private int mMaxMode = LINES; @@ -820,7 +821,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener String fontFeatureSettings = null; mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE; mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE; - mJustify = false; + mJustificationMode = Layout.JUSTIFICATION_MODE_NONE; final Resources.Theme theme = context.getTheme(); @@ -3737,14 +3738,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Enables or disables full justification. The default value is false. If the last line is too - * short for justification, the last line will be displayed with the alignment set by - * {@link android.view.View#setTextAlignment}. + * Set justification mode. The default value is {@link Layout#JUSTIFICATION_MODE_NONE}. If the + * last line is too short for justification, the last line will be displayed with the + * alignment set by {@link android.view.View#setTextAlignment}. * - * @see #getJustify() + * @see #getJustificationMode() */ - public void setJustify(boolean justify) { - mJustify = justify; + @Layout.JustificationMode + public void setJustificationMode(@Layout.JustificationMode int justificationMode) { + mJustificationMode = justificationMode; if (mLayout != null) { nullLayouts(); requestLayout(); @@ -3753,12 +3755,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * @return true if currently paragraph justification is enabled. + * @return true if currently paragraph justification mode. * - * @see #setJustify(boolean) + * @see #setJustificationMode(int) */ - public boolean getJustify() { - return mJustify; + public @Layout.JustificationMode int getJustificationMode() { + return mJustificationMode; } /** @@ -3808,10 +3810,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * TextView. This function also returns true for empty settings string. Otherwise * returns false. * + * @throws FontVariationAxis.InvalidFormatException + * If given string is not a valid font variation settings format. + * * @see #getFontVariationSettings() * @see Paint#getFontVariationSettings() Paint.getFontVariationSettings() */ - public boolean setFontVariationSettings(@Nullable String fontVariationSettings) { + public boolean setFontVariationSettings(@Nullable String fontVariationSettings) + throws FontVariationAxis.InvalidFormatException { final String existingSettings = mTextPaint.getFontVariationSettings(); if (fontVariationSettings == existingSettings || (fontVariationSettings != null @@ -7678,7 +7684,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) .setHyphenationFrequency(mHyphenationFrequency) - .setJustify(mJustify) + .setJustificationMode(mJustificationMode) .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); if (shouldEllipsize) { builder.setEllipsize(mEllipsize) @@ -7720,7 +7726,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mText instanceof Spannable) { result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, - mBreakStrategy, mHyphenationFrequency, mJustify, + mBreakStrategy, mHyphenationFrequency, mJustificationMode, getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth); } else { if (boring == UNKNOWN_BORING) { @@ -7770,7 +7776,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) .setHyphenationFrequency(mHyphenationFrequency) - .setJustify(mJustify) + .setJustificationMode(mJustificationMode) .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); if (shouldEllipsize) { builder.setEllipsize(effectiveEllipsize) @@ -8110,7 +8116,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setIncludePad(getIncludeFontPadding()) .setBreakStrategy(getBreakStrategy()) .setHyphenationFrequency(getHyphenationFrequency()) - .setJustify(getJustify()) + .setJustificationMode(getJustificationMode()) .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE) .setTextDirection(getTextDirectionHeuristic()); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index c235ebd4720d..df65659dface 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -23,21 +23,15 @@ import android.app.usage.UsageStatsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.LabeledIntent; -import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; -import android.content.pm.ShortcutInfo; -import android.content.pm.ShortcutManager; import android.database.DataSetObserver; import android.graphics.Color; import android.graphics.drawable.Drawable; @@ -362,7 +356,6 @@ public class ChooserActivity extends ResolverActivity { mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets)); } mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter); - mChooserRowAdapter.updateRowScales(); mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView)); adapterView.setAdapter(mChooserRowAdapter); if (listView != null) { @@ -849,9 +842,7 @@ public class ChooserActivity extends ResolverActivity { return false; } intent.setComponent(mChooserTarget.getComponentName()); - if (mChooserTarget.getIntentExtras() != null) { - intent.putExtras(mChooserTarget.getIntentExtras()); - } + intent.putExtras(mChooserTarget.getIntentExtras()); // Important: we will ignore the target security checks in ActivityManager // if and only if the ChooserTarget's target package is the same package @@ -934,8 +925,6 @@ public class ChooserActivity extends ResolverActivity { private static final int MAX_SERVICE_TARGETS = 8; private static final int MAX_TARGETS_PER_SERVICE = 4; - private boolean mAreChooserShortcutsRetrieved; - private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>(); private final List<TargetInfo> mCallerTargets = new ArrayList<>(); private boolean mShowServiceTargets; @@ -1027,21 +1016,6 @@ public class ChooserActivity extends ResolverActivity { if (mServiceTargets != null) { pruneServiceTargets(); } - - if (DEBUG) Log.d(TAG, "Adding pushed chooser targets"); - - if (!mAreChooserShortcutsRetrieved) { - LauncherApps launcherApps = getLauncherApps(); - LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); - query.setIntent(getTargetIntent()); - query.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_CHOOSER); - List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(query, - android.os.Process.myUserHandle()); - if (DEBUG) Log.d(TAG, "Adding " + shortcuts.size() + " chooser shortcuts"); - addShortcuts(shortcuts); - mAreChooserShortcutsRetrieved = true; - } - if (DEBUG) Log.d(TAG, "List built querying services"); queryTargetServices(this); } @@ -1067,7 +1041,6 @@ public class ChooserActivity extends ResolverActivity { public int getServiceTargetCount() { if (!mShowServiceTargets) { - if (DEBUG) Log.d("TAG", "Hiding service targets"); return 0; } return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS); @@ -1159,71 +1132,6 @@ public class ChooserActivity extends ResolverActivity { notifyDataSetChanged(); } - // TODO: Pushed targets need to be scored correctly - public void addShortcuts(List<ShortcutInfo> infos) { - for (ShortcutInfo info : infos) { - List<ChooserTarget> newTargets = new ArrayList<>(); - final ComponentName cn = info.getActivity(); - ActivityInfo ai; - ResolveInfo ri = new ResolveInfo(); - if (cn != null) { - try { - ai = getPackageManager().getActivityInfo(cn, 0); - ri.activityInfo = ai; - UserManager userManager = - (UserManager) getSystemService(Context.USER_SERVICE); - ri.iconResourceId = ai.icon; - ri.labelRes = ai.labelRes; - ri.resolvePackageName = ai.packageName; - ri.activityInfo.applicationInfo = new ApplicationInfo( - ri.activityInfo.applicationInfo); - ri.activityInfo.applicationInfo = ai.applicationInfo; - ri.activityInfo.applicationInfo.uid = getUserId(); - } catch (PackageManager.NameNotFoundException ignored) { - if (DEBUG) Log.d(TAG, "Package not found, skipping this shortcut"); - continue; - } - } - - DisplayResolveInfo resolveInfo = new DisplayResolveInfo(getTargetIntent(), - ri, - info.getShortLabel(), - info.getLongLabel(), - getTargetIntent()); - - int bestMatch = 0; - ComponentName bestComponent = null; - for (int i = 0; i < info.getChooserIntentFilters().length; i++) { - int newMatch = info.getChooserIntentFilters()[i] - .match(getContentResolver(), getTargetIntent(), false, TAG); - if (DEBUG) Log.d(TAG, "A match was found with value: " + newMatch); - if (newMatch > bestMatch) { - bestMatch = newMatch; - bestComponent = info.getChooserComponentNames()[i]; - } - } - if (bestMatch == 0) { - Log.e(TAG, "Unexpectedly, no match was found for the provided chooser intent"); - return; - } - - Bundle extrasToAdd = - info.getChooserExtras() == null ? null: new Bundle(info.getChooserExtras()); - if (DEBUG) Log.d(TAG, "Adding service target " + info.getShortLabel()); - newTargets.add(new ChooserTarget( - info.getShortLabel(), - info.getIcon(), - 1, - bestComponent, - extrasToAdd)); - addServiceResults(resolveInfo, newTargets); - } - if (mChooserRowAdapter != null) { - mChooserRowAdapter.updateRowScales(); - } - setShowServiceTargets(true); - } - /** * Set to true to reveal all service targets at once. */ @@ -1338,7 +1246,37 @@ public class ChooserActivity extends ResolverActivity { @Override public void onChanged() { super.onChanged(); - updateRowScales(); + final int rcount = getServiceTargetRowCount(); + if (mServiceTargetScale == null + || mServiceTargetScale.length != rcount) { + RowScale[] old = mServiceTargetScale; + int oldRCount = old != null ? old.length : 0; + mServiceTargetScale = new RowScale[rcount]; + if (old != null && rcount > 0) { + System.arraycopy(old, 0, mServiceTargetScale, 0, + Math.min(old.length, rcount)); + } + + for (int i = rcount; i < oldRCount; i++) { + old[i].cancelAnimation(); + } + + for (int i = oldRCount; i < rcount; i++) { + final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f) + .setInterpolator(mInterpolator); + mServiceTargetScale[i] = rs; + } + + // Start the animations in a separate loop. + // The process of starting animations will result in + // binding views to set up initial values, and we must + // have ALL of the new RowScale objects created above before + // we get started. + for (int i = oldRCount; i < rcount; i++) { + mServiceTargetScale[i].startAnimation(); + } + } + notifyDataSetChanged(); } @@ -1355,40 +1293,6 @@ public class ChooserActivity extends ResolverActivity { }); } - void updateRowScales() { - final int rcount = getServiceTargetRowCount(); - if (mServiceTargetScale == null - || mServiceTargetScale.length != rcount) { - if (DEBUG) Log.d(TAG, "Row scales need adjusting to " + rcount + " rows."); - RowScale[] old = mServiceTargetScale; - int oldRCount = old != null ? old.length : 0; - mServiceTargetScale = new RowScale[rcount]; - if (old != null && rcount > 0) { - System.arraycopy(old, 0, mServiceTargetScale, 0, - Math.min(old.length, rcount)); - } - - for (int i = rcount; i < oldRCount; i++) { - old[i].cancelAnimation(); - } - - for (int i = oldRCount; i < rcount; i++) { - final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f) - .setInterpolator(mInterpolator); - mServiceTargetScale[i] = rs; - } - - // Start the animations in a separate loop. - // The process of starting animations will result in - // binding views to set up initial values, and we must - // have ALL of the new RowScale objects created above before - // we get started. - for (int i = oldRCount; i < rcount; i++) { - mServiceTargetScale[i].startAnimation(); - } - } - } - private float getRowScale(int rowPosition) { final int start = getCallerTargetRowCount(); final int end = start + getServiceTargetRowCount(); @@ -1659,10 +1563,6 @@ public class ChooserActivity extends ResolverActivity { } } - public LauncherApps getLauncherApps() { - return (LauncherApps) getSystemService(Context.LAUNCHER_APPS_SERVICE); - } - static class ServiceResultInfo { public final DisplayResolveInfo originalTarget; public final List<ChooserTarget> resultTargets; diff --git a/core/java/com/android/internal/app/LRResolverRankerService.java b/core/java/com/android/internal/app/LRResolverRankerService.java new file mode 100644 index 000000000000..1cad7c770b7c --- /dev/null +++ b/core/java/com/android/internal/app/LRResolverRankerService.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2017 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.app; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Environment; +import android.os.IBinder; +import android.os.storage.StorageManager; +import android.service.resolver.ResolverRankerService; +import android.service.resolver.ResolverTarget; +import android.util.ArrayMap; +import android.util.Log; + +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * A Logistic Regression based {@link android.service.resolver.ResolverRankerService}, to be used + * in {@link ResolverComparator}. + */ +public final class LRResolverRankerService extends ResolverRankerService { + private static final String TAG = "LRResolverRankerService"; + + private static final boolean DEBUG = false; + + private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params"; + private static final String BIAS_PREF_KEY = "bias"; + private static final String VERSION_PREF_KEY = "version"; + + private static final String LAUNCH_SCORE = "launch"; + private static final String TIME_SPENT_SCORE = "timeSpent"; + private static final String RECENCY_SCORE = "recency"; + private static final String CHOOSER_SCORE = "chooser"; + + // parameters for a pre-trained model, to initialize the app ranker. When updating the + // pre-trained model, please update these params, as well as initModel(). + private static final int CURRENT_VERSION = 1; + private static final float LEARNING_RATE = 0.0001f; + private static final float REGULARIZER_PARAM = 0.0001f; + + private SharedPreferences mParamSharedPref; + private ArrayMap<String, Float> mFeatureWeights; + private float mBias; + + @Override + public IBinder onBind(Intent intent) { + initModel(); + return super.onBind(intent); + } + + @Override + public void onPredictSharingProbabilities(List<ResolverTarget> targets) { + final int size = targets.size(); + for (int i = 0; i < size; ++i) { + ResolverTarget target = targets.get(i); + ArrayMap<String, Float> features = getFeatures(target); + target.setSelectProbability(predict(features)); + } + } + + @Override + public void onTrainRankingModel(List<ResolverTarget> targets, int selectedPosition) { + final int size = targets.size(); + if (selectedPosition < 0 || selectedPosition >= size) { + if (DEBUG) { + Log.d(TAG, "Invalid Position of Selected App " + selectedPosition); + } + return; + } + final ArrayMap<String, Float> positive = getFeatures(targets.get(selectedPosition)); + final float positiveProbability = targets.get(selectedPosition).getSelectProbability(); + final int targetSize = targets.size(); + for (int i = 0; i < targetSize; ++i) { + if (i == selectedPosition) { + continue; + } + final ArrayMap<String, Float> negative = getFeatures(targets.get(i)); + final float negativeProbability = targets.get(i).getSelectProbability(); + if (negativeProbability > positiveProbability) { + update(negative, negativeProbability, false); + update(positive, positiveProbability, true); + } + } + commitUpdate(); + } + + private void initModel() { + mParamSharedPref = getParamSharedPref(); + mFeatureWeights = new ArrayMap<>(4); + if (mParamSharedPref == null || + mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) { + // Initializing the app ranker to a pre-trained model. When updating the pre-trained + // model, please increment CURRENT_VERSION, and update LEARNING_RATE and + // REGULARIZER_PARAM. + mBias = -1.6568f; + mFeatureWeights.put(LAUNCH_SCORE, 2.5543f); + mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f); + mFeatureWeights.put(RECENCY_SCORE, 0.269f); + mFeatureWeights.put(CHOOSER_SCORE, 4.2222f); + } else { + mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f); + mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f)); + mFeatureWeights.put( + TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f)); + mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f)); + mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f)); + } + } + + private ArrayMap<String, Float> getFeatures(ResolverTarget target) { + ArrayMap<String, Float> features = new ArrayMap<>(4); + features.put(RECENCY_SCORE, target.getRecencyScore()); + features.put(TIME_SPENT_SCORE, target.getTimeSpentScore()); + features.put(LAUNCH_SCORE, target.getLaunchScore()); + features.put(CHOOSER_SCORE, target.getChooserScore()); + return features; + } + + private float predict(ArrayMap<String, Float> target) { + if (target == null) { + return 0.0f; + } + final int featureSize = target.size(); + float sum = 0.0f; + for (int i = 0; i < featureSize; i++) { + String featureName = target.keyAt(i); + float weight = mFeatureWeights.getOrDefault(featureName, 0.0f); + sum += weight * target.valueAt(i); + } + return (float) (1.0 / (1.0 + Math.exp(-mBias - sum))); + } + + private void update(ArrayMap<String, Float> target, float predict, boolean isSelected) { + if (target == null) { + return; + } + final int featureSize = target.size(); + float error = isSelected ? 1.0f - predict : -predict; + for (int i = 0; i < featureSize; i++) { + String featureName = target.keyAt(i); + float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f); + mBias += LEARNING_RATE * error; + currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight + + LEARNING_RATE * error * target.valueAt(i); + mFeatureWeights.put(featureName, currentWeight); + } + if (DEBUG) { + Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias); + } + } + + private void commitUpdate() { + try { + SharedPreferences.Editor editor = mParamSharedPref.edit(); + editor.putFloat(BIAS_PREF_KEY, mBias); + final int size = mFeatureWeights.size(); + for (int i = 0; i < size; i++) { + editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i)); + } + editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION); + editor.apply(); + } catch (Exception e) { + Log.e(TAG, "Failed to commit update" + e); + } + } + + private SharedPreferences getParamSharedPref() { + // The package info in the context isn't initialized in the way it is for normal apps, + // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we + // build the path manually below using the same policy that appears in ContextImpl. + if (DEBUG) { + Log.d(TAG, "Context Package Name: " + getPackageName()); + } + final File prefsFile = new File(new File( + Environment.getDataUserCePackageDirectory( + StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()), + "shared_prefs"), + PARAM_SHARED_PREF_NAME + ".xml"); + return getSharedPreferences(prefsFile, Context.MODE_PRIVATE); + } +}
\ No newline at end of file diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 3f1c9adb1b68..622b70843cc2 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -530,6 +530,9 @@ public class ResolverActivity extends Activity { getMainThreadHandler().removeCallbacks(mPostListReadyRunnable); mPostListReadyRunnable = null; } + if (mAdapter != null && mAdapter.mResolverListController != null) { + mAdapter.mResolverListController.destroy(); + } } @Override diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java index 096fcb83e755..73b62a5fe60d 100644 --- a/core/java/com/android/internal/app/ResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverComparator.java @@ -26,20 +26,34 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.SharedPreferences; +import android.content.ServiceConnection; import android.os.Environment; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; import android.os.storage.StorageManager; import android.os.UserHandle; +import android.service.resolver.IResolverRankerService; +import android.service.resolver.IResolverRankerResult; +import android.service.resolver.ResolverRankerService; +import android.service.resolver.ResolverTarget; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import java.io.File; +import java.lang.InterruptedException; import java.text.Collator; import java.util.ArrayList; import java.util.Comparator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -61,11 +75,15 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { private static final float RECENCY_MULTIPLIER = 2.f; - // feature names used in ranking. - private static final String LAUNCH_SCORE = "launch"; - private static final String TIME_SPENT_SCORE = "timeSpent"; - private static final String RECENCY_SCORE = "recency"; - private static final String CHOOSER_SCORE = "chooser"; + // message types + private static final int RESOLVER_RANKER_SERVICE_RESULT = 0; + private static final int RESOLVER_RANKER_RESULT_TIMEOUT = 1; + + // timeout for establishing connections with a ResolverRankerService. + private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200; + // timeout for establishing connections with a ResolverRankerService, collecting features and + // predicting ranking scores. + private static final int WATCHDOG_TIMEOUT_MILLIS = 500; private final Collator mCollator; private final boolean mHttp; @@ -74,18 +92,74 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { private final Map<String, UsageStats> mStats; private final long mCurrentTime; private final long mSinceTime; - private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>(); + private final LinkedHashMap<ComponentName, ResolverTarget> mTargetsDict = new LinkedHashMap<>(); private final String mReferrerPackage; + private final Object mLock = new Object(); + private ArrayList<ResolverTarget> mTargets; private String mContentType; private String[] mAnnotations; private String mAction; - private LogisticRegressionAppRanker mRanker; + private IResolverRankerService mRanker; + private ResolverRankerServiceConnection mConnection; + private AfterCompute mAfterCompute; + private Context mContext; + private CountDownLatch mConnectSignal; + + private final Handler mHandler = new Handler(Looper.getMainLooper()) { + public void handleMessage(Message msg) { + switch (msg.what) { + case RESOLVER_RANKER_SERVICE_RESULT: + if (DEBUG) { + Log.d(TAG, "RESOLVER_RANKER_SERVICE_RESULT"); + } + if (mHandler.hasMessages(RESOLVER_RANKER_RESULT_TIMEOUT)) { + if (msg.obj != null) { + final List<ResolverTarget> receivedTargets = + (List<ResolverTarget>) msg.obj; + if (receivedTargets != null && mTargets != null + && receivedTargets.size() == mTargets.size()) { + final int size = mTargets.size(); + for (int i = 0; i < size; ++i) { + mTargets.get(i).setSelectProbability( + receivedTargets.get(i).getSelectProbability()); + } + } else { + Log.e(TAG, "Sizes of sent and received ResolverTargets diff."); + } + } else { + Log.e(TAG, "Receiving null prediction results."); + } + mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT); + mAfterCompute.afterCompute(); + } + break; + + case RESOLVER_RANKER_RESULT_TIMEOUT: + if (DEBUG) { + Log.d(TAG, "RESOLVER_RANKER_RESULT_TIMEOUT; unbinding services"); + } + mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT); + mAfterCompute.afterCompute(); + break; - public ResolverComparator(Context context, Intent intent, String referrerPackage) { + default: + super.handleMessage(msg); + } + } + }; + + public interface AfterCompute { + public void afterCompute (); + } + + public ResolverComparator(Context context, Intent intent, String referrerPackage, + AfterCompute afterCompute) { mCollator = Collator.getInstance(context.getResources().getConfiguration().locale); String scheme = intent.getScheme(); mHttp = "http".equals(scheme) || "https".equals(scheme); mReferrerPackage = referrerPackage; + mAfterCompute = afterCompute; + mContext = context; mPm = context.getPackageManager(); mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE); @@ -96,9 +170,9 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { mContentType = intent.getType(); getContentAnnotations(intent); mAction = intent.getAction(); - mRanker = new LogisticRegressionAppRanker(context); } + // get annotations of content from intent. public void getContentAnnotations(Intent intent) { ArrayList<String> annotations = intent.getStringArrayListExtra( Intent.EXTRA_CONTENT_ANNOTATIONS); @@ -114,20 +188,24 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { } } + public void setCallBack(AfterCompute afterCompute) { + mAfterCompute = afterCompute; + } + + // compute features for each target according to usage stats of targets. public void compute(List<ResolvedComponentInfo> targets) { - mScoredTargets.clear(); + reset(); final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD; - long mostRecentlyUsedTime = recentSinceTime + 1; - long mostTimeSpent = 1; - int mostLaunched = 1; - int mostSelected = 1; + float mostRecencyScore = 1.0f; + float mostTimeSpentScore = 1.0f; + float mostLaunchScore = 1.0f; + float mostChooserScore = 1.0f; for (ResolvedComponentInfo target : targets) { - final ScoredTarget scoredTarget - = new ScoredTarget(target.getResolveInfoAt(0).activityInfo); - mScoredTargets.put(target.name, scoredTarget); + final ResolverTarget resolverTarget = new ResolverTarget(); + mTargetsDict.put(target.name, resolverTarget); final UsageStats pkStats = mStats.get(target.name.getPackageName()); if (pkStats != null) { // Only count recency for apps that weren't the caller @@ -135,31 +213,33 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { // Persistent processes muck this up, so omit them too. if (!target.name.getPackageName().equals(mReferrerPackage) && !isPersistentProcess(target)) { - final long lastTimeUsed = pkStats.getLastTimeUsed(); - scoredTarget.lastTimeUsed = lastTimeUsed; - if (lastTimeUsed > mostRecentlyUsedTime) { - mostRecentlyUsedTime = lastTimeUsed; + final float recencyScore = + (float) Math.max(pkStats.getLastTimeUsed() - recentSinceTime, 0); + resolverTarget.setRecencyScore(recencyScore); + if (recencyScore > mostRecencyScore) { + mostRecencyScore = recencyScore; } } - final long timeSpent = pkStats.getTotalTimeInForeground(); - scoredTarget.timeSpent = timeSpent; - if (timeSpent > mostTimeSpent) { - mostTimeSpent = timeSpent; + final float timeSpentScore = (float) pkStats.getTotalTimeInForeground(); + resolverTarget.setTimeSpentScore(timeSpentScore); + if (timeSpentScore > mostTimeSpentScore) { + mostTimeSpentScore = timeSpentScore; } - final int launched = pkStats.mLaunchCount; - scoredTarget.launchCount = launched; - if (launched > mostLaunched) { - mostLaunched = launched; + final float launchScore = (float) pkStats.mLaunchCount; + resolverTarget.setLaunchScore(launchScore); + if (launchScore > mostLaunchScore) { + mostLaunchScore = launchScore; } - int selected = 0; + float chooserScore = 0.0f; if (pkStats.mChooserCounts != null && mAction != null && pkStats.mChooserCounts.get(mAction) != null) { - selected = pkStats.mChooserCounts.get(mAction).getOrDefault(mContentType, 0); + chooserScore = (float) pkStats.mChooserCounts.get(mAction) + .getOrDefault(mContentType, 0); if (mAnnotations != null) { final int size = mAnnotations.length; for (int i = 0; i < size; i++) { - selected += pkStats.mChooserCounts.get(mAction) + chooserScore += (float) pkStats.mChooserCounts.get(mAction) .getOrDefault(mAnnotations[i], 0); } } @@ -169,44 +249,37 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { Log.d(TAG, "Action type is null"); } else { Log.d(TAG, "Chooser Count of " + mAction + ":" + - target.name.getPackageName() + " is " + Integer.toString(selected)); + target.name.getPackageName() + " is " + + Float.toString(chooserScore)); } } - scoredTarget.chooserCount = selected; - if (selected > mostSelected) { - mostSelected = selected; + resolverTarget.setChooserScore(chooserScore); + if (chooserScore > mostChooserScore) { + mostChooserScore = chooserScore; } } } - if (DEBUG) { - Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime - + " mostTimeSpent: " + mostTimeSpent - + " recentSinceTime: " + recentSinceTime - + " mostLaunched: " + mostLaunched); + Log.d(TAG, "compute - mostRecencyScore: " + mostRecencyScore + + " mostTimeSpentScore: " + mostTimeSpentScore + + " mostLaunchScore: " + mostLaunchScore + + " mostChooserScore: " + mostChooserScore); } - for (ScoredTarget target : mScoredTargets.values()) { - final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0) - / (mostRecentlyUsedTime - recentSinceTime); - target.setFeatures((float) target.launchCount / mostLaunched, - (float) target.timeSpent / mostTimeSpent, - recency * recency * RECENCY_MULTIPLIER, - (float) target.chooserCount / mostSelected); - target.selectProb = mRanker.predict(target.getFeatures()); + mTargets = new ArrayList<>(mTargetsDict.values()); + for (ResolverTarget target : mTargets) { + final float recency = target.getRecencyScore() / mostRecencyScore; + setFeatures(target, recency * recency * RECENCY_MULTIPLIER, + target.getLaunchScore() / mostLaunchScore, + target.getTimeSpentScore() / mostTimeSpentScore, + target.getChooserScore() / mostChooserScore); + addDefaultSelectProbability(target); if (DEBUG) { Log.d(TAG, "Scores: " + target); } } - } - - static boolean isPersistentProcess(ResolvedComponentInfo rci) { - if (rci != null && rci.getCount() > 0) { - return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags & - ApplicationInfo.FLAG_PERSISTENT) != 0; - } - return false; + predictSelectProbabilities(mTargets); } @Override @@ -245,16 +318,16 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { // Pinned items stay stable within a normal lexical sort and ignore scoring. if (!lPinned && !rPinned) { if (mStats != null) { - final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName( + final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName( lhs.activityInfo.packageName, lhs.activityInfo.name)); - final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName( + final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName( rhs.activityInfo.packageName, rhs.activityInfo.name)); - final int selectProbDiff = Float.compare( - rhsTarget.selectProb, lhsTarget.selectProb); + final int selectProbabilityDiff = Float.compare( + rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability()); - if (selectProbDiff != 0) { - return selectProbDiff > 0 ? 1 : -1; + if (selectProbabilityDiff != 0) { + return selectProbabilityDiff > 0 ? 1 : -1; } } } @@ -268,177 +341,234 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { } public float getScore(ComponentName name) { - final ScoredTarget target = mScoredTargets.get(name); + final ResolverTarget target = mTargetsDict.get(name); if (target != null) { - return target.selectProb; + return target.getSelectProbability(); } return 0; } - static class ScoredTarget { - public final ComponentInfo componentInfo; - public long lastTimeUsed; - public long timeSpent; - public long launchCount; - public long chooserCount; - public ArrayMap<String, Float> features; - public float selectProb; - - public ScoredTarget(ComponentInfo ci) { - componentInfo = ci; - features = new ArrayMap<>(5); + public void updateChooserCounts(String packageName, int userId, String action) { + if (mUsm != null) { + mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action); } + } - @Override - public String toString() { - return "ScoredTarget{" + componentInfo - + " lastTimeUsed: " + lastTimeUsed - + " timeSpent: " + timeSpent - + " launchCount: " + launchCount - + " chooserCount: " + chooserCount - + " selectProb: " + selectProb - + "}"; + // update ranking model when the connection to it is valid. + public void updateModel(ComponentName componentName) { + synchronized (mLock) { + if (mRanker != null) { + try { + int selectedPos = new ArrayList<ComponentName>(mTargetsDict.keySet()) + .indexOf(componentName); + if (selectedPos > 0) { + mRanker.train(mTargets, selectedPos); + } else { + if (DEBUG) { + Log.d(TAG, "Selected a unknown component: " + componentName); + } + } + } catch (RemoteException e) { + Log.e(TAG, "Error in Train: " + e); + } + } else { + if (DEBUG) { + Log.d(TAG, "Ranker is null; skip updateModel."); + } + } } + } - public void setFeatures(float launchCountScore, float usageTimeScore, float recencyScore, - float chooserCountScore) { - features.put(LAUNCH_SCORE, launchCountScore); - features.put(TIME_SPENT_SCORE, usageTimeScore); - features.put(RECENCY_SCORE, recencyScore); - features.put(CHOOSER_SCORE, chooserCountScore); + // unbind the service and clear unhandled messges. + public void destroy() { + mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT); + mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT); + if (mConnection != null) { + mContext.unbindService(mConnection); + mConnection.destroy(); } - - public ArrayMap<String, Float> getFeatures() { - return features; + if (DEBUG) { + Log.d(TAG, "Unbinded Resolver Ranker."); } } - public void updateChooserCounts(String packageName, int userId, String action) { - if (mUsm != null) { - mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action); + // connect to a ranking service. + private void initRanker(Context context) { + synchronized (mLock) { + if (mConnection != null && mRanker != null) { + if (DEBUG) { + Log.d(TAG, "Ranker still exists; reusing the existing one."); + } + return; + } } - } - - public void updateModel(ComponentName componentName) { - if (mScoredTargets == null || componentName == null || - !mScoredTargets.containsKey(componentName)) { + Intent intent = resolveRankerService(); + if (intent == null) { return; } - ScoredTarget selected = mScoredTargets.get(componentName); - for (ComponentName targetComponent : mScoredTargets.keySet()) { - if (targetComponent.equals(componentName)) { + mConnectSignal = new CountDownLatch(1); + mConnection = new ResolverRankerServiceConnection(mConnectSignal); + context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); + } + + // resolve the service for ranking. + private Intent resolveRankerService() { + Intent intent = new Intent(ResolverRankerService.SERVICE_INTERFACE); + final List<ResolveInfo> resolveInfos = mPm.queryIntentServices(intent, 0); + for (ResolveInfo resolveInfo : resolveInfos) { + if (resolveInfo == null || resolveInfo.serviceInfo == null + || resolveInfo.serviceInfo.applicationInfo == null) { + if (DEBUG) { + Log.d(TAG, "Failed to retrieve a ranker: " + resolveInfo); + } continue; } - ScoredTarget target = mScoredTargets.get(targetComponent); - // A potential point of optimization. Save updates or derive a closed form for the - // positive case, to avoid calculating them repeatedly. - if (target.selectProb >= selected.selectProb) { - mRanker.update(target.getFeatures(), target.selectProb, false); - mRanker.update(selected.getFeatures(), selected.selectProb, true); + ComponentName componentName = new ComponentName( + resolveInfo.serviceInfo.applicationInfo.packageName, + resolveInfo.serviceInfo.name); + try { + final String perm = mPm.getServiceInfo(componentName, 0).permission; + if (!ResolverRankerService.BIND_PERMISSION.equals(perm)) { + Log.w(TAG, "ResolverRankerService " + componentName + " does not require" + + " permission " + ResolverRankerService.BIND_PERMISSION + + " - this service will not be queried for ResolverComparator." + + " add android:permission=\"" + + ResolverRankerService.BIND_PERMISSION + "\"" + + " to the <service> tag for " + componentName + + " in the manifest."); + continue; + } + } catch (NameNotFoundException e) { + Log.e(TAG, "Could not look up service " + componentName + + "; component name not found"); + continue; + } + if (DEBUG) { + Log.d(TAG, "Succeeded to retrieve a ranker: " + componentName); } + intent.setComponent(componentName); + return intent; } - mRanker.commitUpdate(); + return null; } - class LogisticRegressionAppRanker { - private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params"; - private static final String BIAS_PREF_KEY = "bias"; - private static final String VERSION_PREF_KEY = "version"; - - // parameters for a pre-trained model, to initialize the app ranker. When updating the - // pre-trained model, please update these params, as well as initModel(). - private static final int CURRENT_VERSION = 1; - private static final float LEARNING_RATE = 0.0001f; - private static final float REGULARIZER_PARAM = 0.0001f; + // set a watchdog, to avoid waiting for ranking service for too long. + private void startWatchDog(int timeOutLimit) { + if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + timeOutLimit + "ms"); + if (mHandler == null) { + Log.d(TAG, "Error: Handler is Null; Needs to be initialized."); + } + mHandler.sendEmptyMessageDelayed(RESOLVER_RANKER_RESULT_TIMEOUT, timeOutLimit); + } - private SharedPreferences mParamSharedPref; - private ArrayMap<String, Float> mFeatureWeights; - private float mBias; + private class ResolverRankerServiceConnection implements ServiceConnection { + private final CountDownLatch mConnectSignal; - public LogisticRegressionAppRanker(Context context) { - mParamSharedPref = getParamSharedPref(context); - initModel(); + public ResolverRankerServiceConnection(CountDownLatch connectSignal) { + mConnectSignal = connectSignal; } - public float predict(ArrayMap<String, Float> target) { - if (target == null) { - return 0.0f; - } - final int featureSize = target.size(); - float sum = 0.0f; - for (int i = 0; i < featureSize; i++) { - String featureName = target.keyAt(i); - float weight = mFeatureWeights.getOrDefault(featureName, 0.0f); - sum += weight * target.valueAt(i); + public final IResolverRankerResult resolverRankerResult = + new IResolverRankerResult.Stub() { + @Override + public void sendResult(List<ResolverTarget> targets) throws RemoteException { + if (DEBUG) { + Log.d(TAG, "Sending Result back to Resolver: " + targets); + } + synchronized (mLock) { + final Message msg = Message.obtain(); + msg.what = RESOLVER_RANKER_SERVICE_RESULT; + msg.obj = targets; + mHandler.sendMessage(msg); + } } - return (float) (1.0 / (1.0 + Math.exp(-mBias - sum))); - } + }; - public void update(ArrayMap<String, Float> target, float predict, boolean isSelected) { - if (target == null) { - return; + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) { + Log.d(TAG, "onServiceConnected: " + name); } - final int featureSize = target.size(); - float error = isSelected ? 1.0f - predict : -predict; - for (int i = 0; i < featureSize; i++) { - String featureName = target.keyAt(i); - float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f); - mBias += LEARNING_RATE * error; - currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight + - LEARNING_RATE * error * target.valueAt(i); - mFeatureWeights.put(featureName, currentWeight); + synchronized (mLock) { + mRanker = IResolverRankerService.Stub.asInterface(service); + mConnectSignal.countDown(); } + } + + @Override + public void onServiceDisconnected(ComponentName name) { if (DEBUG) { - Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias); + Log.d(TAG, "onServiceDisconnected: " + name); + } + synchronized (mLock) { + destroy(); } } - public void commitUpdate() { - SharedPreferences.Editor editor = mParamSharedPref.edit(); - editor.putFloat(BIAS_PREF_KEY, mBias); - final int size = mFeatureWeights.size(); - for (int i = 0; i < size; i++) { - editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i)); + public void destroy() { + synchronized (mLock) { + mRanker = null; } - editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION); - editor.apply(); } + } - private SharedPreferences getParamSharedPref(Context context) { - // The package info in the context isn't initialized in the way it is for normal apps, - // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we - // build the path manually below using the same policy that appears in ContextImpl. + private void reset() { + mTargetsDict.clear(); + mTargets = null; + startWatchDog(WATCHDOG_TIMEOUT_MILLIS); + initRanker(mContext); + } + + // predict select probabilities if ranking service is valid. + private void predictSelectProbabilities(List<ResolverTarget> targets) { + if (mConnection == null) { if (DEBUG) { - Log.d(TAG, "Context Package Name: " + context.getPackageName()); + Log.d(TAG, "Has not found valid ResolverRankerService; Skip Prediction"); + } + return; + } else { + try { + mConnectSignal.await(CONNECTION_COST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + synchronized (mLock) { + if (mRanker != null) { + mRanker.predict(targets, mConnection.resolverRankerResult); + return; + } else { + if (DEBUG) { + Log.d(TAG, "Ranker has not been initialized; skip predict."); + } + } + } + } catch (InterruptedException e) { + Log.e(TAG, "Error in Wait for Service Connection."); + } catch (RemoteException e) { + Log.e(TAG, "Error in Predict: " + e); } - final File prefsFile = new File(new File( - Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL, - context.getUserId(), context.getPackageName()), - "shared_prefs"), - PARAM_SHARED_PREF_NAME + ".xml"); - return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE); } + mAfterCompute.afterCompute(); + } - private void initModel() { - mFeatureWeights = new ArrayMap<>(4); - if (mParamSharedPref == null || - mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) { - // Initializing the app ranker to a pre-trained model. When updating the pre-trained - // model, please increment CURRENT_VERSION, and update LEARNING_RATE and - // REGULARIZER_PARAM. - mBias = -1.6568f; - mFeatureWeights.put(LAUNCH_SCORE, 2.5543f); - mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f); - mFeatureWeights.put(RECENCY_SCORE, 0.269f); - mFeatureWeights.put(CHOOSER_SCORE, 4.2222f); - } else { - mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f); - mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f)); - mFeatureWeights.put( - TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f)); - mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f)); - mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f)); - } + // adds select prob as the default values, according to a pre-trained Logistic Regression model. + private void addDefaultSelectProbability(ResolverTarget target) { + float sum = 2.5543f * target.getLaunchScore() + 2.8412f * target.getTimeSpentScore() + + 0.269f * target.getRecencyScore() + 4.2222f * target.getChooserScore(); + target.setSelectProbability((float) (1.0 / (1.0 + Math.exp(1.6568f - sum)))); + } + + // sets features for each target + private void setFeatures(ResolverTarget target, float recencyScore, float launchScore, + float timeSpentScore, float chooserScore) { + target.setRecencyScore(recencyScore); + target.setLaunchScore(launchScore); + target.setTimeSpentScore(timeSpentScore); + target.setChooserScore(chooserScore); + } + + static boolean isPersistentProcess(ResolvedComponentInfo rci) { + if (rci != null && rci.getCount() > 0) { + return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags & + ApplicationInfo.FLAG_PERSISTENT) != 0; } + return false; } } diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index 4071ff4ebd5a..e8bebb74bdd0 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -32,8 +32,10 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import java.lang.InterruptedException; import java.util.ArrayList; import java.util.Collections; +import java.util.concurrent.CountDownLatch; import java.util.List; /** @@ -205,14 +207,42 @@ public class ResolverListController { return listToReturn; } + private class ComputeCallback implements ResolverComparator.AfterCompute { + + private CountDownLatch mFinishComputeSignal; + + public ComputeCallback(CountDownLatch finishComputeSignal) { + mFinishComputeSignal = finishComputeSignal; + } + + public void afterCompute () { + mFinishComputeSignal.countDown(); + } + } + @VisibleForTesting @WorkerThread public void sort(List<ResolverActivity.ResolvedComponentInfo> inputList) { + final CountDownLatch finishComputeSignal = new CountDownLatch(1); + ComputeCallback callback = new ComputeCallback(finishComputeSignal); if (mResolverComparator == null) { - mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage); + mResolverComparator = + new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, callback); + } else { + mResolverComparator.setCallBack(callback); + } + try { + long beforeRank = System.currentTimeMillis(); + mResolverComparator.compute(inputList); + finishComputeSignal.await(); + Collections.sort(inputList, mResolverComparator); + long afterRank = System.currentTimeMillis(); + if (DEBUG) { + Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank)); + } + } catch (InterruptedException e) { + Log.e(TAG, "Compute & Sort was interrupted: " + e); } - mResolverComparator.compute(inputList); - Collections.sort(inputList, mResolverComparator); } private static boolean isSameResolvedComponent(ResolveInfo a, @@ -233,7 +263,7 @@ public class ResolverListController { @VisibleForTesting public float getScore(ResolverActivity.DisplayResolveInfo target) { if (mResolverComparator == null) { - mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage); + return 0.0f; } return mResolverComparator.getScore(target.getResolvedComponentName()); } @@ -249,4 +279,10 @@ public class ResolverListController { mResolverComparator.updateChooserCounts(packageName, userId, action); } } + + public void destroy() { + if (mResolverComparator != null) { + mResolverComparator.destroy(); + } + } } diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java index 1abb59b006dd..a70209c705c0 100644 --- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java +++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java @@ -74,6 +74,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame private final Rect mOldStableInsets = new Rect(); private final Rect mSystemInsets = new Rect(); private final Rect mStableInsets = new Rect(); + private final Rect mTmpRect = new Rect(); public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds, Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable, @@ -370,12 +371,6 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height); mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height); final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top); - final int bottomInset = DecorView.getColorViewBottomInset(stableInsets.bottom, - systemInsets.bottom); - final int rightInset = DecorView.getColorViewRightInset(stableInsets.right, - systemInsets.right); - final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left, - systemInsets.left); if (mStatusBarColor != null) { mStatusBarColor.setBounds(0, 0, left + width, topInset); mStatusBarColor.draw(canvas); @@ -385,14 +380,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame // don't want the navigation bar background be moving around when resizing in docked mode. // However, we need it for the transitions into/out of docked mode. if (mNavigationBarColor != null && fullscreen) { - final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset); - if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) { - mNavigationBarColor.setBounds(width - size, 0, width, height); - } else if (DecorView.isNavBarToLeftEdge(bottomInset, leftInset)) { - mNavigationBarColor.setBounds(0, 0, size, height); - } else { - mNavigationBarColor.setBounds(0, height - size, width, height); - } + DecorView.getNavigationBarRect(width, height, stableInsets, systemInsets, mTmpRect); + mNavigationBarColor.setBounds(mTmpRect); mNavigationBarColor.draw(canvas); } mSystemBarBackgroundNode.end(canvas); diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index a8e16c96acfa..653796dc39e7 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -119,6 +119,21 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // The height of a window which has not in DIP. private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5; + public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES = + new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, + Gravity.TOP, Gravity.LEFT, Gravity.RIGHT, + Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME, + com.android.internal.R.id.statusBarBackground, + FLAG_FULLSCREEN); + + public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES = + new ColorViewAttributes( + SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, + Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT, + Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, + com.android.internal.R.id.navigationBarBackground, + 0 /* hideWindowFlag */); + // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer // size calculation takes the shadow size into account. We set the elevation currently // to max until the first layout command has been executed. @@ -162,18 +177,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // View added at runtime to draw under the navigation bar area private View mNavigationGuard; - private final ColorViewState mStatusColorViewState = new ColorViewState( - SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, - Gravity.TOP, Gravity.LEFT, Gravity.RIGHT, - Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME, - com.android.internal.R.id.statusBarBackground, - FLAG_FULLSCREEN); - private final ColorViewState mNavigationColorViewState = new ColorViewState( - SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, - Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT, - Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, - com.android.internal.R.id.navigationBarBackground, - 0 /* hideWindowFlag */); + private final ColorViewState mStatusColorViewState = + new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES); + private final ColorViewState mNavigationColorViewState = + new ColorViewState(NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES); private final Interpolator mShowInterpolator; private final Interpolator mHideInterpolator; @@ -983,35 +990,50 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return false; } - static int getColorViewTopInset(int stableTop, int systemTop) { + public static int getColorViewTopInset(int stableTop, int systemTop) { return Math.min(stableTop, systemTop); } - static int getColorViewBottomInset(int stableBottom, int systemBottom) { + public static int getColorViewBottomInset(int stableBottom, int systemBottom) { return Math.min(stableBottom, systemBottom); } - static int getColorViewRightInset(int stableRight, int systemRight) { + public static int getColorViewRightInset(int stableRight, int systemRight) { return Math.min(stableRight, systemRight); } - static int getColorViewLeftInset(int stableLeft, int systemLeft) { + public static int getColorViewLeftInset(int stableLeft, int systemLeft) { return Math.min(stableLeft, systemLeft); } - static boolean isNavBarToRightEdge(int bottomInset, int rightInset) { + public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) { return bottomInset == 0 && rightInset > 0; } - static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) { + public static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) { return bottomInset == 0 && leftInset > 0; } - static int getNavBarSize(int bottomInset, int rightInset, int leftInset) { + public static int getNavBarSize(int bottomInset, int rightInset, int leftInset) { return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset; } + public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets, + Rect contentInsets, Rect outRect) { + final int bottomInset = getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom); + final int leftInset = getColorViewLeftInset(stableInsets.left, contentInsets.left); + final int rightInset = getColorViewLeftInset(stableInsets.right, contentInsets.right); + final int size = getNavBarSize(bottomInset, rightInset, leftInset); + if (isNavBarToRightEdge(bottomInset, rightInset)) { + outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight); + } else if (isNavBarToLeftEdge(bottomInset, leftInset)) { + outRect.set(0, 0, size, canvasHeight); + } else { + outRect.set(0, canvasHeight - size, canvasWidth, canvasHeight); + } + } + WindowInsets updateColorViews(WindowInsets insets, boolean animate) { WindowManager.LayoutParams attrs = mWindow.getAttributes(); int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility(); @@ -1131,9 +1153,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } private int calculateStatusBarColor() { - int flags = mWindow.getAttributes().flags; - return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? mSemiTransparentStatusBarColor - : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? mWindow.mStatusBarColor + return calculateStatusBarColor(mWindow.getAttributes().flags, + mSemiTransparentStatusBarColor, mWindow.mStatusBarColor); + } + + public static int calculateStatusBarColor(int flags, int semiTransparentStatusBarColor, + int statusBarColor) { + return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? semiTransparentStatusBarColor + : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? statusBarColor : Color.BLACK; } @@ -1160,13 +1187,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color, int size, boolean verticalBar, boolean seascape, int sideMargin, boolean animate, boolean force) { - state.present = (sysUiVis & state.systemUiHideFlag) == 0 - && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0 - && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 - || force); - boolean show = state.present - && (color & Color.BLACK) != 0 - && ((mWindow.getAttributes().flags & state.translucentFlag) == 0 || force); + state.present = state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force); + boolean show = state.attributes.isVisible(state.present, color, + mWindow.getAttributes().flags, force); boolean showView = show && !isResizing() && size > 0; boolean visibilityChanged = false; @@ -1175,15 +1198,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size; int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT; int resolvedGravity = verticalBar - ? (seascape ? state.seascapeGravity : state.horizontalGravity) - : state.verticalGravity; + ? (seascape ? state.attributes.seascapeGravity : state.attributes.horizontalGravity) + : state.attributes.verticalGravity; if (view == null) { if (showView) { state.view = view = new View(mContext); view.setBackgroundColor(color); - view.setTransitionName(state.transitionName); - view.setId(state.id); + view.setTransitionName(state.attributes.transitionName); + view.setId(state.attributes.id); visibilityChanged = true; view.setVisibility(INVISIBLE); state.targetVisibility = VISIBLE; @@ -2269,6 +2292,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind boolean visible; int color; + final ColorViewAttributes attributes; + + ColorViewState(ColorViewAttributes attributes) { + this.attributes = attributes; + } + } + + public static class ColorViewAttributes { + final int id; final int systemUiHideFlag; final int translucentFlag; @@ -2278,9 +2310,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind final String transitionName; final int hideWindowFlag; - ColorViewState(int systemUiHideFlag, - int translucentFlag, int verticalGravity, int horizontalGravity, - int seascapeGravity, String transitionName, int id, int hideWindowFlag) { + private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity, + int horizontalGravity, int seascapeGravity, String transitionName, int id, + int hideWindowFlag) { this.id = id; this.systemUiHideFlag = systemUiHideFlag; this.translucentFlag = translucentFlag; @@ -2290,6 +2322,24 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind this.transitionName = transitionName; this.hideWindowFlag = hideWindowFlag; } + + public boolean isPresent(int sysUiVis, int windowFlags, boolean force) { + return (sysUiVis & systemUiHideFlag) == 0 + && (windowFlags & hideWindowFlag) == 0 + && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 + || force); + } + + public boolean isVisible(boolean present, int color, int windowFlags, boolean force) { + return present + && (color & Color.BLACK) != 0 + && ((windowFlags & translucentFlag) == 0 || force); + } + + public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) { + final boolean present = isPresent(sysUiVis, windowFlags, force); + return isVisible(present, color, windowFlags, force); + } } /** diff --git a/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java b/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java new file mode 100644 index 000000000000..e40090f63a76 --- /dev/null +++ b/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 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.view; + +import android.os.Handler; +import android.os.Message; +import android.view.Choreographer; +import android.view.Display; + +/** + * Utility class to schedule things at vsync-sf instead of vsync-app + * @hide + */ +public class SurfaceFlingerVsyncChoreographer { + + private static final long ONE_MS_IN_NS = 1000000; + private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000; + + private final Handler mHandler; + private final Choreographer mChoreographer = Choreographer.getInstance(); + + /** + * The offset between vsync-app and vsync-surfaceflinger. See + * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary. + */ + private long mSurfaceFlingerOffsetMs; + + public SurfaceFlingerVsyncChoreographer(Handler handler, Display display) { + mHandler = handler; + mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(display); + } + + public long getSurfaceFlingerOffsetMs() { + return mSurfaceFlingerOffsetMs; + } + + /** + * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app + * is a couple of milliseconds before vsync-sf, a touch or animation event that causes a surface + * flinger transaction are sometimes processed before the vsync-sf tick, and sometimes after, + * which leads to jank. Figure out this difference here and then post all the touch/animation + * events to start being processed at vsync-sf. + * + * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf. + */ + private long calculateAppSurfaceFlingerVsyncOffsetMs(Display display) { + + // Calculate vsync offset from SurfaceFlinger. + // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs + long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate()); + long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS); + return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS); + } + + public void scheduleAtSfVsync(Runnable r) { + final long delay = calculateDelay(); + if (delay <= 0) { + r.run(); + } else { + mHandler.postDelayed(r, delay); + } + } + + public void scheduleAtSfVsync(Handler h, Message m) { + final long delay = calculateDelay(); + if (delay <= 0) { + h.handleMessage(m); + } else { + m.setAsynchronous(true); + h.sendMessageDelayed(m, delay); + } + } + + private long calculateDelay() { + final long sinceFrameStart = System.nanoTime() - mChoreographer.getLastFrameTimeNanos(); + return mSurfaceFlingerOffsetMs - sinceFrameStart / 1000000; + } +} diff --git a/core/jni/android/graphics/FontUtils.cpp b/core/jni/android/graphics/FontUtils.cpp index 91fec2a75e2c..3bcf0c7fb354 100644 --- a/core/jni/android/graphics/FontUtils.cpp +++ b/core/jni/android/graphics/FontUtils.cpp @@ -55,7 +55,7 @@ void init_FontUtils(JNIEnv* env) { gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;"); gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I"); - jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis"); + jclass axisClass = FindClassOrDie(env, "android/graphics/fonts/FontVariationAxis"); gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I"); gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F"); } diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index a77ed626d0e8..1a353302d7d8 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -10,6 +10,14 @@ using namespace android::uirenderer; +/** + * By default Skia gradients will interpolate their colors in unpremul space + * and then premultiply each of the results. We must set this flag to preserve + * backwards compatiblity by premultiplying the colors of the gradient first, + * and then interpolating between them. + */ +static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag; + static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { if (NULL == ptr) { doThrowIAE(env); @@ -89,7 +97,7 @@ static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr, SkShader* shader = SkGradientShader::MakeLinear(pts, reinterpret_cast<const SkColor*>(colorValues), pos, count, - static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release(); + static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); ThrowIAE_IfNull(env, shader); @@ -109,7 +117,7 @@ static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr, colors[1] = color1; SkShader* s = SkGradientShader::MakeLinear(pts, colors, NULL, 2, - (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release(); + static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); ThrowIAE_IfNull(env, s); return reinterpret_cast<jlong>(s); @@ -135,7 +143,7 @@ static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloa SkShader* shader = SkGradientShader::MakeRadial(center, radius, reinterpret_cast<const SkColor*>(colorValues), pos, count, - static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release(); + static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); @@ -154,7 +162,7 @@ static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloa colors[1] = color1; SkShader* s = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2, - (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release(); + static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release(); ThrowIAE_IfNull(env, s); return reinterpret_cast<jlong>(s); } @@ -174,8 +182,8 @@ static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat #error Need to convert float array to SkScalar array before calling the following function. #endif - SkShader* shader = SkGradientShader::MakeSweep(x, y, - reinterpret_cast<const SkColor*>(colors), pos, count, /* flags */ 0, matrix).release(); + SkShader* shader = SkGradientShader::MakeSweep(x, y, reinterpret_cast<const SkColor*>(colors), + pos, count, sGradientShaderFlags, matrix).release(); env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), JNI_ABORT); ThrowIAE_IfNull(env, shader); @@ -189,7 +197,7 @@ static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat colors[0] = color0; colors[1] = color1; SkShader* s = SkGradientShader::MakeSweep(x, y, colors, NULL, 2, - /* flags */ 0, matrix).release(); + sGradientShaderFlags, matrix).release(); ThrowIAE_IfNull(env, s); return reinterpret_cast<jlong>(s); } diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp index 4b7e0dd562b2..01fe078f6f16 100644 --- a/core/jni/android_hardware_UsbRequest.cpp +++ b/core/jni/android_hardware_UsbRequest.cpp @@ -167,7 +167,7 @@ android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz, } static jboolean -android_hardware_UsbRequest_enqueue(JNIEnv *env, jobject thiz, jobject buffer, jint offset, +android_hardware_UsbRequest_queue(JNIEnv *env, jobject thiz, jobject buffer, jint offset, jint length) { struct usb_request* request = get_request_from_object(env, thiz); @@ -226,8 +226,8 @@ static const JNINativeMethod method_table[] = { {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z", (void *)android_hardware_UsbRequest_init}, {"native_close", "()V", (void *)android_hardware_UsbRequest_close}, - {"native_enqueue", "(Ljava/nio/ByteBuffer;II)Z", - (void *)android_hardware_UsbRequest_enqueue}, + {"native_queue", "(Ljava/nio/ByteBuffer;II)Z", + (void *)android_hardware_UsbRequest_queue}, {"native_queue_array", "([BIZ)Z", (void *)android_hardware_UsbRequest_queue_array}, {"native_dequeue_array", "([BIZ)I", (void *)android_hardware_UsbRequest_dequeue_array}, {"native_queue_direct", "(Ljava/nio/ByteBuffer;IZ)Z", diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 713287e4cd7a..5839fd50d79a 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -101,17 +101,7 @@ sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) { return sur; } -jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, - const sp<IGraphicBufferProducer>& bufferProducer) { - if (bufferProducer == NULL) { - return NULL; - } - - sp<Surface> surface(new Surface(bufferProducer, true)); - if (surface == NULL) { - return NULL; - } - +jobject android_view_Surface_createFromSurface(JNIEnv* env, const sp<Surface>& surface) { jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor, (jlong)surface.get()); if (surfaceObj == NULL) { @@ -126,6 +116,16 @@ jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, return surfaceObj; } +jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, + const sp<IGraphicBufferProducer>& bufferProducer) { + if (bufferProducer == NULL) { + return NULL; + } + + sp<Surface> surface(new Surface(bufferProducer, true)); + return android_view_Surface_createFromSurface(env, surface); +} + int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f) { switch(f) { diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 0ab27f2e0f8d..b95258bca49c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -346,6 +346,11 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, return false; } + // Handle force_mount_namespace with MOUNT_EXTERNAL_NONE. + if (mount_mode == MOUNT_EXTERNAL_NONE) { + return true; + } + if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) { ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno)); diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h index 3f1bdff81aef..2641ab8f0337 100644 --- a/core/jni/include/android_runtime/android_view_Surface.h +++ b/core/jni/include/android_runtime/android_view_Surface.h @@ -69,6 +69,10 @@ extern bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj); /* Gets the underlying Surface from a Surface Java object. */ extern sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj); +/* Creates a Surface from an android::Surface. */ +extern jobject android_view_Surface_createFromSurface(JNIEnv* env, + const sp<Surface>& surface); + /* Creates a Surface from an IGraphicBufferProducer. */ extern jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, const sp<IGraphicBufferProducer>& bufferProducer); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ffcb84762eb5..0a50048c5149 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3129,6 +3129,15 @@ <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE" android:protectionLevel="signature" /> + <!-- @SystemApi Must be required by services that extend + {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can + bind to them. + <p>Protection level: signature + @hide + --> + <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE" + android:protectionLevel="signature" /> + <!-- Must be required by a {@link android.service.notification.ConditionProviderService}, to ensure that only the system can bind to it. @@ -3346,7 +3355,8 @@ android:documentLaunchMode="never" android:relinquishTaskIdentity="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" - android:process=":ui"> + android:process=":ui" + android:visibleToInstantApps="true"> <intent-filter> <action android:name="android.intent.action.CHOOSER" /> <category android:name="android.intent.category.DEFAULT" /> @@ -3360,7 +3370,8 @@ android:documentLaunchMode="never" android:relinquishTaskIdentity="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" - android:process=":ui"> + android:process=":ui" + android:visibleToInstantApps="true"> <intent-filter> <action android:name="android.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" /> <category android:name="android.intent.category.DEFAULT" /> @@ -3421,7 +3432,8 @@ android:exported="true" android:theme="@style/Theme.DeviceDefault.Light.Dialog" android:label="@string/choose_account_label" - android:process=":ui"> + android:process=":ui" + android:visibleToInstantApps="true"> </activity> <activity android:name="android.accounts.ChooseTypeAndAccountActivity" @@ -3429,14 +3441,16 @@ android:exported="true" android:theme="@style/Theme.DeviceDefault.Light.Dialog" android:label="@string/choose_account_label" - android:process=":ui"> + android:process=":ui" + android:visibleToInstantApps="true"> </activity> <activity android:name="android.accounts.ChooseAccountTypeActivity" android:excludeFromRecents="true" android:theme="@style/Theme.DeviceDefault.Light.Dialog" android:label="@string/choose_account_label" - android:process=":ui"> + android:process=":ui" + android:visibleToInstantApps="true"> </activity> <activity android:name="android.accounts.CantAddAccountActivity" @@ -3450,7 +3464,8 @@ android:excludeFromRecents="true" android:exported="true" android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge" - android:process=":ui"> + android:process=":ui" + android:visibleToInstantApps="true"> </activity> <activity android:name="android.content.SyncActivityTooManyDeletes" @@ -3634,6 +3649,14 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> + <service android:name="com.android.internal.app.LRResolverRankerService" + android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE" + android:exported="false" + android:priority="-1" > + <intent-filter> + <action android:name="android.service.resolver.ResolverRankerService" /> + </intent-filter> + </service> </application> </manifest> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 554f50c23daa..ee73b6983888 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8566,6 +8566,11 @@ <!-- @hide From Theme.colorBackground, used for the TaskDescription background color. --> <attr name="colorBackground" /> + <!-- @hide From Theme.statusBarColor, used for the TaskDescription status bar color. --> + <attr name="statusBarColor"/> + <!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar + color. --> + <attr name="navigationBarColor"/> </declare-styleable> <declare-styleable name="Shortcut"> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bcd8a8aeb7f7..85ecaff26b21 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2819,4 +2819,7 @@ density will be scaled accordingly to maintain aspect ratio. A value of 0 indicates no constraint will be enforced. --> <integer name="config_maxUiWidth">0</integer> + + <!-- Whether the device supports quick settings and its associated APIs --> + <bool name="config_quickSettingsSupported">true</bool> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index dfd18e77a264..ae05a69da20d 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2955,4 +2955,5 @@ <java-symbol type="string" name="etws_primary_default_message_test" /> <java-symbol type="string" name="etws_primary_default_message_others" /> + <java-symbol type="bool" name="config_quickSettingsSupported" /> </resources> diff --git a/core/tests/coretests/src/android/graphics/VariationParserTest.java b/core/tests/coretests/src/android/graphics/VariationParserTest.java deleted file mode 100644 index fdabb130115c..000000000000 --- a/core/tests/coretests/src/android/graphics/VariationParserTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2016 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.graphics; - -import android.test.suitebuilder.annotation.SmallTest; -import android.text.FontConfig; - -import junit.framework.TestCase; - -import java.util.List; - - -public class VariationParserTest extends TestCase { - - @SmallTest - public void testParseFontVariationSetting() { - int tag = FontListParser.makeTag("wdth"); - List<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings("'wdth' 1"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(1.0f, axes.get(0).getStyleValue()); - - axes = FontListParser.parseFontVariationSettings("\"wdth\" 100"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(100.0f, axes.get(0).getStyleValue()); - - axes = FontListParser.parseFontVariationSettings(" 'wdth' 100"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(100.0f, axes.get(0).getStyleValue()); - - axes = FontListParser.parseFontVariationSettings("\t'wdth' 0.5"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(0.5f, axes.get(0).getStyleValue()); - - tag = FontListParser.makeTag("AX "); - axes = FontListParser.parseFontVariationSettings("'AX ' 1"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(1.0f, axes.get(0).getStyleValue()); - - axes = FontListParser.parseFontVariationSettings("'AX '\t1"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(1.0f, axes.get(0).getStyleValue()); - - axes = FontListParser.parseFontVariationSettings("'AX '\n1"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(1.0f, axes.get(0).getStyleValue()); - - axes = FontListParser.parseFontVariationSettings("'AX '\r1"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(1.0f, axes.get(0).getStyleValue()); - - axes = FontListParser.parseFontVariationSettings("'AX '\r\t\n 1"); - assertEquals(tag, axes.get(0).getTag()); - assertEquals(1.0f, axes.get(0).getStyleValue()); - - // Test for invalid input - axes = FontListParser.parseFontVariationSettings(""); - assertEquals(0, axes.size()); - axes = FontListParser.parseFontVariationSettings("invalid_form"); - assertEquals(0, axes.size()); - - // Test with invalid tag - axes = FontListParser.parseFontVariationSettings("'' 1"); - assertEquals(0, axes.size()); - axes = FontListParser.parseFontVariationSettings("'invalid' 1"); - assertEquals(0, axes.size()); - - // Test with invalid styleValue - axes = FontListParser.parseFontVariationSettings("'wdth' "); - assertEquals(0, axes.size()); - axes = FontListParser.parseFontVariationSettings("'wdth' x"); - assertEquals(0, axes.size()); - axes = FontListParser.parseFontVariationSettings("'wdth' \t"); - assertEquals(0, axes.size()); - axes = FontListParser.parseFontVariationSettings("'wdth' \n\r"); - assertEquals(0, axes.size()); - } - - @SmallTest - public void testParseFontVariationStyleSettings() { - List<FontConfig.Axis> axes = - FontListParser.parseFontVariationSettings("'wdth' 10,'AX '\r1"); - int tag1 = FontListParser.makeTag("wdth"); - int tag2 = FontListParser.makeTag("AX "); - assertEquals(tag1, axes.get(0).getTag()); - assertEquals(10.0f, axes.get(0).getStyleValue()); - assertEquals(tag2, axes.get(1).getTag()); - assertEquals(1.0f, axes.get(1).getStyleValue()); - - // Test only spacers are allowed before tag - axes = FontListParser.parseFontVariationSettings(" 'wdth' 10,ab'wdth' 1"); - tag1 = FontListParser.makeTag("wdth"); - assertEquals(tag1, axes.get(0).getTag()); - assertEquals(10.0f, axes.get(0).getStyleValue()); - assertEquals(1, axes.size()); - } - - @SmallTest - public void testInvalidTagCharacters() { - List<FontConfig.Axis> axes = - FontListParser.parseFontVariationSettings("'\u0000\u0000\u0000\u0000' 10"); - assertEquals(0, axes.size()); - axes = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10"); - assertEquals(0, axes.size()); - } - - @SmallTest - public void testMakeTag() { - assertEquals(0x77647468, FontListParser.makeTag("wdth")); - assertEquals(0x41582020, FontListParser.makeTag("AX ")); - assertEquals(0x20202020, FontListParser.makeTag(" ")); - } -} diff --git a/core/tests/coretests/src/android/text/VariationParserTest.java b/core/tests/coretests/src/android/text/VariationParserTest.java new file mode 100644 index 000000000000..bcc47e1fc201 --- /dev/null +++ b/core/tests/coretests/src/android/text/VariationParserTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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.text; + +import android.graphics.fonts.FontVariationAxis; +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.TestCase; + +public class VariationParserTest extends TestCase { + private static final String[] INVALID_STYLE_VALUES = { + "", "x", "\t", "\n" + }; + + @SmallTest + public void testFromFontVariationSetting_InvalidStyleValue() { + // Test with invalid styleValue + for (String invalidStyle : INVALID_STYLE_VALUES) { + try { + FontVariationAxis.fromFontVariationSettings("'wdth' " + invalidStyle); + fail(); + } catch (FontVariationAxis.InvalidFormatException e) { + // pass + } + } + for (String invalidStyle : INVALID_STYLE_VALUES) { + try { + FontVariationAxis.fromFontVariationSettings("'wght' 1, 'wdth' " + invalidStyle); + fail(); + } catch (FontVariationAxis.InvalidFormatException e) { + // pass + } + } + } + + @SmallTest + public void testOpenTypeTagValue() throws FontVariationAxis.InvalidFormatException { + assertEquals(0x77647468, (new FontVariationAxis("wdth", 0).getOpenTypeTagValue())); + assertEquals(0x41582020, (new FontVariationAxis("AX ", 0).getOpenTypeTagValue())); + assertEquals(0x20202020, (new FontVariationAxis(" ", 0).getOpenTypeTagValue())); + } +} diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 3dfecc646169..1080a9fcfe71 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -16,17 +16,6 @@ package com.android.internal.app; -import android.app.Instrumentation; -import android.content.ComponentName; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.LauncherApps; -import android.content.pm.PackageManager; -import android.content.pm.ShortcutInfo; -import android.content.pm.ShortcutManager; -import android.graphics.drawable.Icon; -import android.os.SystemClock; import com.android.internal.R; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; @@ -59,31 +48,25 @@ import static com.android.internal.app.ChooserWrapperActivity.sOverrides; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.isA; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; /** * Chooser activity instrumentation tests */ @RunWith(AndroidJUnit4.class) public class ChooserActivityTest { - private Instrumentation instrumentation; - - @Before - public void setUp() { - instrumentation = InstrumentationRegistry.getInstrumentation(); - sOverrides.reset(); - } - @Rule public ActivityTestRule<ChooserWrapperActivity> mActivityRule = new ActivityTestRule<>(ChooserWrapperActivity.class, false, false); + @Before + public void cleanOverrideData() { + sOverrides.reset(); + } + @Test public void customTitle() throws InterruptedException { Intent sendIntent = createSendImageIntent(); @@ -252,6 +235,7 @@ public class ChooserActivityTest { chosen[0] = targetInfo.getResolveInfo(); return true; }; + // Make a stable copy of the components as the original list may be modified List<ResolvedComponentInfo> stableCopy = createResolvedComponentsForTestWithOtherProfile(2); @@ -340,32 +324,6 @@ public class ChooserActivityTest { assertThat(chosen[0], is(toChoose)); } - public void pushedChooserTarget() { - ResolveInfo[] chosen = new ResolveInfo[1]; - sOverrides.onSafelyStartCallback = targetInfo -> { - chosen[0] = targetInfo.getResolveInfo(); - return true; - }; - - setChooserShortcuts(1); - List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); - when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), - Mockito.anyBoolean(), - Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); - - Intent sendIntent = createSendImageIntent(); - final ChooserWrapperActivity activity = mActivityRule - .launchActivity(Intent.createChooser(sendIntent, null)); - - waitForIdle(); - - onView(withText("short chooser label 0")) - .perform(click()); - waitForIdle(); - assertThat(chosen[0].resolvePackageName, - is(ResolverDataProvider.createActivityInfo(0).packageName)); - } - private Intent createSendImageIntent() { Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); @@ -413,48 +371,4 @@ public class ChooserActivityTest { } return packageStats.mChooserCounts.get(action).getOrDefault(annotation, 0); } - - private void setChooserShortcuts(int numShortcuts) { - ArrayList<ShortcutInfo> shortcuts = new ArrayList<>(); - for (int i = 0; i < numShortcuts; i++) { - shortcuts.add(makeShortcut(i)); - } - when(sOverrides.launcherApps.getShortcuts( - Mockito.isA(LauncherApps.ShortcutQuery.class), - Mockito.eq(UserHandle.SYSTEM))) - .thenReturn(shortcuts); - } - - private ShortcutInfo makeShortcut(int i) { - try { - IntentFilter filter = new IntentFilter(Intent.ACTION_SEND, "image/jpeg"); - - ComponentName component = new ComponentName("foo.bar", "foo.bar" + ".MainActivity"); - ShortcutInfo.Builder b = new ShortcutInfo.Builder(instrumentation.getContext(), "" + i) - .setActivity(component) - .setShortLabel("short chooser label " + i) - .setLongLabel("long chooser label" + i) - .setRank(i) - .setIntent(createSendImageIntent()) - .setIcon(Icon.createWithResource(instrumentation.getContext(), - android.R.drawable.ic_menu_add)) - .addChooserIntentFilter( - filter, - component); - - sOverrides.createPackageManager = pm -> { - final PackageManager spied = spy(pm); - try { - doAnswer(invocation -> ResolverDataProvider.createActivityInfo(i)) - .when(spied).getActivityInfo( - Mockito.isA(ComponentName.class), Mockito.anyInt()); - } catch (Exception e) { - // this is ok, just not found - e.printStackTrace(); - } - return spied; - }; - return b.build(); - } catch (Exception e) {return null;} - } }
\ No newline at end of file diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 0dac2602740f..c446f3c79ea8 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -18,7 +18,6 @@ package com.android.internal.app; import android.app.usage.UsageStatsManager; import android.content.Context; -import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import java.util.function.Function; @@ -75,11 +74,6 @@ public class ChooserWrapperActivity extends ChooserActivity { return super.getPackageManager(); } - @Override - public LauncherApps getLauncherApps() { - return sOverrides.launcherApps; - } - /** * We cannot directly mock the activity created since instrumentation creates it. * <p> @@ -88,7 +82,6 @@ public class ChooserWrapperActivity extends ChooserActivity { static class OverrideData { @SuppressWarnings("Since15") public Function<PackageManager, PackageManager> createPackageManager; - public LauncherApps launcherApps; public Function<TargetInfo, Boolean> onSafelyStartCallback; public ResolverListController resolverListController; public Boolean isVoiceInteraction; @@ -97,7 +90,6 @@ public class ChooserWrapperActivity extends ChooserActivity { onSafelyStartCallback = null; isVoiceInteraction = null; createPackageManager = null; - launcherApps = mock(LauncherApps.class); resolverListController = mock(ResolverListController.class); } } diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 344f3c83ba6c..86ab3dc227f4 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -181,6 +181,9 @@ <allow-in-power-save package="com.android.cellbroadcastreceiver" /> <allow-in-power-save package="com.android.shell" /> + <!-- STOPSHIP(b/36856786): Revert this once it is fixed properly --> + <allow-in-power-save package="com.google.android.apps.enterprise.dmagent" /> + <!-- These are the packages that are white-listed to be able to run as system user --> <system-user-whitelisted-app package="com.android.settings" /> diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 76c29a9bf971..3dab1f7e20e1 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -3,15 +3,10 @@ WARNING: Parsing of this file by third-party apps is not supported. The file, and the font files it refers to, will be renamed and/or moved out from their respective location in the next Android release, and/or the - format or syntax of the file may change significantly. You must not - parse this file for information about system fonts. Instead, you must - call android.text.FontManager#getSystemFonts(). For example, it can be - called as context.getSystemService(FontManager.class).getSystemFonts(). - Note that the returned FontConfig includes data on all the defined font - families and all the details about weight, style, etc. It also provides - an open file descriptor to each font file. Note that callers of the API - should ensure they close the given file descriptors once they are done - using them. + format or syntax of the file may change significantly. If you parse this + file for information about system fonts, do it at your own risk. Your + application will almost certainly break with the next major Android + release. In this file, all fonts without names are added to the default list. Fonts are chosen based on a match: full BCP-47 language tag including diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java index d69f67d138a1..218b857ce83c 100644 --- a/graphics/java/android/graphics/Color.java +++ b/graphics/java/android/graphics/Color.java @@ -289,7 +289,7 @@ import java.util.function.DoubleUnaryOperator; * and <code>(1.0, 0.0, 0.0, 0.5)</code>.</p> */ @AnyThread -public final class Color { +public class Color { @ColorInt public static final int BLACK = 0xFF000000; @ColorInt public static final int DKGRAY = 0xFF444444; @ColorInt public static final int GRAY = 0xFF888888; diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index 6214ba6741c9..4b1b0c641807 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -17,6 +17,7 @@ package android.graphics; import android.content.res.AssetManager; +import android.graphics.fonts.FontVariationAxis; import android.text.FontConfig; import android.util.Log; import dalvik.annotation.optimization.CriticalNative; @@ -81,7 +82,7 @@ public class FontFamily { } } - public boolean addFont(String path, int ttcIndex, FontConfig.Axis[] axes, int weight, + public boolean addFont(String path, int ttcIndex, FontVariationAxis[] axes, int weight, int italic) { if (mBuilderPtr == 0) { throw new IllegalStateException("Unable to call addFont after freezing."); @@ -91,8 +92,8 @@ public class FontFamily { long fontSize = fileChannel.size(); ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); if (axes != null) { - for (FontConfig.Axis axis : axes) { - nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue()); + for (FontVariationAxis axis : axes) { + nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); } } return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic); @@ -102,14 +103,14 @@ public class FontFamily { } } - public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontConfig.Axis[] axes, + public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontVariationAxis[] axes, int weight, int italic) { if (mBuilderPtr == 0) { throw new IllegalStateException("Unable to call addFontWeightStyle after freezing."); } if (axes != null) { - for (FontConfig.Axis axis : axes) { - nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue()); + for (FontVariationAxis axis : axes) { + nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); } } return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, weight, italic); @@ -129,13 +130,13 @@ public class FontFamily { */ public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie, boolean isAsset, int ttcIndex, int weight, int isItalic, - FontConfig.Axis[] axes) { + FontVariationAxis[] axes) { if (mBuilderPtr == 0) { throw new IllegalStateException("Unable to call addFontFromAsset after freezing."); } if (axes != null) { - for (FontConfig.Axis axis : axes) { - nAddAxisValue(mBuilderPtr, axis.getTag(), axis.getStyleValue()); + for (FontVariationAxis axis : axes) { + nAddAxisValue(mBuilderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue()); } } return nAddFontFromAssetManager(mBuilderPtr, mgr, path, cookie, isAsset, ttcIndex, weight, diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index ff9f11dae4dc..1a4f225c6267 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -17,6 +17,7 @@ package android.graphics; import android.text.FontConfig; +import android.graphics.fonts.FontVariationAxis; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; @@ -50,72 +51,6 @@ public class FontListParser { } } - // Note that a well-formed variation contains a four-character tag and a float as styleValue, - // with spacers in between. The tag is enclosd either by double quotes or single quotes. - @VisibleForTesting - public static ArrayList<FontConfig.Axis> parseFontVariationSettings(@Nullable String settings) { - ArrayList<FontConfig.Axis> axisList = new ArrayList<>(); - if (settings == null) { - return axisList; - } - String[] settingList = settings.split(","); - settingLoop: - for (String setting : settingList) { - int pos = 0; - while (pos < setting.length()) { - char c = setting.charAt(pos); - if (c == '\'' || c == '"') { - break; - } else if (!isSpacer(c)) { - continue settingLoop; // Only spacers are allowed before tag appeared. - } - pos++; - } - if (pos + 7 > setting.length()) { - continue; // 7 is the minimum length of tag-style value pair text. - } - if (setting.charAt(pos) != setting.charAt(pos + 5)) { - continue; // Tag should be wrapped with double or single quote. - } - String tagString = setting.substring(pos + 1, pos + 5); - if (!TAG_PATTERN.matcher(tagString).matches()) { - continue; // Skip incorrect format tag. - } - pos += 6; - while (pos < setting.length()) { - if (!isSpacer(setting.charAt(pos++))) { - break; // Skip spacers between the tag and the styleValue. - } - } - // Skip invalid styleValue - float styleValue; - String valueString = setting.substring(pos - 1); - if (!STYLE_VALUE_PATTERN.matcher(valueString).matches()) { - continue; // Skip incorrect format styleValue. - } - try { - styleValue = Float.parseFloat(valueString); - } catch (NumberFormatException e) { - continue; // ignoreing invalid number format - } - int tag = makeTag(tagString); - axisList.add(new FontConfig.Axis(tag, styleValue)); - } - return axisList; - } - - public static int makeTag(String tagString) { - char c1 = tagString.charAt(0); - char c2 = tagString.charAt(1); - char c3 = tagString.charAt(2); - char c4 = tagString.charAt(3); - return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; - } - - private static boolean isSpacer(char c) { - return c == ' ' || c == '\r' || c == '\t' || c == '\n'; - } - private static FontConfig readFamilies(XmlPullParser parser) throws XmlPullParserException, IOException { List<FontConfig.Family> families = new ArrayList<>(); @@ -172,7 +107,7 @@ public class FontListParser { throws XmlPullParserException, IOException { String indexStr = parser.getAttributeValue(null, "index"); int index = indexStr == null ? 0 : Integer.parseInt(indexStr); - List<FontConfig.Axis> axes = new ArrayList<FontConfig.Axis>(); + List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>(); String weightStr = parser.getAttributeValue(null, "weight"); int weight = weightStr == null ? 400 : Integer.parseInt(weightStr); boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style")); @@ -191,47 +126,20 @@ public class FontListParser { } String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); return new FontConfig.Font(sanitizedName, index, - axes.toArray(new FontConfig.Axis[axes.size()]), weight, isItalic); + axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic); } - /** The 'tag' attribute value is read as four character values between U+0020 and U+007E - * inclusive. - */ - private static final Pattern TAG_PATTERN = Pattern.compile("[\\x20-\\x7E]{4}"); - - public static boolean isValidTag(String tagString) { - if (tagString == null || tagString.length() != 4) { - return false; - } - return TAG_PATTERN.matcher(tagString).matches(); - } - - /** The 'styleValue' attribute has an optional leading '-', followed by '<digits>', - * '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9]. - */ - private static final Pattern STYLE_VALUE_PATTERN = - Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))"); - - private static FontConfig.Axis readAxis(XmlPullParser parser) + private static FontVariationAxis readAxis(XmlPullParser parser) throws XmlPullParserException, IOException { - int tag = 0; String tagStr = parser.getAttributeValue(null, "tag"); - if (isValidTag(tagStr)) { - tag = makeTag(tagStr); - } else { - throw new XmlPullParserException("Invalid tag attribute value.", parser, null); - } - - float styleValue = 0; String styleValueStr = parser.getAttributeValue(null, "stylevalue"); - if (styleValueStr != null && STYLE_VALUE_PATTERN.matcher(styleValueStr).matches()) { - styleValue = Float.parseFloat(styleValueStr); - } else { - throw new XmlPullParserException("Invalid styleValue attribute value.", parser, null); - } - skip(parser); // axis tag is empty, ignore any contents and consume end tag - return new FontConfig.Axis(tag, styleValue); + try { + return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr)); + } catch (FontVariationAxis.InvalidFormatException e) { + // Treat as system failure since system preinstalled font setting has invalid format. + throw new RuntimeException(e); + } } private static FontConfig.Alias readAlias(XmlPullParser parser) diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index c4f7dc39b4bd..828729a064e9 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -20,6 +20,7 @@ import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Size; import android.graphics.FontListParser; +import android.graphics.fonts.FontVariationAxis; import android.os.LocaleList; import android.text.FontConfig; import android.text.GraphicsOperations; @@ -1551,8 +1552,11 @@ public class Paint { * @return true if the given settings is effective to at least one font file underlying this * typeface. This function also returns true for empty settings string. Otherwise * returns false + * @throws FontVariationAxis.InvalidFormatException + * If given string is not a valid font variation settings format. */ - public boolean setFontVariationSettings(String settings) { + public boolean setFontVariationSettings(String settings) + throws FontVariationAxis.InvalidFormatException { settings = TextUtils.nullIfEmpty(settings); if (settings == mFontVariationSettings || (settings != null && settings.equals(mFontVariationSettings))) { @@ -1566,11 +1570,10 @@ public class Paint { return true; } - final ArrayList<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings(settings); - final ArrayList<FontConfig.Axis> filteredAxes = new ArrayList<FontConfig.Axis>(); - for (int i = 0; i < axes.size(); ++i) { - final FontConfig.Axis axis = axes.get(i); - if (mTypeface.isSupportedAxes(axis.getTag())) { + FontVariationAxis[] axes = FontVariationAxis.fromFontVariationSettings(settings); + final ArrayList<FontVariationAxis> filteredAxes = new ArrayList<FontVariationAxis>(); + for (final FontVariationAxis axis : axes) { + if (mTypeface.isSupportedAxes(axis.getOpenTypeTagValue())) { filteredAxes.add(axis); } } diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 8c3a2e8068ca..560d29f1934d 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -32,6 +32,7 @@ import android.content.res.AssetManager; import android.graphics.FontListParser; import android.graphics.fonts.FontRequest; import android.graphics.fonts.FontResult; +import android.graphics.fonts.FontVariationAxis; import android.os.Bundle; import android.os.Handler; import android.os.ParcelFileDescriptor; @@ -358,11 +359,15 @@ public class Typeface { FileChannel.MapMode.READ_ONLY, 0, fontSize); int style = result.getStyle(); int weight = (style & BOLD) != 0 ? 700 : 400; - final ArrayList<FontConfig.Axis> axes = FontListParser.parseFontVariationSettings( - result.getFontVariationSettings()); - if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(), - axes.toArray(new FontConfig.Axis[axes.size()]), weight, - (style & ITALIC) == 0 ? Builder.NORMAL : Builder.ITALIC)) { + FontVariationAxis[] axes = null; + try { + axes = FontVariationAxis.fromFontVariationSettings( + result.getFontVariationSettings()); + } catch (FontVariationAxis.InvalidFormatException e) { + // TODO: Nice to pass FontVariationAxis[] directly instead of string. + } + if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(), axes, weight, + (style & ITALIC) == 0 ? Builder.NORMAL : Builder.ITALIC)) { Log.e(TAG, "Error creating font " + request.getQuery()); callback.onTypefaceRequestFailed( FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR); @@ -514,7 +519,7 @@ public class Typeface { public static final int ITALIC = 1; private int mTtcIndex; - private FontConfig.Axis[] mAxes; + private FontVariationAxis[] mAxes; private AssetManager mAssetManager; private String mPath; @@ -682,15 +687,16 @@ public class Typeface { * Sets a font variation settings. * * @param variationSettings See {@link android.widget.TextView#setFontVariationSettings}. + * @throws FontVariationAxis.InvalidFormatException If given string is not a valid font + * variation settings format. */ - public Builder setFontVariationSettings(@Nullable String variationSettings) { + public Builder setFontVariationSettings(@Nullable String variationSettings) + throws FontVariationAxis.InvalidFormatException { checkNotRecycled(); if (mAxes != null) { throw new IllegalStateException("Font variation settings are already set."); } - final List<FontConfig.Axis> axesList = FontListParser.parseFontVariationSettings( - variationSettings); - mAxes = axesList.toArray(new FontConfig.Axis[axesList.size()]); + mAxes = FontVariationAxis.fromFontVariationSettings(variationSettings); return this; } @@ -699,7 +705,7 @@ public class Typeface { * * @param axes An array of font variation axis tag-value pairs. */ - public Builder setFontVariationSettings(@Nullable FontConfig.Axis[] axes) { + public Builder setFontVariationSettings(@Nullable FontVariationAxis[] axes) { checkNotRecycled(); if (mAxes != null) { throw new IllegalStateException("Font variation settings are already set."); @@ -718,7 +724,7 @@ public class Typeface { * @return Unique id for a given AssetManager and asset path. */ private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex, - @Nullable FontConfig.Axis[] axes) { + @Nullable FontVariationAxis[] axes) { final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers(); final StringBuilder builder = new StringBuilder(); final int size = pkgs.size(); @@ -731,8 +737,8 @@ public class Typeface { builder.append(Integer.toString(ttcIndex)); builder.append("-"); if (axes != null) { - for (FontConfig.Axis axis : axes) { - builder.append(Integer.toHexString(axis.getTag())); + for (FontVariationAxis axis : axes) { + builder.append(axis.getTag()); builder.append("-"); builder.append(Float.toString(axis.getStyleValue())); } @@ -865,7 +871,7 @@ public class Typeface { /** @hide */ public static Typeface createFromTypefaceWithVariation(Typeface family, - List<FontConfig.Axis> axes) { + List<FontVariationAxis> axes) { final long ni = family == null ? 0 : family.native_instance; return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes)); } @@ -1162,9 +1168,9 @@ public class Typeface { } private static native long nativeCreateFromTypeface(long native_instance, int style); - // TODO: clean up: change List<FontConfig.Axis> to FontConfig.Axis[] + // TODO: clean up: change List<FontVariationAxis> to FontVariationAxis[] private static native long nativeCreateFromTypefaceWithVariation( - long native_instance, List<FontConfig.Axis> axes); + long native_instance, List<FontVariationAxis> axes); private static native long nativeCreateWeightAlias(long native_instance, int weight); private static native void nativeUnref(long native_instance); private static native int nativeGetStyle(long native_instance); diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index d88aee93fae2..a491d7e771dc 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -210,6 +210,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { /** * Change the global fade duration when a new drawable is entering * the scene. + * * @param ms The amount of time to fade in milliseconds. */ public void setEnterFadeDuration(int ms) { @@ -219,6 +220,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { /** * Change the global fade duration when a new drawable is leaving * the scene. + * * @param ms The amount of time to fade in milliseconds. */ public void setExitFadeDuration(int ms) { @@ -375,6 +377,13 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public void invalidateDrawable(@NonNull Drawable who) { + // This may have been called as the result of a tint changing, in + // which case we may need to refresh the cached statefulness or + // opacity. + if (mDrawableContainerState != null) { + mDrawableContainerState.invalidateCache(); + } + if (who == mCurrDrawable && getCallback() != null) { getCallback().invalidateDrawable(this); } @@ -822,8 +831,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDrawables[pos] = dr; mNumChildren++; mChildrenChangingConfigurations |= dr.getChangingConfigurations(); - mCheckedStateful = false; - mCheckedOpacity = false; + + invalidateCache(); mConstantPadding = null; mCheckedPadding = false; @@ -833,6 +842,14 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return pos; } + /** + * Invalidates the cached opacity and statefulness. + */ + void invalidateCache() { + mCheckedOpacity = false; + mCheckedStateful = false; + } + final int getCapacity() { return mDrawables.length; } diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 355e45e70a6b..b159f0f4a2be 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -32,6 +32,7 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.LayoutDirection; +import android.util.Log; import android.view.Gravity; import android.view.View; @@ -66,6 +67,8 @@ import java.io.IOException; * @attr ref android.R.styleable#LayerDrawableItem_id */ public class LayerDrawable extends Drawable implements Drawable.Callback { + private static final String LOG_TAG = "LayerDrawable"; + /** * Padding mode used to nest each layer inside the padding of the previous * layer. @@ -89,6 +92,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ public static final int INSET_UNDEFINED = Integer.MIN_VALUE; + @NonNull LayerState mLayerState; private int[] mPaddingL; @@ -170,13 +174,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); - final LayerState state = mLayerState; - if (state == null) { - return; - } - // The density may have changed since the last update. This will // apply scaling to any existing constant state properties. + final LayerState state = mLayerState; final int density = Drawable.resolveDensity(r, 0); state.setDensity(density); @@ -202,10 +202,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { super.applyTheme(t); final LayerState state = mLayerState; - if (state == null) { - return; - } - final int density = Drawable.resolveDensity(t.getResources(), 0); state.setDensity(density); @@ -403,7 +399,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public boolean canApplyTheme() { - return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme(); + return mLayerState.canApplyTheme() || super.canApplyTheme(); } /** @@ -986,6 +982,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { if (mSuspendChildInvalidation) { mChildRequestedInvalidation = true; } else { + // This may have been called as the result of a tint changing, in + // which case we may need to refresh the cached statefulness or + // opacity. + mLayerState.invalidateCache(); + invalidateSelf(); } } @@ -1836,15 +1837,24 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ConstantState cs = dr.getConstantState(); if (cs == null) { clone = dr; + if (dr.getCallback() != null) { + // This drawable already has an owner. + Log.w(LOG_TAG, "Invalid drawable added to LayerDrawable! Drawable already " + + "belongs to another owner but does not expose a constant state.", + new RuntimeException()); + } } else if (res != null) { clone = cs.newDrawable(res); } else { clone = cs.newDrawable(); } - clone.setCallback(owner); clone.setLayoutDirection(dr.getLayoutDirection()); clone.setBounds(dr.getBounds()); clone.setLevel(dr.getLevel()); + + // Set the callback last to prevent invalidation from + // propagating before the constant state has been set. + clone.setCallback(owner); } else { clone = null; } @@ -2121,7 +2131,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return true; } - public void invalidateCache() { + /** + * Invalidates the cached opacity and statefulness. + */ + void invalidateCache() { mCheckedOpacity = false; mCheckedStateful = false; } diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java new file mode 100644 index 000000000000..91ec0e8df912 --- /dev/null +++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2017 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.graphics.fonts; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.regex.Pattern; + +/** + * Class that holds information about single font variation axis. + */ +public final class FontVariationAxis implements Parcelable { + private final int mTag; + private final String mTagString; + private final float mStyleValue; + + /** + * Construct FontVariationAxis. + * + * The axis tag must contain four ASCII characters. Tag string that are longer or shorter than + * four characters, or contains characters outside of U+0020..U+007E are invalid. + * + * @throws {@link InvalidFormatException} If given tag string is invalid. + */ + public FontVariationAxis(@NonNull String tagString, float styleValue) + throws InvalidFormatException { + if (!isValidTag(tagString)) { + throw new InvalidFormatException("Invalid tag pattern: " + tagString); + } + mTag = makeTag(tagString); + mTagString = tagString; + mStyleValue = styleValue; + } + + /** + * Returns the OpenType style tag value. + * @hide + */ + public int getOpenTypeTagValue() { + return mTag; + } + + /** + * Returns the variable font axis tag associated to this axis. + */ + public String getTag() { + return mTagString; + } + + /** + * Returns the style value associated to the given axis for this font. + */ + public float getStyleValue() { + return mStyleValue; + } + + /** + * @hide + */ + public FontVariationAxis(Parcel in) { + mTag = in.readInt(); + mTagString = in.readString(); + mStyleValue = in.readFloat(); + } + + @Override + public void writeToParcel(Parcel out, int flag) { + out.writeInt(mTag); + out.writeString(mTagString); + out.writeFloat(mStyleValue); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator<FontVariationAxis> CREATOR = new Creator<FontVariationAxis>() { + @Override + public FontVariationAxis createFromParcel(Parcel in) { + return new FontVariationAxis(in); + } + + @Override + public FontVariationAxis[] newArray(int size) { + return new FontVariationAxis[size]; + } + }; + + /** + * Returns a valid font variation setting string for this object. + */ + @Override + public @NonNull String toString() { + return "'" + mTagString + "' " + Float.toString(mStyleValue); + } + + /** + * The 'tag' attribute value is read as four character values between U+0020 and U+007E + * inclusive. + */ + private static final Pattern TAG_PATTERN = Pattern.compile("[\u0020-\u007E]{4}"); + + /** + * Returns true if 'tagString' is valid for font variation axis tag. + */ + private static boolean isValidTag(String tagString) { + return tagString != null && TAG_PATTERN.matcher(tagString).matches(); + } + + /** + * The 'styleValue' attribute has an optional leading '-', followed by '<digits>', + * '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9]. + */ + private static final Pattern STYLE_VALUE_PATTERN = + Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))"); + + private static boolean isValidValueFormat(String valueString) { + return valueString != null && STYLE_VALUE_PATTERN.matcher(valueString).matches(); + } + + /** @hide */ + public static int makeTag(String tagString) { + final char c1 = tagString.charAt(0); + final char c2 = tagString.charAt(1); + final char c3 = tagString.charAt(2); + final char c4 = tagString.charAt(3); + return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; + } + + /** + * An exception indicates that the format of font variation settings is invalid. + */ + public static class InvalidFormatException extends Exception { + public InvalidFormatException(String message) { + super(message); + } + }; + + /** + * Construct FontVariationAxis array from font variation settings. + * + * The settings string is constructed from multiple pairs of axis tag and style values. The axis + * tag must contain four ASCII characters and must be wrapped with single quotes (U+0027) or + * double quotes (U+0022). Axis strings that are longer or shorter than four characters, or + * contain characters outside of U+0020..U+007E are invalid. If a specified axis name is not + * defined in the font, the settings will be ignored. + * + * <pre> + * FontVariationAxis.fromFontVariationSettings("'wdth' 1.0"); + * FontVariationAxis.fromFontVariationSettings("'AX ' 1.0, 'FB ' 2.0"); + * </pre> + * + * @param settings font variation settings. + * @return FontVariationAxis[] the array of parsed font variation axis. {@code null} if settings + * has no font variation settings. + * @throws InvalidFormatException If given string is not a valid font variation settings format. + */ + public static @Nullable FontVariationAxis[] fromFontVariationSettings(@Nullable String settings) + throws InvalidFormatException { + if (settings == null || settings.isEmpty()) { + return null; + } + final ArrayList<FontVariationAxis> axisList = new ArrayList<>(); + final int length = settings.length(); + for (int i = 0; i < length; i++) { + final char c = settings.charAt(i); + if (Character.isWhitespace(c)) { + continue; + } + if (!(c == '\'' || c == '"') || length < i + 6 || settings.charAt(i + 5) != c) { + throw new InvalidFormatException( + "Tag should be wrapped with double or single quote: " + settings); + } + final String tagString = settings.substring(i + 1, i + 5); + + i += 6; // Move to end of tag. + int endOfValueString = settings.indexOf(',', i); + if (endOfValueString == -1) { + endOfValueString = length; + } + final float value; + try { + // Float.parseFloat ignores leading/trailing whitespaces. + value = Float.parseFloat(settings.substring(i, endOfValueString)); + } catch (NumberFormatException e) { + throw new InvalidFormatException("Failed to parse float string: " + e.getMessage()); + } + axisList.add(new FontVariationAxis(tagString, value)); + i = endOfValueString; + } + if (axisList.isEmpty()) { + return null; + } + return axisList.toArray(new FontVariationAxis[0]); + } + + /** + * Stringify the array of FontVariationAxis. + * + * @param axes an array of FontVariationAxis. + * @return String a valid font variation settings string. + */ + public static @NonNull String toFontVariationSettings(@Nullable FontVariationAxis[] axes) { + if (axes == null || axes.length == 0) { + return ""; + } + return TextUtils.join(",", axes); + } +} + diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index dceb28518db3..d4d0c997be11 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -189,9 +189,9 @@ void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount, uint8_t*& dst) const { float oppAmount = 1.0f - amount; float a = start.a * oppAmount + end.a * amount; - *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f); - *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f); - *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f); + *dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f); + *dst++ = uint8_t(OECF(start.g * oppAmount + end.g * amount) * 255.0f); + *dst++ = uint8_t(OECF(start.b * oppAmount + end.b * amount) * 255.0f); *dst++ = uint8_t(a * 255.0f); } @@ -202,13 +202,13 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, float* d = (float*) dst; #ifdef ANDROID_ENABLE_LINEAR_BLENDING // We want to stay linear - *d++ = a * (start.r * oppAmount + end.r * amount); - *d++ = a * (start.g * oppAmount + end.g * amount); - *d++ = a * (start.b * oppAmount + end.b * amount); + *d++ = (start.r * oppAmount + end.r * amount); + *d++ = (start.g * oppAmount + end.g * amount); + *d++ = (start.b * oppAmount + end.b * amount); #else - *d++ = a * OECF(start.r * oppAmount + end.r * amount); - *d++ = a * OECF(start.g * oppAmount + end.g * amount); - *d++ = a * OECF(start.b * oppAmount + end.b * amount); + *d++ = OECF(start.r * oppAmount + end.r * amount); + *d++ = OECF(start.g * oppAmount + end.g * amount); + *d++ = OECF(start.b * oppAmount + end.b * amount); #endif *d++ = a; dst += 4 * sizeof(float); @@ -229,10 +229,10 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, ChannelMixer mix = gMixers[mUseFloatTexture]; FloatColor start; - start.setUnPreMultiplied(colors[0]); + start.set(colors[0]); FloatColor end; - end.setUnPreMultiplied(colors[1]); + end.set(colors[1]); int currentPos = 1; float startPos = positions[0]; @@ -247,7 +247,7 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, currentPos++; - end.setUnPreMultiplied(colors[currentPos]); + end.set(colors[currentPos]); distance = positions[currentPos] - startPos; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 1f78e09b5a58..d0f0949d5e78 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -295,10 +295,6 @@ const char* gFS_GradientPreamble[2] = { vec4 dither(const vec4 color) { return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); } - vec4 gradientMix(const vec4 a, const vec4 b, float v) { - vec4 c = mix(a, b, v); - return vec4(c.rgb * c.a, c.a); - } )__SHADER__", // sRGB framebuffer R"__SHADER__( @@ -306,10 +302,6 @@ const char* gFS_GradientPreamble[2] = { vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); return vec4(dithered * dithered, color.a); } - vec4 gradientMixMix(const vec4 a, const vec4 b, float v) { - vec4 c = mix(a, b, v); - return vec4(c.rgb * c.a, c.a); - } )__SHADER__", }; @@ -364,19 +356,19 @@ const char* gFS_Main_FetchGradient[6] = { // Linear " vec4 gradientColor = texture2D(gradientSampler, linear);\n", - " vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n", + " vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n", // Circular " vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n", - " vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n", + " vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n", // Sweep " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n", " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" - " vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n" + " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n" }; const char* gFS_Main_FetchBitmap = " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n"; diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 8a504d4431c4..5c5378bf22ad 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -173,8 +173,8 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode outData->gradientSampler = 0; outData->gradientTexture = nullptr; - outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]); - outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]); + outData->startColor.set(gradInfo.fColors[0]); + outData->endColor.set(gradInfo.fColors[1]); } return true; diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk index 7f06421b02a0..8826cfcc3100 100644 --- a/libs/hwui/hwui_static_deps.mk +++ b/libs/hwui/hwui_static_deps.mk @@ -27,5 +27,7 @@ LOCAL_SHARED_LIBRARIES += \ libft2 \ libminikin \ libandroidfw \ - libRScpp \ + libRScpp + +LOCAL_STATIC_LIBRARIES += \ libplatformprotos diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index c7796cdd4cc4..4adbf79d562c 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2540,6 +2540,44 @@ public class AudioManager { /** * @hide + * Notifies an application with a focus listener of gain or loss of audio focus. + * This method can only be used by owners of an {@link AudioPolicy} configured with + * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. + * @param afi the recipient of the focus change, that has previously requested audio focus, and + * that was received by the {@code AudioPolicy} through + * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. + * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, + * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or + * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) + * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, + * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, + * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). + * <br>For the focus gain, the change type should be the same as the app requested. + * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. + * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or + * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or + * if there was an error sending the request. + * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. + */ + @SystemApi + public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, + @NonNull AudioPolicy ap) { + if (afi == null) { + throw new NullPointerException("Illegal null AudioFocusInfo"); + } + if (ap == null) { + throw new NullPointerException("Illegal null AudioPolicy"); + } + final IAudioService service = getService(); + try { + return service.dispatchFocusChange(afi, focusChange, ap.cb()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide * Used internally by telephony package to abandon audio focus, typically after a call or * when ringing ends and the call is rejected or not answered. * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. @@ -2548,7 +2586,7 @@ public class AudioManager { final IAudioService service = getService(); try { service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID, - null /*AudioAttributes, legacy behavior*/); + null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2579,7 +2617,7 @@ public class AudioManager { final IAudioService service = getService(); try { status = service.abandonAudioFocus(mAudioFocusDispatcher, - getIdForAudioFocusListener(l), aa); + getIdForAudioFocusListener(l), aa, getContext().getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2787,7 +2825,7 @@ public class AudioManager { final IAudioService service = getService(); try { String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), - policy.hasFocusListener()); + policy.hasFocusListener(), policy.isFocusPolicy()); if (regId == null) { return ERROR; } else { diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 58559843f1f9..884d41e59ada 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -20,6 +20,7 @@ import android.app.PendingIntent; import android.bluetooth.BluetoothDevice; import android.content.ComponentName; import android.media.AudioAttributes; +import android.media.AudioFocusInfo; import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; @@ -122,7 +123,8 @@ interface IAudioService { IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags, IAudioPolicyCallback pcb); - int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, in AudioAttributes aa); + int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, in AudioAttributes aa, + in String callingPackageName); void unregisterAudioFocusClient(String clientId); @@ -164,7 +166,7 @@ interface IAudioService { boolean isHdmiSystemAudioSupported(); String registerAudioPolicy(in AudioPolicyConfig policyConfig, - in IAudioPolicyCallback pcb, boolean hasFocusListener); + in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy); oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb); @@ -196,5 +198,8 @@ interface IAudioService { int getFocusRampTimeMs(in int focusGain, in AudioAttributes attr); + int dispatchFocusChange(in AudioFocusInfo afi, in int focusChange, + in IAudioPolicyCallback pcb); + // WARNING: read warning at top of file, it is recommended to add new methods at the end } diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index cdc1d60fa789..4675e327ce25 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -746,14 +746,19 @@ public class MediaRecorder } /** - * Sets the video encoding profile for recording. Call this method before prepare(). - * Prepare() may perform additional checks on the parameter to make sure whether the - * specified profile and level are applicable, and sometimes the passed profile or - * level will be discarded due to codec capablity or to ensure the video recording - * can proceed smoothly based on the capabilities of the platform. - * @hide + * Sets the desired video encoding profile and level for recording. The profile and level + * must be valid for the video encoder set by {@link #setVideoEncoder}. This method can + * called before or after {@link #setVideoEncoder} but it must be called before {@link #prepare}. + * {@code prepare()} may perform additional checks on the parameter to make sure that the specified + * profile and level are applicable, and sometimes the passed profile or level will be + * discarded due to codec capablity or to ensure the video recording can proceed smoothly + * based on the capabilities of the platform. <br>Application can also use the + * {@link MediaCodecInfo.CodecCapabilities#profileLevels} to query applicable combination of profile + * and level for the corresponding format. Note that the requested profile/level may not be supported by + * the codec that is actually being used by this MediaRecorder instance. * @param profile declared in {@link MediaCodecInfo.CodecProfileLevel}. * @param level declared in {@link MediaCodecInfo.CodecProfileLevel}. + * @throws IllegalArgumentException when an invalid profile or level value is used. */ public void setVideoEncodingProfileLevel(int profile, int level) { if (profile <= 0) { @@ -1281,3 +1286,4 @@ public class MediaRecorder @Override protected void finalize() { native_finalize(); } } + diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 423b4678441c..61d642f50179 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -68,6 +68,7 @@ public class AudioPolicy { private int mStatus; private String mRegistrationId; private AudioPolicyStatusListener mStatusListener; + private boolean mIsFocusPolicy; /** * The behavior of a policy with regards to audio focus where it relies on the application @@ -96,12 +97,14 @@ public class AudioPolicy { public AudioPolicyConfig getConfig() { return mConfig; } /** @hide */ public boolean hasFocusListener() { return mFocusListener != null; } + /** @hide */ + public boolean isFocusPolicy() { return mIsFocusPolicy; } /** * The parameter is guaranteed non-null through the Builder */ private AudioPolicy(AudioPolicyConfig config, Context context, Looper looper, - AudioPolicyFocusListener fl, AudioPolicyStatusListener sl) { + AudioPolicyFocusListener fl, AudioPolicyStatusListener sl, boolean isFocusPolicy) { mConfig = config; mStatus = POLICY_STATUS_UNREGISTERED; mContext = context; @@ -116,10 +119,12 @@ public class AudioPolicy { } mFocusListener = fl; mStatusListener = sl; + mIsFocusPolicy = isFocusPolicy; } /** - * Builder class for {@link AudioPolicy} objects + * Builder class for {@link AudioPolicy} objects. + * By default the policy to be created doesn't govern audio focus decisions. */ @SystemApi public static class Builder { @@ -128,6 +133,7 @@ public class AudioPolicy { private Looper mLooper; private AudioPolicyFocusListener mFocusListener; private AudioPolicyStatusListener mStatusListener; + private boolean mIsFocusPolicy = false; /** * Constructs a new Builder with no audio mixes. @@ -179,6 +185,21 @@ public class AudioPolicy { } /** + * Declares whether this policy will grant and deny audio focus through + * the {@link AudioPolicy.AudioPolicyStatusListener}. + * If set to {@code true}, it is mandatory to set an + * {@link AudioPolicy.AudioPolicyStatusListener} in order to successfully build + * an {@code AudioPolicy} instance. + * @param enforce true if the policy will govern audio focus decisions. + * @return the same Builder instance. + */ + @SystemApi + public Builder setIsAudioFocusPolicy(boolean isFocusPolicy) { + mIsFocusPolicy = isFocusPolicy; + return this; + } + + /** * Sets the audio policy status listener. * @param l a {@link AudioPolicy.AudioPolicyStatusListener} */ @@ -187,6 +208,14 @@ public class AudioPolicy { mStatusListener = l; } + /** + * Combines all of the attributes that have been set on this {@code Builder} and returns a + * new {@link AudioPolicy} object. + * @return a new {@code AudioPolicy} object. + * @throws IllegalStateException if there is no + * {@link AudioPolicy.AudioPolicyStatusListener} but the policy was configured + * as an audio focus policy with {@link #setIsAudioFocusPolicy(boolean)}. + */ @SystemApi public AudioPolicy build() { if (mStatusListener != null) { @@ -195,8 +224,12 @@ public class AudioPolicy { mix.mCallbackFlags |= AudioMix.CALLBACK_FLAG_NOTIFY_ACTIVITY; } } + if (mIsFocusPolicy && mFocusListener == null) { + throw new IllegalStateException("Cannot be a focus policy without " + + "an AudioPolicyFocusListener"); + } return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper, - mFocusListener, mStatusListener); + mFocusListener, mStatusListener, mIsFocusPolicy); } } @@ -402,6 +435,24 @@ public class AudioPolicy { public static abstract class AudioPolicyFocusListener { public void onAudioFocusGrant(AudioFocusInfo afi, int requestResult) {} public void onAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {} + /** + * Called whenever an application requests audio focus. + * Only ever called if the {@link AudioPolicy} was built with + * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}. + * @param afi information about the focus request and the requester + * @param requestResult the result that was returned synchronously by the framework to the + * application, {@link #AUDIOFOCUS_REQUEST_FAILED},or + * {@link #AUDIOFOCUS_REQUEST_DELAYED}. + */ + public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {} + /** + * Called whenever an application abandons audio focus. + * Only ever called if the {@link AudioPolicy} was built with + * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}. + * @param afi information about the focus request being abandoned and the original + * requester. + */ + public void onAudioFocusAbandon(AudioFocusInfo afi) {} } private void onPolicyStatusChange() { @@ -439,6 +490,22 @@ public class AudioPolicy { } } + public void notifyAudioFocusRequest(AudioFocusInfo afi, int requestResult) { + sendMsg(MSG_FOCUS_REQUEST, afi, requestResult); + if (DEBUG) { + Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client=" + + afi.getClientId() + "reqRes=" + requestResult); + } + } + + public void notifyAudioFocusAbandon(AudioFocusInfo afi) { + sendMsg(MSG_FOCUS_ABANDON, afi, 0 /* ignored */); + if (DEBUG) { + Log.v(TAG, "notifyAudioFocusAbandon: pack=" + afi.getPackageName() + " client=" + + afi.getClientId()); + } + } + public void notifyMixStateUpdate(String regId, int state) { for (AudioMix mix : mConfig.getMixes()) { if (mix.getRegistration().equals(regId)) { @@ -459,6 +526,8 @@ public class AudioPolicy { private final static int MSG_FOCUS_GRANT = 1; private final static int MSG_FOCUS_LOSS = 2; private final static int MSG_MIX_STATE_UPDATE = 3; + private final static int MSG_FOCUS_REQUEST = 4; + private final static int MSG_FOCUS_ABANDON = 5; private class EventHandler extends Handler { public EventHandler(AudioPolicy ap, Looper looper) { @@ -488,6 +557,20 @@ public class AudioPolicy { mStatusListener.onMixStateUpdate((AudioMix) msg.obj); } break; + case MSG_FOCUS_REQUEST: + if (mFocusListener != null) { + mFocusListener.onAudioFocusRequest((AudioFocusInfo) msg.obj, msg.arg1); + } else { // should never be null, but don't crash + Log.e(TAG, "Invalid null focus listener for focus request event"); + } + break; + case MSG_FOCUS_ABANDON: + if (mFocusListener != null) { // should never be null + mFocusListener.onAudioFocusAbandon((AudioFocusInfo) msg.obj); + } else { // should never be null, but don't crash + Log.e(TAG, "Invalid null focus listener for focus abandon event"); + } + break; default: Log.e(TAG, "Unknown event " + msg.what); } diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl index ad8af15b15f2..86abbb4dc8d9 100644 --- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl +++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl @@ -22,9 +22,12 @@ import android.media.AudioFocusInfo; */ oneway interface IAudioPolicyCallback { - // callbacks for audio focus + // callbacks for audio focus listening void notifyAudioFocusGrant(in AudioFocusInfo afi, int requestResult); void notifyAudioFocusLoss(in AudioFocusInfo afi, boolean wasNotified); + // callback for audio focus policy + void notifyAudioFocusRequest(in AudioFocusInfo afi, int requestResult); + void notifyAudioFocusAbandon(in AudioFocusInfo afi); // callback for mix activity status update void notifyMixStateUpdate(in String regId, int state); diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 06fc4bce3c76..d8c3eca300a3 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -16,6 +16,7 @@ package android.media.tv; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; @@ -840,7 +841,7 @@ public final class TvContract { public interface BasePreviewProgramColumns extends BaseProgramColumns { /** @hide */ - @StringDef({ + @IntDef({ TYPE_MOVIE, TYPE_TV_SERIES, TYPE_TV_SEASON, @@ -862,87 +863,87 @@ public final class TvContract { * * @see #COLUMN_TYPE */ - String TYPE_MOVIE = "TYPE_MOVIE"; + int TYPE_MOVIE = 0; /** * The program type for TV series. * * @see #COLUMN_TYPE */ - String TYPE_TV_SERIES = "TYPE_TV_SERIES"; + int TYPE_TV_SERIES = 1; /** * The program type for TV season. * * @see #COLUMN_TYPE */ - String TYPE_TV_SEASON = "TYPE_TV_SEASON"; + int TYPE_TV_SEASON = 2; /** * The program type for TV episode. * * @see #COLUMN_TYPE */ - String TYPE_TV_EPISODE = "TYPE_TV_EPISODE"; + int TYPE_TV_EPISODE = 3; /** * The program type for clip. * * @see #COLUMN_TYPE */ - String TYPE_CLIP = "TYPE_CLIP"; + int TYPE_CLIP = 4; /** * The program type for event. * * @see #COLUMN_TYPE */ - String TYPE_EVENT = "TYPE_EVENT"; + int TYPE_EVENT = 5; /** * The program type for channel. * * @see #COLUMN_TYPE */ - String TYPE_CHANNEL = "TYPE_CHANNEL"; + int TYPE_CHANNEL = 6; /** * The program type for track. * * @see #COLUMN_TYPE */ - String TYPE_TRACK = "TYPE_TRACK"; + int TYPE_TRACK = 7; /** * The program type for album. * * @see #COLUMN_TYPE */ - String TYPE_ALBUM = "TYPE_ALBUM"; + int TYPE_ALBUM = 8; /** * The program type for artist. * * @see #COLUMN_TYPE */ - String TYPE_ARTIST = "TYPE_ARTIST"; + int TYPE_ARTIST = 9; /** * The program type for playlist. * * @see #COLUMN_TYPE */ - String TYPE_PLAYLIST = "TYPE_PLAYLIST"; + int TYPE_PLAYLIST = 10; /** * The program type for station. * * @see #COLUMN_TYPE */ - String TYPE_STATION = "TYPE_STATION"; + int TYPE_STATION = 11; /** @hide */ - @StringDef({ + @IntDef({ ASPECT_RATIO_16_9, ASPECT_RATIO_3_2, ASPECT_RATIO_1_1, @@ -957,7 +958,7 @@ public final class TvContract { * @see #COLUMN_POSTER_ART_ASPECT_RATIO * @see #COLUMN_THUMBNAIL_ASPECT_RATIO */ - String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9"; + int ASPECT_RATIO_16_9 = 0; /** * The aspect ratio for 3:2. @@ -965,7 +966,7 @@ public final class TvContract { * @see #COLUMN_POSTER_ART_ASPECT_RATIO * @see #COLUMN_THUMBNAIL_ASPECT_RATIO */ - String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2"; + int ASPECT_RATIO_3_2 = 1; /** * The aspect ratio for 1:1. @@ -973,7 +974,7 @@ public final class TvContract { * @see #COLUMN_POSTER_ART_ASPECT_RATIO * @see #COLUMN_THUMBNAIL_ASPECT_RATIO */ - String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1"; + int ASPECT_RATIO_1_1 = 2; /** * The aspect ratio for 2:3. @@ -981,10 +982,10 @@ public final class TvContract { * @see #COLUMN_POSTER_ART_ASPECT_RATIO * @see #COLUMN_THUMBNAIL_ASPECT_RATIO */ - String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3"; + int ASPECT_RATIO_2_3 = 3; /** @hide */ - @StringDef({ + @IntDef({ AVAILABILITY_AVAILABLE, AVAILABILITY_FREE_WITH_SUBSCRIPTION, AVAILABILITY_PAID_CONTENT, @@ -997,15 +998,14 @@ public final class TvContract { * * @see #COLUMN_AVAILABILITY */ - String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE"; + int AVAILABILITY_AVAILABLE = 0; /** * The availability for "free with subscription". * * @see #COLUMN_AVAILABILITY */ - String AVAILABILITY_FREE_WITH_SUBSCRIPTION = - "AVAILABILITY_FREE_WITH_SUBSCRIPTION"; + int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; /** * The availability for "paid content, either to-own or rental @@ -1013,72 +1013,72 @@ public final class TvContract { * * @see #COLUMN_AVAILABILITY */ - String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT"; + int AVAILABILITY_PAID_CONTENT = 2; /** @hide */ - @StringDef({ + @IntDef({ + INTERACTION_TYPE_VIEWS, INTERACTION_TYPE_LISTENS, INTERACTION_TYPE_FOLLOWERS, INTERACTION_TYPE_FANS, INTERACTION_TYPE_LIKES, INTERACTION_TYPE_THUMBS, - INTERACTION_TYPE_VIEWS, INTERACTION_TYPE_VIEWERS, }) @Retention(RetentionPolicy.SOURCE) public @interface InteractionType {} /** - * The interaction type for "listens". + * The interaction type for "views". * * @see #COLUMN_INTERACTION_TYPE */ - String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS"; + int INTERACTION_TYPE_VIEWS = 0; /** - * The interaction type for "followers". + * The interaction type for "listens". * * @see #COLUMN_INTERACTION_TYPE */ - String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS"; + int INTERACTION_TYPE_LISTENS = 1; /** - * The interaction type for "fans". + * The interaction type for "followers". * * @see #COLUMN_INTERACTION_TYPE */ - String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS"; + int INTERACTION_TYPE_FOLLOWERS = 2; /** - * The interaction type for "likes". + * The interaction type for "fans". * * @see #COLUMN_INTERACTION_TYPE */ - String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES"; + int INTERACTION_TYPE_FANS = 3; /** - * The interaction type for "thumbs". + * The interaction type for "likes". * * @see #COLUMN_INTERACTION_TYPE */ - String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS"; + int INTERACTION_TYPE_LIKES = 4; /** - * The interaction type for "views". + * The interaction type for "thumbs". * * @see #COLUMN_INTERACTION_TYPE */ - String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS"; + int INTERACTION_TYPE_THUMBS = 5; /** * The interaction type for "viewers". * * @see #COLUMN_INTERACTION_TYPE */ - String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS"; + int INTERACTION_TYPE_VIEWERS = 6; /** @hide */ - @StringDef({ + @IntDef({ REVIEW_RATING_STYLE_STARS, REVIEW_RATING_STYLE_THUMBS_UP_DOWN, REVIEW_RATING_STYLE_PERCENTAGE, @@ -1091,23 +1091,21 @@ public final class TvContract { * * @see #COLUMN_REVIEW_RATING_STYLE */ - String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS"; + int REVIEW_RATING_STYLE_STARS = 0; /** * The review rating style for thumbs-up and thumbs-down rating. * * @see #COLUMN_REVIEW_RATING_STYLE */ - String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = - "REVIEW_RATING_STYLE_THUMBS_UP_DOWN"; + int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; /** * The review rating style for 0 to 100 point system. * * @see #COLUMN_REVIEW_RATING_STYLE */ - String REVIEW_RATING_STYLE_PERCENTAGE = - "REVIEW_RATING_STYLE_PERCENTAGE"; + int REVIEW_RATING_STYLE_PERCENTAGE = 2; /** * The type of this program content. @@ -1129,7 +1127,7 @@ public final class TvContract { * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW} * channel. * - * <p>Type: TEXT + * <p>Type: INTEGER */ String COLUMN_TYPE = "type"; @@ -1142,7 +1140,7 @@ public final class TvContract { * {@link #ASPECT_RATIO_1_1}, and * {@link #ASPECT_RATIO_2_3}. * - * <p>Type: TEXT + * <p>Type: INTEGER */ String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio"; @@ -1155,7 +1153,7 @@ public final class TvContract { * {@link #ASPECT_RATIO_1_1}, and * {@link #ASPECT_RATIO_2_3}. * - * <p>Type: TEXT + * <p>Type: INTEGER */ String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio"; @@ -1188,7 +1186,7 @@ public final class TvContract { * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and * {@link #AVAILABILITY_PAID_CONTENT}. * - * <p>Type: TEXT + * <p>Type: INTEGER */ String COLUMN_AVAILABILITY = "availability"; @@ -1299,18 +1297,17 @@ public final class TvContract { String COLUMN_DURATION_MILLIS = "duration_millis"; /** - * The intent URI which is launched when the preview video is selected. + * The intent URI which is launched when the preview program is selected. * * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME} * and converted back to the original intent with {@link Intent#parseUri}. The intent is - * launched when the user selects the preview video item. + * launched when the user selects the preview program item. * * <p>Can be empty. * * <p>Type: TEXT */ - String COLUMN_APP_LINK_INTENT_URI = - "app_link_intent_uri"; + String COLUMN_INTENT_URI = "intent_uri"; /** * The flag indicating whether this program is transient or not. @@ -1328,15 +1325,15 @@ public final class TvContract { * The type of interaction for this TV program. * * <p> The value should match one of the followings: + * {@link #INTERACTION_TYPE_VIEWS}, * {@link #INTERACTION_TYPE_LISTENS}, * {@link #INTERACTION_TYPE_FOLLOWERS}, * {@link #INTERACTION_TYPE_FANS}, * {@link #INTERACTION_TYPE_LIKES}, - * {@link #INTERACTION_TYPE_THUMBS}, - * {@link #INTERACTION_TYPE_VIEWS}, and + * {@link #INTERACTION_TYPE_THUMBS}, and * {@link #INTERACTION_TYPE_VIEWERS}. * - * <p>Type: TEXT + * <p>Type: INTEGER * @see #COLUMN_INTERACTION_COUNT */ String COLUMN_INTERACTION_TYPE = "interaction_type"; @@ -1364,7 +1361,7 @@ public final class TvContract { * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS}, * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}. * - * <p>Type: TEXT + * <p>Type: INTEGER * @see #COLUMN_REVIEW_RATING */ String COLUMN_REVIEW_RATING_STYLE = "review_rating_style"; @@ -2725,7 +2722,7 @@ public final class TvContract { public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program"; /** @hide */ - @StringDef({ + @IntDef({ WATCH_NEXT_TYPE_CONTINUE, WATCH_NEXT_TYPE_NEXT, WATCH_NEXT_TYPE_NEW, @@ -2740,7 +2737,7 @@ public final class TvContract { * * @see #COLUMN_WATCH_NEXT_TYPE */ - public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE"; + public static final int WATCH_NEXT_TYPE_CONTINUE = 0; /** * The watch next type for NEXT. Use this type when the user has watched one or more @@ -2750,7 +2747,7 @@ public final class TvContract { * * @see #COLUMN_WATCH_NEXT_TYPE */ - public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT"; + public static final int WATCH_NEXT_TYPE_NEXT = 1; /** * The watch next type for NEW. Use this type when the user had watched all of the available @@ -2760,7 +2757,7 @@ public final class TvContract { * * @see #COLUMN_WATCH_NEXT_TYPE */ - public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW"; + public static final int WATCH_NEXT_TYPE_NEW = 2; /** * The watch next type for WATCHLIST. Use this type when the user has elected to explicitly @@ -2769,7 +2766,7 @@ public final class TvContract { * * @see #COLUMN_WATCH_NEXT_TYPE */ - public static final String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST"; + public static final int WATCH_NEXT_TYPE_WATCHLIST = 3; /** * The "watch next" type of this program content. @@ -2782,7 +2779,7 @@ public final class TvContract { * * <p>This is a required field. * - * <p>Type: TEXT + * <p>Type: INTEGER */ public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type"; diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index c7bed9bc1685..c82a1f6a646a 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -153,6 +153,7 @@ LIBANDROID { ANativeWindow_acquire; ANativeWindow_fromSurface; ANativeWindow_fromSurfaceTexture; # introduced-arm=13 introduced-mips=13 introduced-x86=13 + ANativeWindow_toSurface; # introduced=26 ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getWidth; diff --git a/native/android/native_window_jni.cpp b/native/android/native_window_jni.cpp index dc3040533974..859c550db94d 100644 --- a/native/android/native_window_jni.cpp +++ b/native/android/native_window_jni.cpp @@ -20,6 +20,7 @@ #include <android/native_window.h> #include <system/window.h> +#include <gui/Surface.h> #include <utils/StrongPointer.h> #include <android_runtime/android_view_Surface.h> @@ -33,3 +34,11 @@ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) { } return win.get(); } + +jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) { + if (window == NULL) { + return NULL; + } + sp<Surface> surface = static_cast<Surface*>(window); + return android_view_Surface_createFromSurface(env, surface); +} diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index c2ce7c9fd5de..8833fb8cab53 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -1394,7 +1394,9 @@ public class ApplicationsState { @Override public boolean filterApp(AppEntry entry) { - if ((entry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + if (AppUtils.isInstant(entry.info)) { + return false; + } else if ((entry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { return true; } else if ((entry.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { return true; @@ -1407,6 +1409,23 @@ public class ApplicationsState { } }; + /** + * Displays a combined list with "downloaded" and "visible in launcher" apps only. + */ + public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT = new AppFilter() { + + @Override + public void init() { + } + + @Override + public boolean filterApp(AppEntry entry) { + return AppUtils.isInstant(entry.info) + || FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(entry); + } + + }; + public static final AppFilter FILTER_THIRD_PARTY = new AppFilter() { @Override public void init() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java index 69b45e5541b2..9ea7a4af8d12 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java @@ -71,14 +71,15 @@ public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + if (intent.getAction() == null || !intent.getAction().equals(INTENT_DISCOVERABLE_TIMEOUT)) { + return; + } LocalBluetoothAdapter localBluetoothAdapter = LocalBluetoothAdapter.getInstance(); - - if(localBluetoothAdapter != null && + if(localBluetoothAdapter != null && localBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { Log.d(TAG, "Disable discoverable..."); - localBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE); - } else { + } else { Log.e(TAG, "localBluetoothAdapter is NULL!!"); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index a3ae9269b1f7..abd4e294fecb 100755 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -103,7 +103,7 @@ public class CachedBluetoothDeviceManager { */ public String getName(BluetoothDevice device) { CachedBluetoothDevice cachedDevice = findDevice(device); - if (cachedDevice != null) { + if (cachedDevice != null && cachedDevice.getName() != null) { return cachedDevice.getName(); } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java index e204a3a65c72..6a029f0be64d 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java @@ -110,6 +110,70 @@ public class ApplicationsStateTest { } @Test + public void testDownloadAndLauncherAndInstantAcceptsCorrectApps() { + // should include instant apps + mEntry.isHomeApp = false; + mEntry.hasLauncherEntry = false; + when(mEntry.info.isInstantApp()).thenReturn(true); + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry)) + .isTrue(); + + // should included updated system apps + when(mEntry.info.isInstantApp()).thenReturn(false); + mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry)) + .isTrue(); + + // should not include system apps other than the home app + mEntry.info.flags = ApplicationInfo.FLAG_SYSTEM; + mEntry.isHomeApp = false; + mEntry.hasLauncherEntry = false; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry)) + .isFalse(); + + // should include the home app + mEntry.isHomeApp = true; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry)) + .isTrue(); + + // should include any System app with a launcher entry + mEntry.isHomeApp = false; + mEntry.hasLauncherEntry = true; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(mEntry)) + .isTrue(); + } + + @Test + public void testDownloadAndLauncherAcceptsCorrectApps() { + mEntry.isHomeApp = false; + mEntry.hasLauncherEntry = false; + + // should included updated system apps + when(mEntry.info.isInstantApp()).thenReturn(false); + mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry)) + .isTrue(); + + // should not include system apps other than the home app + mEntry.info.flags = ApplicationInfo.FLAG_SYSTEM; + mEntry.isHomeApp = false; + mEntry.hasLauncherEntry = false; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry)) + .isFalse(); + + // should include the home app + mEntry.isHomeApp = true; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry)) + .isTrue(); + + // should include any System app with a launcher entry + mEntry.isHomeApp = false; + mEntry.hasLauncherEntry = true; + assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(mEntry)) + .isTrue(); + } + + @Test public void testInstantFilterAcceptsInstantApp() { when(mEntry.info.isInstantApp()).thenReturn(true); assertThat(ApplicationsState.FILTER_INSTANT.filterApp(mEntry)).isTrue(); diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index ad39f5475554..a8cf3daec41e 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1962,4 +1962,31 @@ <!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] --> <string name="mobile_data">Mobile data</string> + <!-- Label for when wifi is off in QS detail panel [CHAR LIMIT=NONE] --> + <string name="wifi_is_off">Wi-Fi is off</string> + + <!-- Label for when bluetooth is off in QS detail panel [CHAR LIMIT=NONE] --> + <string name="bt_is_off">Bluetooth is off</string> + + <!-- Label for when Do not disturb is off in QS detail panel [CHAR LIMIT=NONE] --> + <string name="dnd_is_off">Do Not Disturb is off</string> + + <!-- Prompt for when Do not disturb is on from automatic rule in QS [CHAR LIMIT=NONE] --> + <string name="qs_dnd_prompt_auto_rule">Do Not Disturb was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>). Keep current settings?</string> + + <!-- Prompt for when Do not disturb is on from app in QS [CHAR LIMIT=NONE] --> + <string name="qs_dnd_prompt_app">Do Not Disturb was turned on by an app (<xliff:g name="app">%s</xliff:g>). Keep current settings?</string> + + <!-- Prompt for when Do not disturb is on from automatic rule or app in QS [CHAR LIMIT=NONE] --> + <string name="qs_dnd_prompt_auto_rule_app">Do Not Disturb was turned on by an automatic rule or app. Keep current settings?</string> + + <!-- Description of Do Not Disturb option in QS that ends at the specified time[CHAR LIMIT=20] --> + <string name="qs_dnd_until">Until <xliff:g name="time">%s</xliff:g></string> + + <!-- Do Not Disturb button to keep the current settings [CHAR LIMIT=20] --> + <string name="qs_dnd_keep">Keep</string> + + <!-- Do Not Disturb button to change the current settings [CHAR LIMIT=20] --> + <string name="qs_dnd_replace">Replace</string> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 17228b9c876c..bcf1957109de 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -417,17 +417,17 @@ public class PipMenuActivity extends Activity { } private void updateDismissFraction(float fraction) { - setDecorViewVisibility(true); int alpha; if (mMenuVisible) { - mMenuContainer.setAlpha(1-fraction); + mMenuContainer.setAlpha(1 - fraction); final float interpolatedAlpha = MENU_BACKGROUND_ALPHA * (1.0f - fraction) + DISMISS_BACKGROUND_ALPHA * fraction; - alpha = (int) (interpolatedAlpha*255); + alpha = (int) (interpolatedAlpha * 255); } else { - alpha = (int) (fraction*DISMISS_BACKGROUND_ALPHA*255); + alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255); } mBackgroundDrawable.setAlpha(alpha); + setDecorViewVisibility(alpha > 0); } private void notifyRegisterInputConsumer() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java index 4b2c20f4f7db..5b9d95d3e2c0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java @@ -1,3 +1,4 @@ + /* * Copyright (C) 2014 The Android Open Source Project * @@ -358,9 +359,8 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic @Override public void onClick(View widget) { final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); mDialog.dismiss(); - mContext.startActivity(intent); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); } @Override @@ -373,9 +373,8 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic @Override public void onClick(View widget) { final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); mDialog.dismiss(); - mContext.startActivity(intent); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 1c71da007fd0..3a43d304b1ca 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -355,9 +355,10 @@ public class SystemServicesProxy { rti.firstActiveTime = rti.lastActiveTime = i; if (i % 2 == 0) { rti.taskDescription = new ActivityManager.TaskDescription(description, - Bitmap.createBitmap(mDummyIcon), null, - 0xFF000000 | (0xFFFFFF & new Random().nextInt()), - 0xFF000000 | (0xFFFFFF & new Random().nextInt())); + Bitmap.createBitmap(mDummyIcon), null, + 0xFF000000 | (0xFFFFFF & new Random().nextInt()), + 0xFF000000 | (0xFFFFFF & new Random().nextInt()), + 0, 0); } else { rti.taskDescription = new ActivityManager.TaskDescription(); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 97506e6df1c2..0ee3e1917117 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -58,6 +58,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.internal.policy.DockedDividerUtils; +import com.android.internal.view.SurfaceFlingerVsyncChoreographer; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.Recents; @@ -108,9 +109,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, private static final Interpolator IME_ADJUST_INTERPOLATOR = new PathInterpolator(0.2f, 0f, 0.1f, 1f); - private static final long ONE_MS_IN_NS = 1000000; - private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000; - private static final int MSG_RESIZE_STACK = 0; private DividerHandleView mHandle; @@ -161,12 +159,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private boolean mHomeStackResizable; private boolean mAdjustedForIme; private DividerState mState; - - /** - * The offset between vsync-app and vsync-surfaceflinger. See - * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary. - */ - private long mSurfaceFlingerOffsetMs; + private SurfaceFlingerVsyncChoreographer mSfChoreographer; private final Handler mHandler = new Handler() { @Override @@ -319,7 +312,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, protected void onAttachedToWindow() { super.onAttachedToWindow(); EventBus.getDefault().register(this); - mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(); + mSfChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, getDisplay()); } @Override @@ -328,25 +321,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, EventBus.getDefault().unregister(this); } - /** - * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app - * is a couple of milliseconds before vsync-sf, a touch or animation event that causes the - * stacks to be resized are sometimes processed before the vsync-sf tick, and sometimes after, - * which leads to jank. Figure out this difference here and then post all the touch/animation - * events to start being processed at vsync-sf. - * - * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf. - */ - private long calculateAppSurfaceFlingerVsyncOffsetMs() { - Display display = getDisplay(); - - // Calculate vsync offset from SurfaceFlinger. - // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs - long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate()); - long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS); - return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS); - } - @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { if (mStableInsets.left != insets.getStableInsetLeft() @@ -630,8 +604,8 @@ public class DividerView extends FrameLayout implements OnTouchListener, delay = endDelay; } else if (mCancelled) { delay = 0; - } else if (mSurfaceFlingerOffsetMs != 0) { - delay = mSurfaceFlingerOffsetMs; + } else if (mSfChoreographer.getSurfaceFlingerOffsetMs() > 0) { + delay = mSfChoreographer.getSurfaceFlingerOffsetMs(); } if (delay == 0) { endAction.run(); @@ -916,14 +890,10 @@ public class DividerView extends FrameLayout implements OnTouchListener, } public void resizeStackDelayed(int position, int taskPosition, SnapTarget taskSnapTarget) { - if (mSurfaceFlingerOffsetMs != 0) { - Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition, - taskSnapTarget); - message.setAsynchronous(true); - mHandler.sendMessageDelayed(message, mSurfaceFlingerOffsetMs); - } else { - resizeStack(position, taskPosition, taskSnapTarget); - } + Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition, + taskSnapTarget); + message.setAsynchronous(true); + mSfChoreographer.scheduleAtSfVsync(mHandler, message); } public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) { diff --git a/preloaded-classes b/preloaded-classes index a72a04272cba..892c59394855 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -1817,7 +1817,6 @@ android.text.FontConfig$Family android.text.FontConfig$Family$1 android.text.FontConfig$Font android.text.FontConfig$Font$1 -android.text.FontManager android.text.GetChars android.text.GraphicsOperations android.text.Html diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index f6d91f44b2cf..c4a28313ed0a 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -165,6 +165,14 @@ message SystemMessage { // Package: android NOTE_NET_LIMIT_SNOOZED = 36; + // Inform the user they need to sign in to an account + // Package: android, and others + NOTE_ACCOUNT_REQUIRE_SIGNIN = 37; + + // Inform the user that there has been a permission request for an account + // Package: android + NOTE_ACCOUNT_CREDENTIAL_PERMISSION = 38; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release @@ -216,9 +224,5 @@ message SystemMessage { // Notify the user that data or apps are being moved to external storage. // Package: com.android.systemui NOTE_STORAGE_MOVE = 0x534d4f56; - - // Account Manager allocates IDs sequentially, starting here. - // Package: android - ACCOUNT_MANAGER_BASE = 0x70000000; } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 087c24866146..1968d2e925aa 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -585,17 +585,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { result = mEnabledServicesForFeedbackTempList; result.clear(); List<Service> services = userState.mBoundServices; - while (feedbackType != 0) { - final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); - feedbackType &= ~feedbackTypeBit; - final int serviceCount = services.size(); - for (int i = 0; i < serviceCount; i++) { - Service service = services.get(i); - // Don't report the UIAutomation (fake service) - if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName) - && (service.mFeedbackType & feedbackTypeBit) != 0) { - result.add(service.mAccessibilityServiceInfo); - } + for (int serviceCount = services.size(), i = 0; i < serviceCount; ++i) { + Service service = services.get(i); + // Don't report the UIAutomation (fake service) + if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName) + && (service.mFeedbackType & feedbackType) != 0) { + result.add(service.mAccessibilityServiceInfo); } } } diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java index 3aba723b7e5f..20def0c5a4f8 100644 --- a/services/autofill/java/com/android/server/autofill/ViewState.java +++ b/services/autofill/java/com/android/server/autofill/ViewState.java @@ -156,7 +156,7 @@ final class ViewState { } // Then checks if the session has a response waiting authentication; if so, uses it instead. final FillResponse currentResponse = mSession.getCurrentResponse(); - if (currentResponse.getAuthentication() != null) { + if (currentResponse != null && currentResponse.getAuthentication() != null) { mListener.onFillReady(currentResponse, this.id, mCurrentValue); } } diff --git a/services/core/Android.mk b/services/core/Android.mk index 099f557ad416..8003d21d165e 100644 --- a/services/core/Android.mk +++ b/services/core/Android.mk @@ -39,8 +39,8 @@ endif LOCAL_JACK_FLAGS := \ -D jack.transformations.boost-locked-region-priority=true \ - -D jack.transformations.boost-locked-region-priority.classname=com.android.server.am.ActivityManagerService \ - -D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection \ - -D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection + -D jack.transformations.boost-locked-region-priority.classname=com.android.server.am.ActivityManagerService,com.android.server.wm.WindowHashMap \ + -D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection,com.android.server.wm.WindowManagerService\#boostPriorityForLockedSection \ + -D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection,com.android.server.wm.WindowManagerService\#resetPriorityAfterLockedSection include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0e752ffdb5a5..25ac008fa586 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -29,13 +29,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; -import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; -import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; -import static android.net.NetworkPolicyManager.RULE_NONE; -import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; -import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; -import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; -import static android.net.NetworkPolicyManager.uidRulesToString; import android.annotation.Nullable; import android.app.BroadcastOptions; @@ -104,7 +97,6 @@ import android.security.Credentials; import android.security.KeyStore; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.util.ArraySet; import android.util.LocalLog; import android.util.LocalLog.ReadOnlyLocalLog; import android.util.Log; @@ -130,6 +122,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.XmlUtils; +import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.KeepaliveTracker; @@ -147,6 +140,7 @@ import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; +import com.android.server.net.NetworkPolicyManagerInternal; import com.google.android.collect.Lists; @@ -221,18 +215,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean mLockdownEnabled; private LockdownVpnTracker mLockdownTracker; - /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ - private Object mRulesLock = new Object(); - /** Currently active network rules by UID. */ - @GuardedBy("mRulesLock") - private SparseIntArray mUidRules = new SparseIntArray(); - /** Set of ifaces that are costly. */ - @GuardedBy("mRulesLock") - private ArraySet<String> mMeteredIfaces = new ArraySet<>(); - /** Flag indicating if background data is restricted. */ - @GuardedBy("mRulesLock") - private boolean mRestrictBackground; - final private Context mContext; private int mNetworkPreference; // 0 is full bad, 100 is full good @@ -246,6 +228,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkManagementService mNetd; private INetworkStatsService mStatsService; private INetworkPolicyManager mPolicyManager; + private NetworkPolicyManagerInternal mPolicyManagerInternal; private String mCurrentTcpBufferSizes; @@ -715,12 +698,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mStatsService = checkNotNull(statsService, "missing INetworkStatsService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); + mPolicyManagerInternal = checkNotNull( + LocalServices.getService(NetworkPolicyManagerInternal.class), + "missing NetworkPolicyManagerInternal"); + mKeyStore = KeyStore.getInstance(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); try { - mPolicyManager.setConnectivityListener(mPolicyListener); - mRestrictBackground = mPolicyManager.getRestrictBackground(); + mPolicyManager.registerListener(mPolicyListener); } catch (RemoteException e) { // ouch, no rules updates means some processes may never get network loge("unable to register INetworkPolicyListener" + e); @@ -991,51 +977,22 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, boolean ignoreBlocked) { // Networks aren't blocked when ignoring blocked status - if (ignoreBlocked) return false; + if (ignoreBlocked) { + return false; + } // Networks are never blocked for system services - if (isSystem(uid)) return false; - - final boolean networkMetered; - final int uidRules; - + // TODO: consider moving this check to NetworkPolicyManagerInternal.isUidNetworkingBlocked. + if (isSystem(uid)) { + return false; + } synchronized (mVpns) { final Vpn vpn = mVpns.get(UserHandle.getUserId(uid)); if (vpn != null && vpn.isBlockingUid(uid)) { return true; } } - final String iface = (lp == null ? "" : lp.getInterfaceName()); - synchronized (mRulesLock) { - networkMetered = mMeteredIfaces.contains(iface); - uidRules = mUidRules.get(uid, RULE_NONE); - } - - boolean allowed = true; - // Check Data Saver Mode first... - if (networkMetered) { - if ((uidRules & RULE_REJECT_METERED) != 0) { - if (LOGD_RULES) Log.d(TAG, "uid " + uid + " is blacklisted"); - // Explicitly blacklisted. - allowed = false; - } else { - allowed = !mRestrictBackground - || (uidRules & RULE_ALLOW_METERED) != 0 - || (uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0; - if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" - + " mRestrictBackground=" + mRestrictBackground - + ", whitelisted=" + ((uidRules & RULE_ALLOW_METERED) != 0) - + ", tempWhitelist= + ((uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0)" - + ": " + allowed); - } - } - // ...then power restrictions. - if (allowed) { - allowed = (uidRules & RULE_REJECT_ALL) == 0; - if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" - + " rule is " + uidRulesToString(uidRules) + ": " + allowed); - } - return !allowed; + return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface); } private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { @@ -1481,67 +1438,24 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } - private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { + private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { @Override public void onUidRulesChanged(int uid, int uidRules) { - // caller is NPMS, since we only register with them - if (LOGD_RULES) { - log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")"); - } - - synchronized (mRulesLock) { - // skip update when we've already applied rules - final int oldRules = mUidRules.get(uid, RULE_NONE); - if (oldRules == uidRules) return; - - if (uidRules == RULE_NONE) { - mUidRules.delete(uid); - } else { - mUidRules.put(uid, uidRules); - } - } - // TODO: notify UID when it has requested targeted updates } - @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { - // caller is NPMS, since we only register with them - if (LOGD_RULES) { - log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")"); - } - - synchronized (mRulesLock) { - mMeteredIfaces.clear(); - for (String iface : meteredIfaces) { - mMeteredIfaces.add(iface); - } - } } - @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { - // caller is NPMS, since we only register with them - if (LOGD_RULES) { - log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); - } - - synchronized (mRulesLock) { - mRestrictBackground = restrictBackground; - } - + // TODO: relocate this specific callback in Tethering. if (restrictBackground) { log("onRestrictBackgroundChanged(true): disabling tethering"); mTethering.untetherAll(); } } - @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { - // caller is NPMS, since we only register with them - if (LOGD_RULES) { - log("onUidRulesChanged(uid=" + uid + ", uidPolicies=" + uidPolicies + ")"); - } } }; @@ -1976,33 +1890,6 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.decreaseIndent(); pw.println(); - pw.println("Metered Interfaces:"); - pw.increaseIndent(); - for (String value : mMeteredIfaces) { - pw.println(value); - } - pw.decreaseIndent(); - pw.println(); - - pw.print("Restrict background: "); - pw.println(mRestrictBackground); - pw.println(); - - pw.println("Status for known UIDs:"); - pw.increaseIndent(); - final int size = mUidRules.size(); - for (int i = 0; i < size; i++) { - final int uid = mUidRules.keyAt(i); - pw.print("UID="); - pw.print(uid); - final int uidRules = mUidRules.get(uid, RULE_NONE); - pw.print(" rules="); - pw.print(uidRulesToString(uidRules)); - pw.println(); - } - pw.println(); - pw.decreaseIndent(); - pw.println("Network Requests:"); pw.increaseIndent(); for (NetworkRequestInfo nri : mNetworkRequests.values()) { @@ -3437,6 +3324,10 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.e(TAG, s); } + private static void loge(String s, Throwable t) { + Slog.e(TAG, s, t); + } + private static <T> T checkNotNull(T value, String message) { if (value == null) { throw new NullPointerException(message); @@ -4197,20 +4088,16 @@ public class ConnectivityService extends IConnectivityManager.Stub private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) { final int uid = Binder.getCallingUid(); if (isSystem(uid)) { + // Exemption for system uid. return; } - // if UID is restricted, don't allow them to bring up metered APNs - if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) { - final int uidRules; - synchronized(mRulesLock) { - uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); - } - if (mRestrictBackground && (uidRules & RULE_ALLOW_METERED) == 0 - && (uidRules & RULE_TEMPORARY_ALLOW_METERED) == 0) { - // we could silently fail or we can filter the available nets to only give - // them those they have access to. Chose the more useful option. - networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); - } + if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) { + // Policy already enforced. + return; + } + if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) { + // If UID is restricted, don't allow them to bring up metered APNs. + networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); } } diff --git a/services/core/java/com/android/server/FontManagerService.java b/services/core/java/com/android/server/FontManagerService.java deleted file mode 100644 index f1726473c591..000000000000 --- a/services/core/java/com/android/server/FontManagerService.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import android.content.Context; -import android.graphics.FontListParser; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.text.FontConfig; -import android.util.Slog; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.font.IFontManager; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; - -public class FontManagerService extends IFontManager.Stub { - private static final String TAG = "FontManagerService"; - private static final String FONTS_CONFIG = "/system/etc/fonts.xml"; - private static final String SYSTEM_FONT_DIR = "/system/fonts/"; - - @GuardedBy("mLock") - private FontConfig mConfig; - private final Object mLock = new Object(); - - public static final class Lifecycle extends SystemService { - private final FontManagerService mService; - - public Lifecycle(Context context) { - super(context); - mService = new FontManagerService(); - } - - @Override - public void onStart() { - try { - publishBinderService(Context.FONT_SERVICE, mService); - } catch (Throwable t) { - // Starting this service is not critical to the running of this device and should - // therefore not crash the device. If it fails, log the error and continue. - Slog.e(TAG, "Could not start the FontManagerService.", t); - } - } - } - - @Override - public FontConfig getSystemFonts() { - synchronized (mLock) { - if (mConfig != null) { - return mConfig; - } - - mConfig = loadFromSystem(); - if (mConfig == null) { - return null; - } - - for (FontConfig.Family family : mConfig.getFamilies()) { - for (FontConfig.Font font : family.getFonts()) { - File fontFile = new File(SYSTEM_FONT_DIR, font.getFontName()); - font.setUri(Uri.fromFile(fontFile)); - } - } - - return mConfig; - } - } - - private FontConfig loadFromSystem() { - File configFilename = new File(FONTS_CONFIG); - try { - FileInputStream fontsIn = new FileInputStream(configFilename); - return FontListParser.parse(fontsIn); - } catch (IOException | XmlPullParserException e) { - Slog.e(TAG, "Error opening " + configFilename, e); - } - return null; - } - - public FontManagerService() { - } -} diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index 421d5a6ab964..c105b1244e74 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.app.ActivityThread; import android.content.Context; import android.os.IBinder; import android.os.ServiceManager; @@ -104,6 +105,16 @@ public abstract class SystemService { } /** + * Get the system UI context. This context is to be used for displaying UI. It is themable, + * which means resources can be overridden at runtime. Do not use to retrieve properties that + * configure the behavior of the device that is not UX related. + */ + public final Context getUiContext() { + // This has already been set up by the time any SystemServices are created. + return ActivityThread.currentActivityThread().getSystemUiContext(); + } + + /** * Returns true if the system is running in safe mode. * TODO: we should define in which phase this becomes valid */ diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java new file mode 100644 index 000000000000..17965d099af0 --- /dev/null +++ b/services/core/java/com/android/server/ThreadPriorityBooster.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 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; + +import android.os.Process; + +/** + * Utility class to boost threads in sections where important locks are held. + */ +public class ThreadPriorityBooster { + + private final int mBoostToPriority; + private final int mLockGuardIndex; + + private final ThreadLocal<PriorityState> mThreadState = new ThreadLocal<PriorityState>() { + @Override protected PriorityState initialValue() { + return new PriorityState(); + } + }; + + public ThreadPriorityBooster(int boostToPriority, int lockGuardIndex) { + mBoostToPriority = boostToPriority; + mLockGuardIndex = lockGuardIndex; + } + + public void boost() { + final int tid = Process.myTid(); + final int prevPriority = Process.getThreadPriority(tid); + PriorityState state = mThreadState.get(); + if (state.regionCounter == 0 && prevPriority > mBoostToPriority) { + state.prevPriority = prevPriority; + Process.setThreadPriority(tid, mBoostToPriority); + } + state.regionCounter++; + if (LockGuard.ENABLED) { + LockGuard.guard(mLockGuardIndex); + } + } + + public void reset() { + PriorityState state = mThreadState.get(); + state.regionCounter--; + if (state.regionCounter == 0 && state.prevPriority > mBoostToPriority) { + Process.setThreadPriority(Process.myTid(), state.prevPriority); + } + } + + private static class PriorityState { + + /** + * Acts as counter for number of synchronized region that needs to acquire 'this' as a lock + * the current thread is currently in. When it drops down to zero, we will no longer boost + * the thread's priority. + */ + int regionCounter; + + /** + * The thread's previous priority before boosting. + */ + int prevPriority; + } +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index d996ee282ef9..e560d325e6dd 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -123,7 +123,6 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; /** @@ -191,17 +190,14 @@ public class AccountManagerService } private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>(); - private final AtomicInteger mNotificationIds = - new AtomicInteger(SystemMessage.ACCOUNT_MANAGER_BASE); static class UserAccounts { private final int userId; final AccountsDb accountsDb; - private final HashMap<Pair<Pair<Account, String>, Integer>, Integer> - credentialsPermissionNotificationIds = - new HashMap<Pair<Pair<Account, String>, Integer>, Integer>(); - private final HashMap<Account, Integer> signinRequiredNotificationIds = - new HashMap<Account, Integer>(); + private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId> + credentialsPermissionNotificationIds = new HashMap<>(); + private final HashMap<Account, NotificationId> signinRequiredNotificationIds + = new HashMap<>(); final Object cacheLock = new Object(); final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock /** protected by the {@link #cacheLock} */ @@ -1863,12 +1859,12 @@ public class AccountManagerService */ cancelNotification( getSigninRequiredNotificationId(accounts, accountToRename), - new UserHandle(accounts.userId)); + new UserHandle(accounts.userId)); synchronized(accounts.credentialsPermissionNotificationIds) { for (Pair<Pair<Account, String>, Integer> pair: accounts.credentialsPermissionNotificationIds.keySet()) { if (accountToRename.equals(pair.first.first)) { - int id = accounts.credentialsPermissionNotificationIds.get(pair); + NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair); cancelNotification(id, new UserHandle(accounts.userId)); } } @@ -2021,7 +2017,7 @@ public class AccountManagerService for (Pair<Pair<Account, String>, Integer> pair: accounts.credentialsPermissionNotificationIds.keySet()) { if (account.equals(pair.first.first)) { - int id = accounts.credentialsPermissionNotificationIds.get(pair); + NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair); cancelNotification(id, user); } } @@ -2912,8 +2908,8 @@ public class AccountManagerService // the intent from a non-Activity context. This is the default behavior. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } - intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account, - authTokenType, uid) + (packageName != null ? packageName : ""))); + intent.addCategory(getCredentialPermissionNotificationId(account, + authTokenType, uid).mTag + (packageName != null ? packageName : "")); intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account); intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType); intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response); @@ -2922,33 +2918,39 @@ public class AccountManagerService return intent; } - private Integer getCredentialPermissionNotificationId(Account account, String authTokenType, - int uid) { - Integer id; + private NotificationId getCredentialPermissionNotificationId(Account account, + String authTokenType, int uid) { + NotificationId nId; UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid)); synchronized (accounts.credentialsPermissionNotificationIds) { final Pair<Pair<Account, String>, Integer> key = new Pair<Pair<Account, String>, Integer>( new Pair<Account, String>(account, authTokenType), uid); - id = accounts.credentialsPermissionNotificationIds.get(key); - if (id == null) { - id = mNotificationIds.incrementAndGet(); - accounts.credentialsPermissionNotificationIds.put(key, id); + nId = accounts.credentialsPermissionNotificationIds.get(key); + if (nId == null) { + String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION + + ":" + account.hashCode() + ":" + authTokenType.hashCode(); + int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION; + nId = new NotificationId(tag, id); + accounts.credentialsPermissionNotificationIds.put(key, nId); } } - return id; + return nId; } - private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) { - Integer id; + private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) { + NotificationId nId; synchronized (accounts.signinRequiredNotificationIds) { - id = accounts.signinRequiredNotificationIds.get(account); - if (id == null) { - id = mNotificationIds.incrementAndGet(); - accounts.signinRequiredNotificationIds.put(account, id); + nId = accounts.signinRequiredNotificationIds.get(account); + if (nId == null) { + String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN + + ":" + account.hashCode(); + int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN; + nId = new NotificationId(tag, id); + accounts.signinRequiredNotificationIds.put(account, nId); } } - return id; + return nId; } @Override @@ -4931,8 +4933,8 @@ public class AccountManagerService createNoCredentialsPermissionNotification(account, intent, packageName, userId); } else { Context contextForUser = getContextForUser(new UserHandle(userId)); - final Integer notificationId = getSigninRequiredNotificationId(accounts, account); - intent.addCategory(String.valueOf(notificationId)); + final NotificationId id = getSigninRequiredNotificationId(accounts, account); + intent.addCategory(id.mTag); final String notificationTitleFormat = contextForUser.getText(R.string.notification_title).toString(); @@ -4948,21 +4950,21 @@ public class AccountManagerService mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, new UserHandle(userId))) .build(); - installNotification(notificationId, n, packageName, userId); + installNotification(id, n, packageName, userId); } } finally { restoreCallingIdentity(identityToken); } } - private void installNotification(int notificationId, final Notification notification, + private void installNotification(NotificationId id, final Notification notification, String packageName, int userId) { final long token = clearCallingIdentity(); try { INotificationManager notificationManager = mInjector.getNotificationManager(); try { - notificationManager.enqueueNotificationWithTag(packageName, packageName, null, - notificationId, notification, new int[1], userId); + notificationManager.enqueueNotificationWithTag(packageName, packageName, + id.mTag, id.mId, notification, new int[1], userId); } catch (RemoteException e) { /* ignore - local call */ } @@ -4971,15 +4973,15 @@ public class AccountManagerService } } - private void cancelNotification(int id, UserHandle user) { + private void cancelNotification(NotificationId id, UserHandle user) { cancelNotification(id, mContext.getPackageName(), user); } - private void cancelNotification(int id, String packageName, UserHandle user) { + private void cancelNotification(NotificationId id, String packageName, UserHandle user) { long identityToken = clearCallingIdentity(); try { INotificationManager service = mInjector.getNotificationManager(); - service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier()); + service.cancelNotificationWithTag(packageName, id.mTag, id.mId, user.getIdentifier()); } catch (RemoteException e) { /* ignore - local call */ } finally { @@ -5893,4 +5895,14 @@ public class AccountManagerService return NotificationManager.getService(); } } + + private class NotificationId { + final String mTag; + private final int mId; + + NotificationId(String tag, int type) { + mTag = tag; + mId = type; + } + } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 9ad945ffb43a..4cbfb275fd32 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1140,7 +1140,7 @@ public final class ActiveServices { // Service is already running, so we can immediately // publish the connection. try { - c.conn.connected(s.name, b.intent.binder); + c.conn.connected(s.name, b.intent.binder, false); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + s.shortName + " to connection " + c.conn.asBinder() @@ -1194,7 +1194,7 @@ public final class ActiveServices { } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c); try { - c.conn.connected(r.name, service); + c.conn.connected(r.name, service, false); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + r.name + " to connection " + c.conn.asBinder() + @@ -2081,7 +2081,7 @@ public final class ActiveServices { // being brought down. Mark it as dead. cr.serviceDead = true; try { - cr.conn.connected(r.name, null); + cr.conn.connected(r.name, null, true); } catch (Exception e) { Slog.w(TAG, "Failure disconnecting service " + r.name + " to connection " + c.get(i).conn.asBinder() + diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7618144afd9c..19fc2b876c3e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -17,12 +17,12 @@ package com.android.server.am; import static android.Manifest.permission.CHANGE_CONFIGURATION; +import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; -import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; @@ -42,13 +42,49 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; +import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; +import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground; import static android.os.Build.VERSION_CODES.N; +import static android.os.Process.BLUETOOTH_UID; +import static android.os.Process.FIRST_APPLICATION_UID; +import static android.os.Process.FIRST_ISOLATED_UID; +import static android.os.Process.LAST_ISOLATED_UID; +import static android.os.Process.NFC_UID; +import static android.os.Process.PHONE_UID; import static android.os.Process.PROC_CHAR; import static android.os.Process.PROC_OUT_LONG; import static android.os.Process.PROC_PARENS; import static android.os.Process.PROC_SPACE_TERM; -import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; -import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground; +import static android.os.Process.ProcessStartResult; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SCHED_FIFO; +import static android.os.Process.SCHED_OTHER; +import static android.os.Process.SCHED_RESET_ON_FORK; +import static android.os.Process.SHELL_UID; +import static android.os.Process.SIGNAL_QUIT; +import static android.os.Process.SIGNAL_USR1; +import static android.os.Process.SYSTEM_UID; +import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE; +import static android.os.Process.THREAD_GROUP_DEFAULT; +import static android.os.Process.THREAD_GROUP_TOP_APP; +import static android.os.Process.THREAD_PRIORITY_BACKGROUND; +import static android.os.Process.THREAD_PRIORITY_FOREGROUND; +import static android.os.Process.getFreeMemory; +import static android.os.Process.getThreadPriority; +import static android.os.Process.getTotalMemory; +import static android.os.Process.isThreadInProcess; +import static android.os.Process.killProcess; +import static android.os.Process.killProcessQuiet; +import static android.os.Process.myPid; +import static android.os.Process.myUid; +import static android.os.Process.readProcFile; +import static android.os.Process.removeAllProcessGroups; +import static android.os.Process.sendSignal; +import static android.os.Process.setProcessGroup; +import static android.os.Process.setThreadPriority; +import static android.os.Process.setThreadScheduler; +import static android.os.Process.startWebView; +import static android.os.Process.zygoteProcess; import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; import static android.provider.Settings.Global.DEBUG_APP; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; @@ -323,7 +359,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; -import com.android.internal.notification.SystemNotificationChannels; import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -341,6 +376,7 @@ import com.android.internal.app.procstats.ProcessStats; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; +import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.IResultReceiver; @@ -367,6 +403,7 @@ import com.android.server.ServiceThread; import com.android.server.SystemConfig; import com.android.server.SystemService; import com.android.server.SystemServiceManager; +import com.android.server.ThreadPriorityBooster; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.firewall.IntentFirewall; @@ -409,7 +446,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import dalvik.system.VMRuntime; - import libcore.io.IoUtils; import libcore.util.EmptyArray; @@ -547,7 +583,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Maximum number of persisted Uri grants a package is allowed static final int MAX_PERSISTED_URI_GRANTS = 128; - static final int MY_PID = Process.myPid(); + static final int MY_PID = myPid(); static final String[] EMPTY_STRING_ARRAY = new String[0]; @@ -680,13 +716,13 @@ public class ActivityManagerService extends IActivityManager.Stub if (mTopAppVrThreadTid > 0) { // Ensure that when entering persistent VR mode the last top-app loses // SCHED_FIFO. - Process.setThreadScheduler(mTopAppVrThreadTid, Process.SCHED_OTHER, 0); + setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0); mTopAppVrThreadTid = 0; } } else if (mPersistentVrThreadTid > 0) { // Ensure that when leaving persistent VR mode we reschedule the high priority // persistent thread. - Process.setThreadScheduler(mPersistentVrThreadTid, Process.SCHED_OTHER, 0); + setThreadScheduler(mPersistentVrThreadTid, SCHED_OTHER, 0); mPersistentVrThreadTid = 0; } } @@ -773,42 +809,15 @@ public class ActivityManagerService extends IActivityManager.Stub && !mKeyguardController.isKeyguardShowing(); } - private static final class PriorityState { - // Acts as counter for number of synchronized region that needs to acquire 'this' as a lock - // the current thread is currently in. When it drops down to zero, we will no longer boost - // the thread's priority. - private int regionCounter = 0; - - // The thread's previous priority before boosting. - private int prevPriority = Integer.MIN_VALUE; - } - - static ThreadLocal<PriorityState> sThreadPriorityState = new ThreadLocal<PriorityState>() { - @Override protected PriorityState initialValue() { - return new PriorityState(); - } - }; + private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster( + THREAD_PRIORITY_FOREGROUND, LockGuard.INDEX_ACTIVITY); static void boostPriorityForLockedSection() { - int tid = Process.myTid(); - int prevPriority = Process.getThreadPriority(tid); - PriorityState state = sThreadPriorityState.get(); - if (state.regionCounter == 0 && prevPriority > -2) { - state.prevPriority = prevPriority; - Process.setThreadPriority(tid, -2); - } - state.regionCounter++; - if (LockGuard.ENABLED) { - LockGuard.guard(LockGuard.INDEX_ACTIVITY); - } + sThreadPriorityBooster.boost(); } static void resetPriorityAfterLockedSection() { - PriorityState state = sThreadPriorityState.get(); - state.regionCounter--; - if (state.regionCounter == 0 && state.prevPriority > -2) { - Process.setThreadPriority(Process.myTid(), state.prevPriority); - } + sThreadPriorityBooster.reset(); } public class PendingAssistExtras extends Binder implements Runnable { @@ -889,7 +898,7 @@ public class ActivityManagerService extends IActivityManager.Stub * Non-persistent app uid whitelist for background restrictions */ int[] mBackgroundUidWhitelist = new int[] { - Process.BLUETOOTH_UID + BLUETOOTH_UID }; /** @@ -1350,7 +1359,13 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") boolean mLaunchWarningShown = false; @GuardedBy("this") boolean mCheckedForSetup = false; - Context mContext; + final Context mContext; + + /** + * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can + * change at runtime. Use mContext for non-UI purposes. + */ + final Context mUiContext; /** * The time at which we will allow normal application switches again, @@ -1852,7 +1867,7 @@ public class ActivityManagerService extends IActivityManager.Stub } break; case SHOW_FACTORY_ERROR_UI_MSG: { Dialog d = new FactoryErrorDialog( - mContext, msg.getData().getCharSequence("msg")); + mUiContext, msg.getData().getCharSequence("msg")); d.show(); ensureBootCompleted(); } break; @@ -1863,7 +1878,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (!app.waitedForDebugger) { Dialog d = new AppWaitingForDebuggerDialog( ActivityManagerService.this, - mContext, app); + mUiContext, app); app.waitDialog = d; app.waitedForDebugger = true; d.show(); @@ -1878,24 +1893,24 @@ public class ActivityManagerService extends IActivityManager.Stub } break; case SHOW_UID_ERROR_UI_MSG: { if (mShowDialogs) { - AlertDialog d = new BaseErrorDialog(mContext); + AlertDialog d = new BaseErrorDialog(mUiContext); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); d.setCancelable(false); - d.setTitle(mContext.getText(R.string.android_system_label)); - d.setMessage(mContext.getText(R.string.system_error_wipe_data)); - d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), + d.setTitle(mUiContext.getText(R.string.android_system_label)); + d.setMessage(mUiContext.getText(R.string.system_error_wipe_data)); + d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok), obtainMessage(DISMISS_DIALOG_UI_MSG, d)); d.show(); } } break; case SHOW_FINGERPRINT_ERROR_UI_MSG: { if (mShowDialogs) { - AlertDialog d = new BaseErrorDialog(mContext); + AlertDialog d = new BaseErrorDialog(mUiContext); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); d.setCancelable(false); - d.setTitle(mContext.getText(R.string.android_system_label)); - d.setMessage(mContext.getText(R.string.system_error_manufacturer)); - d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), + d.setTitle(mUiContext.getText(R.string.android_system_label)); + d.setMessage(mUiContext.getText(R.string.system_error_manufacturer)); + d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok), obtainMessage(DISMISS_DIALOG_UI_MSG, d)); d.show(); } @@ -1919,7 +1934,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (mode == ActivityManager.COMPAT_MODE_DISABLED || mode == ActivityManager.COMPAT_MODE_ENABLED) { mCompatModeDialog = new CompatModeDialog( - ActivityManagerService.this, mContext, + ActivityManagerService.this, mUiContext, ar.info.applicationInfo); mCompatModeDialog.show(); } @@ -1939,7 +1954,7 @@ public class ActivityManagerService extends IActivityManager.Stub ar.packageName)) { // TODO(multi-display): Show dialog on appropriate display. mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog( - ActivityManagerService.this, mContext, ar.info.applicationInfo); + ActivityManagerService.this, mUiContext, ar.info.applicationInfo); mUnsupportedDisplaySizeDialog.show(); } } @@ -2461,12 +2476,12 @@ public class ActivityManagerService extends IActivityManager.Stub if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) { try { if (mVrState == VR_MODE) { - Process.setThreadScheduler(proc.vrThreadTid, - Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + setThreadScheduler(proc.vrThreadTid, + SCHED_FIFO | SCHED_RESET_ON_FORK, 1); mTopAppVrThreadTid = proc.vrThreadTid; } else { - Process.setThreadScheduler(proc.vrThreadTid, - Process.SCHED_OTHER, 0); + setThreadScheduler(proc.vrThreadTid, + SCHED_OTHER, 0); mTopAppVrThreadTid = 0; } } catch (IllegalArgumentException e) { @@ -2523,7 +2538,7 @@ public class ActivityManagerService extends IActivityManager.Stub final List<ProcessCpuTracker.Stats> stats; synchronized (mProcessCpuTracker) { stats = mProcessCpuTracker.getStats( (st)-> { - return st.vsize > 0 && st.uid < Process.FIRST_APPLICATION_UID; + return st.vsize > 0 && st.uid < FIRST_APPLICATION_UID; }); } final int N = stats.size(); @@ -2731,6 +2746,7 @@ public class ActivityManagerService extends IActivityManager.Stub public ActivityManagerService(Injector injector) { mInjector = injector; mContext = mInjector.getContext(); + mUiContext = null; GL_ES_VERSION = 0; mActivityStarter = null; mAppErrors = null; @@ -2762,8 +2778,10 @@ public class ActivityManagerService extends IActivityManager.Stub LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY); mInjector = new Injector(); mContext = systemContext; + mFactoryTest = FactoryTest.getMode(); mSystemThread = ActivityThread.currentActivityThread(); + mUiContext = mSystemThread.getSystemUiContext(); Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); @@ -2771,7 +2789,7 @@ public class ActivityManagerService extends IActivityManager.Stub com.android.internal.R.bool.config_permissionReviewRequired); mHandlerThread = new ServiceThread(TAG, - android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); + THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); mHandlerThread.start(); mHandler = new MainHandler(mHandlerThread.getLooper()); mUiHandler = mInjector.getUiHandler(this); @@ -2792,7 +2810,7 @@ public class ActivityManagerService extends IActivityManager.Stub /* static; one-time init here */ if (sKillHandler == null) { sKillThread = new ServiceThread(TAG + ":kill", - android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */); + THREAD_PRIORITY_BACKGROUND, true /* allowIo */); sKillThread.start(); sKillHandler = new KillHandler(sKillThread.getLooper()); } @@ -2806,7 +2824,7 @@ public class ActivityManagerService extends IActivityManager.Stub mServices = new ActiveServices(this); mProviderMap = new ProviderMap(this); - mAppErrors = new AppErrors(mContext, this); + mAppErrors = new AppErrors(mUiContext, this); // TODO: Move creation of battery stats service outside of activity manager service. File dataDir = Environment.getDataDirectory(); @@ -2849,7 +2867,7 @@ public class ActivityManagerService extends IActivityManager.Stub mTempConfig.setToDefaults(); mTempConfig.setLocales(LocaleList.getDefault()); mConfigurationSeq = mTempConfig.seq = 1; - mStackSupervisor = new ActivityStackSupervisor(this); + mStackSupervisor = createStackSupervisor(); mStackSupervisor.onConfigurationChanged(mTempConfig); mKeyguardController = mStackSupervisor.mKeyguardController; mCompatModePackages = new CompatModePackages(this, systemDir, mHandler); @@ -2897,6 +2915,10 @@ public class ActivityManagerService extends IActivityManager.Stub Watchdog.getInstance().addThread(mHandler); } + protected ActivityStackSupervisor createStackSupervisor() { + return new ActivityStackSupervisor(this, mHandler.getLooper()); + } + public void setSystemServiceManager(SystemServiceManager mgr) { mSystemServiceManager = mgr; } @@ -2906,7 +2928,7 @@ public class ActivityManagerService extends IActivityManager.Stub } private void start() { - Process.removeAllProcessGroups(); + removeAllProcessGroups(); mProcessCpuThread.start(); mBatteryStatsService.publish(mContext); @@ -3114,7 +3136,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, - -1, Process.SYSTEM_UID, UserHandle.USER_ALL); + -1, SYSTEM_UID, UserHandle.USER_ALL); } } @@ -3151,7 +3173,8 @@ public class ActivityManagerService extends IActivityManager.Stub * {@link ActivityStack#setResumedActivityLocked} when an activity is resumed. */ void setResumedActivityUncheckLocked(ActivityRecord r, String reason) { - if (r.task.isApplicationTask()) { + final TaskRecord task = r.getTask(); + if (task.isApplicationTask()) { if (mCurAppTimeTracker != r.appTimeTracker) { // We are switching app tracking. Complete the current one. if (mCurAppTimeTracker != null) { @@ -3174,17 +3197,18 @@ public class ActivityManagerService extends IActivityManager.Stub // TODO: VI Maybe r.task.voiceInteractor || r.voiceInteractor != null // TODO: Probably not, because we don't want to resume voice on switching // back to this activity - if (r.task.voiceInteractor != null) { - startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid); + if (task.voiceInteractor != null) { + startRunningVoiceLocked(task.voiceSession, r.info.applicationInfo.uid); } else { finishRunningVoiceLocked(); if (mLastResumedActivity != null) { final IVoiceInteractionSession session; - if (mLastResumedActivity.task != null - && mLastResumedActivity.task.voiceSession != null) { - session = mLastResumedActivity.task.voiceSession; + final TaskRecord lastResumedActivityTask = mLastResumedActivity.getTask(); + if (lastResumedActivityTask != null + && lastResumedActivityTask.voiceSession != null) { + session = lastResumedActivityTask.voiceSession; } else { session = mLastResumedActivity.voiceSession; } @@ -3317,7 +3341,7 @@ public class ActivityManagerService extends IActivityManager.Stub final void showAskCompatModeDialogLocked(ActivityRecord r) { Message msg = Message.obtain(); msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG; - msg.obj = r.task.askedCompatMode ? null : r; + msg.obj = r.getTask().askedCompatMode ? null : r; mUiHandler.sendMessage(msg); } @@ -3384,7 +3408,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (lrui >= 0) { if (!app.killed) { Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app); - Process.killProcessQuiet(app.pid); + killProcessQuiet(app.pid); killProcessGroup(app.uid, app.pid); } if (lrui <= mLruProcessActivityStart) { @@ -3593,7 +3617,7 @@ public class ActivityManagerService extends IActivityManager.Stub } final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) { - if (uid == Process.SYSTEM_UID) { + if (uid == SYSTEM_UID) { // The system gets to run in any process. If there are multiple // processes with the same uid, just pick the first (this // should never happen). @@ -3659,7 +3683,7 @@ public class ActivityManagerService extends IActivityManager.Stub // closest thing to a parent's uid is SYSTEM_UID. // The only important thing here is to keep AI.uid != PR.uid, in order to trigger // the |isolated| logic in the ProcessRecord constructor. - info.uid = Process.SYSTEM_UID; + info.uid = SYSTEM_UID; info.processName = processName; info.className = entryPoint; info.packageName = "android"; @@ -3954,9 +3978,9 @@ public class ActivityManagerService extends IActivityManager.Stub Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); checkTime(startTime, "startProcess: asking zygote to start proc"); - Process.ProcessStartResult startResult; + ProcessStartResult startResult; if (hostingType.equals("webview_service")) { - startResult = Process.startWebView(entryPoint, + startResult = startWebView(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, entryPointArgs); @@ -4193,7 +4217,7 @@ public class ActivityManagerService extends IActivityManager.Stub } void enforceShellRestriction(String restriction, int userHandle) { - if (Binder.getCallingUid() == Process.SHELL_UID) { + if (Binder.getCallingUid() == SHELL_UID) { if (userHandle < 0 || mUserController.hasUserRestriction(restriction, userHandle)) { throw new SecurityException("Shell does not have permission to access user " + userHandle); @@ -4559,7 +4583,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (sourceRecord.app == null) { throw new SecurityException("Called without a process attached to activity"); } - if (UserHandle.getAppId(sourceRecord.app.uid) != Process.SYSTEM_UID) { + if (UserHandle.getAppId(sourceRecord.app.uid) != SYSTEM_UID) { // This is still okay, as long as this activity is running under the // uid of the original calling activity. if (sourceRecord.app.uid != sourceRecord.launchedFromUid) { @@ -4723,7 +4747,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (ActivityRecord.forTokenLocked(callingActivity) != activity) { throw new SecurityException("Only focused activity can call startVoiceInteraction"); } - if (mRunningVoice != null || activity.task.voiceSession != null + if (mRunningVoice != null || activity.getTask().voiceSession != null || activity.voiceSession != null) { Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction"); return; @@ -5033,7 +5057,7 @@ public class ActivityManagerService extends IActivityManager.Stub return true; } // Keep track of the root activity of the task before we finish it - TaskRecord tr = r.task; + TaskRecord tr = r.getTask(); ActivityRecord rootR = tr.getRootActivity(); if (rootR == null) { Slog.w(TAG, "Finishing task with all activities already finished"); @@ -5170,7 +5194,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps // can finish. - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV && mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) { mStackSupervisor.showLockTaskToast(); @@ -5411,7 +5435,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (!app.killed) { if (!fromBinderDied) { - Process.killProcessQuiet(pid); + killProcessQuiet(pid); } killProcessGroup(app.uid, pid); app.killed = true; @@ -5506,7 +5530,7 @@ public class ActivityManagerService extends IActivityManager.Stub } public void dumpWithTimeout(int pid) { - Process.sendSignal(pid, Process.SIGNAL_QUIT); + sendSignal(pid, SIGNAL_QUIT); synchronized (this) { try { wait(TRACE_DUMP_TIMEOUT_MS); // Wait for traces file to be closed. @@ -5761,7 +5785,7 @@ public class ActivityManagerService extends IActivityManager.Stub intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); intent.putExtra(Intent.EXTRA_UID, pkgUidF); intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUidF)); - broadcastIntentInPackage("android", Process.SYSTEM_UID, intent, + broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0, null, null, null, null, false, false, userIdF); if (observer != null) { @@ -5979,7 +6003,7 @@ public class ActivityManagerService extends IActivityManager.Stub public void addPackageDependency(String packageName) { synchronized (this) { int callingPid = Binder.getCallingPid(); - if (callingPid == Process.myPid()) { + if (callingPid == myPid()) { // Yeah, um, no. return; } @@ -6011,7 +6035,7 @@ public class ActivityManagerService extends IActivityManager.Stub } int callerUid = Binder.getCallingUid(); // Only the system server can kill an application - if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) { + if (UserHandle.getAppId(callerUid) == SYSTEM_UID) { // Post an aysnc message to kill the application Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG); msg.arg1 = appId; @@ -6038,7 +6062,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { // Only allow this from foreground processes, so that background // applications can't abuse it to prevent system UI from being shown. - if (uid >= Process.FIRST_APPLICATION_UID) { + if (uid >= FIRST_APPLICATION_UID) { ProcessRecord proc; synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(pid); @@ -6069,7 +6093,7 @@ public class ActivityManagerService extends IActivityManager.Stub broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, - -1, Process.SYSTEM_UID, UserHandle.USER_ALL); + -1, SYSTEM_UID, UserHandle.USER_ALL); } @Override @@ -6135,7 +6159,7 @@ public class ActivityManagerService extends IActivityManager.Stub int callerUid = Binder.getCallingUid(); // Only the system server can kill an application - if (callerUid == Process.SYSTEM_UID) { + if (callerUid == SYSTEM_UID) { synchronized (this) { ProcessRecord app = getProcessRecordLocked(processName, uid, true); if (app != null && app.thread != null) { @@ -6171,7 +6195,7 @@ public class ActivityManagerService extends IActivityManager.Stub intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid)); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid)); + null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid)); } @@ -6688,7 +6712,7 @@ public class ActivityManagerService extends IActivityManager.Stub + " (IApplicationThread " + thread + "); dropping process"); EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid); if (pid > 0 && pid != MY_PID) { - Process.killProcessQuiet(pid); + killProcessQuiet(pid); //TODO: killProcessGroup(app.info.uid, pid); } else { try { @@ -6796,7 +6820,7 @@ public class ActivityManagerService extends IActivityManager.Stub // If the app is being launched for restore or full backup, set it up specially boolean isRestrictedBackupMode = false; if (mBackupTarget != null && mBackupAppName.equals(processName)) { - isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID + isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID && ((mBackupTarget.backupMode == BackupRecord.RESTORE) || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL) || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL)); @@ -7019,7 +7043,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void showBootMessage(final CharSequence msg, final boolean always) { - if (Binder.getCallingUid() != Process.myUid()) { + if (Binder.getCallingUid() != myUid()) { throw new SecurityException(); } mWindowManager.showBootMessage(msg, always); @@ -7056,7 +7080,7 @@ public class ActivityManagerService extends IActivityManager.Stub ArraySet<String> completedIsas = new ArraySet<String>(); for (String abi : Build.SUPPORTED_ABIS) { - Process.zygoteProcess.establishZygoteConnectionForAbi(abi); + zygoteProcess.establishZygoteConnectionForAbi(abi); final String instructionSet = VMRuntime.getInstructionSet(abi); if (!completedIsas.contains(instructionSet)) { try { @@ -7397,7 +7421,7 @@ public class ActivityManagerService extends IActivityManager.Stub userId = UserHandle.USER_CURRENT; } try { - if (callingUid != 0 && callingUid != Process.SYSTEM_UID) { + if (callingUid != 0 && callingUid != SYSTEM_UID) { final int uid = AppGlobals.getPackageManager().getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid)); if (!UserHandle.isSameApp(callingUid, uid)) { @@ -7834,7 +7858,7 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } // An activity is consider to be in multi-window mode if its task isn't fullscreen. - return !r.task.mFullscreen; + return !r.getTask().mFullscreen; } } finally { Binder.restoreCallingIdentity(origId); @@ -8664,7 +8688,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Third... does the caller itself have permission to access // this uri? final int callingAppId = UserHandle.getAppId(callingUid); - if ((callingAppId == Process.SYSTEM_UID) || (callingAppId == Process.ROOT_UID)) { + if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) { if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) { // Exempted authority for cropping user photos in Settings app } else { @@ -9150,7 +9174,7 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("Unknown owner: " + token); } if (fromUid != Binder.getCallingUid()) { - if (Binder.getCallingUid() != Process.myUid()) { + if (Binder.getCallingUid() != myUid()) { // Only system code can grant URI permissions on behalf // of other users. throw new SecurityException("nice try"); @@ -9534,8 +9558,8 @@ public class ActivityManagerService extends IActivityManager.Stub public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ); final long cachedAppMem = mProcessList.getMemLevel(ProcessList.CACHED_APP_MIN_ADJ); - outInfo.availMem = Process.getFreeMemory(); - outInfo.totalMem = Process.getTotalMemory(); + outInfo.availMem = getFreeMemory(); + outInfo.totalMem = getTotalMemory(); outInfo.threshold = homeAppMem; outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2)); outInfo.hiddenAppThreshold = cachedAppMem; @@ -9927,8 +9951,9 @@ public class ActivityManagerService extends IActivityManager.Stub ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r != null) { r.setTaskDescription(td); - r.task.updateTaskDescription(); - mTaskChangeNotificationController.notifyTaskDescriptionChanged(r.task.taskId, td); + final TaskRecord task = r.getTask(); + task.updateTaskDescription(); + mTaskChangeNotificationController.notifyTaskDescriptionChanged(task.taskId, td); } } } @@ -10378,8 +10403,8 @@ public class ActivityManagerService extends IActivityManager.Stub } if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r); - r.task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, - ANIMATE, !DEFER_RESUME, "exitFreeformMode"); + r.getTask().reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, + REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "exitFreeformMode"); } finally { Binder.restoreCallingIdentity(ident); } @@ -10677,7 +10702,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void updateDeviceOwner(String packageName) { final int callingUid = Binder.getCallingUid(); - if (callingUid != 0 && callingUid != Process.SYSTEM_UID) { + if (callingUid != 0 && callingUid != SYSTEM_UID) { throw new SecurityException("updateDeviceOwner called from non-system process"); } synchronized (this) { @@ -10688,7 +10713,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void updateLockTaskPackages(int userId, String[] packages) { final int callingUid = Binder.getCallingUid(); - if (callingUid != 0 && callingUid != Process.SYSTEM_UID) { + if (callingUid != 0 && callingUid != SYSTEM_UID) { enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES, "updateLockTaskPackages()"); } @@ -10711,7 +10736,7 @@ public class ActivityManagerService extends IActivityManager.Stub // is initiated by system after the pinning request was shown and locked mode is initiated // by an authorized app directly final int callingUid = Binder.getCallingUid(); - boolean isSystemInitiated = callingUid == Process.SYSTEM_UID; + boolean isSystemInitiated = callingUid == SYSTEM_UID; long ident = Binder.clearCallingIdentity(); try { if (!isSystemInitiated) { @@ -10760,7 +10785,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (r == null) { return; } - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); if (task != null) { startLockTaskModeLocked(task); } @@ -10859,7 +10884,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (r == null) { return; } - mStackSupervisor.showLockTaskEscapeMessageLocked(r.task); + mStackSupervisor.showLockTaskEscapeMessageLocked(r.getTask()); } } @@ -11190,7 +11215,7 @@ public class ActivityManagerService extends IActivityManager.Stub proc.procStatFile = "/proc/" + proc.pid + "/stat"; } mProcessStateStatsLongs[0] = 0; - if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null, + if (!readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null, mProcessStateStatsLongs, null)) { if (DEBUG_OOM_ADJ) Slog.d(TAG, "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile); return false; @@ -11892,7 +11917,7 @@ public class ActivityManagerService extends IActivityManager.Stub public final void installSystemProviders() { List<ProviderInfo> providers; synchronized (this) { - ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID); + ProcessRecord app = mProcessNames.get("system", SYSTEM_UID); providers = generateApplicationProvidersLocked(app); if (providers != null) { for (int i=providers.size()-1; i>=0; i--) { @@ -12065,11 +12090,11 @@ public class ActivityManagerService extends IActivityManager.Stub int uid = info.uid; if (isolated) { if (isolatedUid == 0) { - int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1; + int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1; while (true) { - if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID - || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) { - mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID; + if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID + || mNextIsolatedProcessUid > LAST_ISOLATED_UID) { + mNextIsolatedProcessUid = FIRST_ISOLATED_UID; } uid = UserHandle.getUid(userId, mNextIsolatedProcessUid); mNextIsolatedProcessUid++; @@ -13121,9 +13146,10 @@ public class ActivityManagerService extends IActivityManager.Stub if (r == null) { return false; } - int index = r.task.mActivities.lastIndexOf(r); + final TaskRecord task = r.getTask(); + int index = task.mActivities.lastIndexOf(r); if (index > 0) { - ActivityRecord under = r.task.mActivities.get(index - 1); + ActivityRecord under = task.mActivities.get(index - 1); under.returningOptions = ActivityOptions.fromBundle(options); } final boolean translucentChanged = r.changeWindowTranslucency(false); @@ -13257,7 +13283,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { // Disable any existing VR thread. if (mTopAppVrThreadTid > 0) { - Process.setThreadScheduler(mTopAppVrThreadTid, Process.SCHED_OTHER, 0); + setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0); mTopAppVrThreadTid = 0; } @@ -13281,15 +13307,15 @@ public class ActivityManagerService extends IActivityManager.Stub */ private int updateVrThreadLocked(ProcessRecord proc, int lastTid, int pid, int tid) { // ensure the tid belongs to the process - if (!Process.isThreadInProcess(pid, tid)) { + if (!isThreadInProcess(pid, tid)) { throw new IllegalArgumentException("VR thread does not belong to process"); } // reset existing VR thread to CFS if this thread still exists and belongs to // the calling process - if (lastTid != 0 && Process.isThreadInProcess(pid, lastTid)) { + if (lastTid != 0 && isThreadInProcess(pid, lastTid)) { try { - Process.setThreadScheduler(lastTid, Process.SCHED_OTHER, 0); + setThreadScheduler(lastTid, SCHED_OTHER, 0); } catch (IllegalArgumentException e) { // Ignore this. Only occurs in race condition where previous VR thread // was destroyed during this method call. @@ -13300,8 +13326,8 @@ public class ActivityManagerService extends IActivityManager.Stub try { if ((proc == null || proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) && tid > 0) { - Process.setThreadScheduler(tid, - Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + setThreadScheduler(tid, + SCHED_FIFO | SCHED_RESET_ON_FORK, 1); } return tid; } catch (IllegalArgumentException e) { @@ -13320,7 +13346,7 @@ public class ActivityManagerService extends IActivityManager.Stub proc = mPidsSelfLocked.get(pid); if (proc != null && proc.renderThreadTid == 0 && tid > 0) { // ensure the tid belongs to the process - if (!Process.isThreadInProcess(pid, tid)) { + if (!isThreadInProcess(pid, tid)) { throw new IllegalArgumentException( "Render thread does not belong to process"); } @@ -13332,10 +13358,10 @@ public class ActivityManagerService extends IActivityManager.Stub if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) { if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band"); if (mUseFifoUiScheduling) { - Process.setThreadScheduler(proc.renderThreadTid, - Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + setThreadScheduler(proc.renderThreadTid, + SCHED_FIFO | SCHED_RESET_ON_FORK, 1); } else { - Process.setThreadPriority(proc.renderThreadTid, -10); + setThreadPriority(proc.renderThreadTid, -10); } } } else { @@ -13410,7 +13436,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (r == null) { throw new IllegalArgumentException(); } - return r.task.getTopActivity() == r; + return r.getTask().getTopActivity() == r; } } @@ -13496,7 +13522,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (sender == null) { uid = sourceUid; } else { - uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid; + uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid; } BatteryStatsImpl.Uid.Pkg pkg = stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid, @@ -13519,7 +13545,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (sender == null) { uid = sourceUid; } else { - uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid; + uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid; } mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid); } @@ -13538,14 +13564,14 @@ public class ActivityManagerService extends IActivityManager.Stub if (sender == null) { uid = sourceUid; } else { - uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid; + uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid; } mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid); } } public boolean killPids(int[] pids, String pReason, boolean secure) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { + if (Binder.getCallingUid() != SYSTEM_UID) { throw new SecurityException("killPids only available to the system"); } String reason = (pReason == null) ? "Unknown" : pReason; @@ -13611,7 +13637,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean killProcessesBelowForeground(String reason) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { + if (Binder.getCallingUid() != SYSTEM_UID) { throw new SecurityException("killProcessesBelowForeground() only available to system"); } @@ -13619,7 +13645,7 @@ public class ActivityManagerService extends IActivityManager.Stub } private boolean killProcessesBelowAdj(int belowAdj, String reason) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { + if (Binder.getCallingUid() != SYSTEM_UID) { throw new SecurityException("killProcessesBelowAdj() only available to system"); } @@ -13696,7 +13722,7 @@ public class ActivityManagerService extends IActivityManager.Stub Log.i(TAG, "Shutting down activity manager..."); shutdown(10000); Log.i(TAG, "Shutdown complete, restarting!"); - Process.killProcess(Process.myPid()); + killProcess(myPid()); System.exit(10); } }; @@ -14040,7 +14066,7 @@ public class ActivityManagerService extends IActivityManager.Stub intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - null, false, false, MY_PID, Process.SYSTEM_UID, + null, false, false, MY_PID, SYSTEM_UID, currentUserId); intent = new Intent(Intent.ACTION_USER_STARTING); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -14054,7 +14080,7 @@ public class ActivityManagerService extends IActivityManager.Stub } }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, - null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL); } catch (Throwable t) { Slog.wtf(TAG, "Failed sending first user broadcasts", t); } finally { @@ -15928,8 +15954,9 @@ public class ActivityManagerService extends IActivityManager.Stub } needSep = true; synchronized (this) { - if (lastTask != r.task) { - lastTask = r.task; + final TaskRecord task = r.getTask(); + if (lastTask != task) { + lastTask = task; pw.print("TASK "); pw.print(lastTask.affinity); pw.print(" id="); pw.print(lastTask.taskId); pw.print(" userId="); pw.println(lastTask.userId); @@ -16698,22 +16725,22 @@ public class ActivityManagerService extends IActivityManager.Stub private final long[] getKsmInfo() { long[] longOut = new long[4]; final int[] SINGLE_LONG_FORMAT = new int[] { - Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG + PROC_SPACE_TERM| PROC_OUT_LONG }; long[] longTmp = new long[1]; - Process.readProcFile("/sys/kernel/mm/ksm/pages_shared", + readProcFile("/sys/kernel/mm/ksm/pages_shared", SINGLE_LONG_FORMAT, null, longTmp, null); longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024; longTmp[0] = 0; - Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing", + readProcFile("/sys/kernel/mm/ksm/pages_sharing", SINGLE_LONG_FORMAT, null, longTmp, null); longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024; longTmp[0] = 0; - Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared", + readProcFile("/sys/kernel/mm/ksm/pages_unshared", SINGLE_LONG_FORMAT, null, longTmp, null); longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024; longTmp[0] = 0; - Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile", + readProcFile("/sys/kernel/mm/ksm/pages_volatile", SINGLE_LONG_FORMAT, null, longTmp, null); longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024; return longOut; @@ -17643,7 +17670,6 @@ public class ActivityManagerService extends IActivityManager.Stub */ private final boolean cleanUpApplicationRecordLocked(ProcessRecord app, boolean restarting, boolean allowRestart, int index, boolean replacingPid) { - Slog.d(TAG, "cleanUpApplicationRecord -- " + app.pid); if (index >= 0) { removeLruProcessLocked(app); ProcessList.remove(app.pid); @@ -17990,7 +18016,7 @@ public class ActivityManagerService extends IActivityManager.Stub String className, int flags) { boolean result = false; // For apps that don't have pre-defined UIDs, check for permission - if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) { + if (UserHandle.getAppId(aInfo.uid) >= FIRST_APPLICATION_UID) { if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) { if (ActivityManager.checkUidPermission( INTERACT_ACROSS_USERS, @@ -18009,7 +18035,7 @@ public class ActivityManagerService extends IActivityManager.Stub result = true; } else if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) { // Phone app and persistent apps are allowed to export singleuser providers. - result = UserHandle.isSameApp(aInfo.uid, Process.PHONE_UID) + result = UserHandle.isSameApp(aInfo.uid, PHONE_UID) || (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0; } if (DEBUG_MU) Slog.v(TAG_MU, @@ -18027,8 +18053,8 @@ public class ActivityManagerService extends IActivityManager.Stub boolean isValidSingletonCall(int callingUid, int componentUid) { int componentAppId = UserHandle.getAppId(componentUid); return UserHandle.isSameApp(callingUid, componentUid) - || componentAppId == Process.SYSTEM_UID - || componentAppId == Process.PHONE_UID + || componentAppId == SYSTEM_UID + || componentAppId == PHONE_UID || ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, componentUid) == PackageManager.PERMISSION_GRANTED; } @@ -18269,7 +18295,7 @@ public class ActivityManagerService extends IActivityManager.Stub // ========================================================= private boolean isInstantApp(ProcessRecord record, String callerPackage, int uid) { - if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) { + if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) { return false; } // Easy case -- we have the app's ProcessRecord. @@ -18330,7 +18356,7 @@ public class ActivityManagerService extends IActivityManager.Stub + " (pid=" + Binder.getCallingPid() + ") when registering receiver " + receiver); } - if (callerApp.info.uid != Process.SYSTEM_UID && + if (callerApp.info.uid != SYSTEM_UID && !callerApp.pkgList.containsKey(callerPackage) && !"android".equals(callerPackage)) { throw new SecurityException("Given caller package " + callerPackage @@ -18547,7 +18573,7 @@ public class ActivityManagerService extends IActivityManager.Stub for (int user : users) { // Skip users that have Shell restrictions, with exception of always permitted // Shell broadcasts - if (callingUid == Process.SHELL_UID + if (callingUid == SHELL_UID && mUserController.hasUserRestriction( UserManager.DISALLOW_DEBUGGING_FEATURES, user) && !isPermittedShellBroadcast(intent)) { @@ -18731,7 +18757,7 @@ public class ActivityManagerService extends IActivityManager.Stub // and upgrade steps. if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) { - if ((callingUid != Process.SYSTEM_UID + if ((callingUid != SYSTEM_UID || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { Slog.w(TAG, "Skipping broadcast of " + intent @@ -18775,11 +18801,11 @@ public class ActivityManagerService extends IActivityManager.Stub final boolean isCallerSystem; switch (UserHandle.getAppId(callingUid)) { - case Process.ROOT_UID: - case Process.SYSTEM_UID: - case Process.PHONE_UID: - case Process.BLUETOOTH_UID: - case Process.NFC_UID: + case ROOT_UID: + case SYSTEM_UID: + case PHONE_UID: + case BLUETOOTH_UID: + case NFC_UID: isCallerSystem = true; break; default: @@ -19155,7 +19181,7 @@ public class ActivityManagerService extends IActivityManager.Stub receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } if (intent.getComponent() == null) { - if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) { + if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { // Query one target user at a time, excluding shell-restricted users for (int i = 0; i < users.length; i++) { if (mUserController.hasUserRestriction( @@ -19397,8 +19423,8 @@ public class ActivityManagerService extends IActivityManager.Stub if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) { switch (Binder.getCallingUid()) { - case Process.ROOT_UID: - case Process.SHELL_UID: + case ROOT_UID: + case SHELL_UID: break; default: Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID " @@ -19853,7 +19879,7 @@ public class ActivityManagerService extends IActivityManager.Stub private void enforceWriteSettingsPermission(String func) { int uid = Binder.getCallingUid(); - if (uid == Process.ROOT_UID) { + if (uid == ROOT_UID) { return; } @@ -20051,7 +20077,7 @@ public class ActivityManagerService extends IActivityManager.Stub | Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, - AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, + AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL); if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) { intent = new Intent(Intent.ACTION_LOCALE_CHANGED); @@ -20062,7 +20088,7 @@ public class ActivityManagerService extends IActivityManager.Stub intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, - AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, + AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL); } @@ -20562,8 +20588,9 @@ public class ActivityManagerService extends IActivityManager.Stub app.cached = false; app.empty = false; foregroundActivities = true; - if (r.task != null && minLayer > 0) { - final int layer = r.task.mLayerRank; + final TaskRecord task = r.getTask(); + if (task != null && minLayer > 0) { + final int layer = task.mLayerRank; if (layer >= 0 && minLayer > layer) { minLayer = layer; } @@ -21535,27 +21562,27 @@ public class ActivityManagerService extends IActivityManager.Stub int processGroup; switch (app.curSchedGroup) { case ProcessList.SCHED_GROUP_BACKGROUND: - processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; + processGroup = THREAD_GROUP_BG_NONINTERACTIVE; break; case ProcessList.SCHED_GROUP_TOP_APP: case ProcessList.SCHED_GROUP_TOP_APP_BOUND: - processGroup = Process.THREAD_GROUP_TOP_APP; + processGroup = THREAD_GROUP_TOP_APP; break; default: - processGroup = Process.THREAD_GROUP_DEFAULT; + processGroup = THREAD_GROUP_DEFAULT; break; } long oldId = Binder.clearCallingIdentity(); try { - Process.setProcessGroup(app.pid, processGroup); + setProcessGroup(app.pid, processGroup); if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) { // do nothing if we already switched to RT if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) { // Switch VR thread for app to SCHED_FIFO if (mVrState == VR_MODE && app.vrThreadTid != 0) { try { - Process.setThreadScheduler(app.vrThreadTid, - Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + setThreadScheduler(app.vrThreadTid, + SCHED_FIFO | SCHED_RESET_ON_FORK, 1); mTopAppVrThreadTid = app.vrThreadTid; } catch (IllegalArgumentException e) { // thread died, ignore @@ -21563,17 +21590,17 @@ public class ActivityManagerService extends IActivityManager.Stub } if (mUseFifoUiScheduling) { // Switch UI pipeline for app to SCHED_FIFO - app.savedPriority = Process.getThreadPriority(app.pid); + app.savedPriority = getThreadPriority(app.pid); try { - Process.setThreadScheduler(app.pid, - Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + setThreadScheduler(app.pid, + SCHED_FIFO | SCHED_RESET_ON_FORK, 1); } catch (IllegalArgumentException e) { // thread died, ignore } if (app.renderThreadTid != 0) { try { - Process.setThreadScheduler(app.renderThreadTid, - Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + setThreadScheduler(app.renderThreadTid, + SCHED_FIFO | SCHED_RESET_ON_FORK, 1); } catch (IllegalArgumentException e) { // thread died, ignore } @@ -21588,10 +21615,10 @@ public class ActivityManagerService extends IActivityManager.Stub } } else { // Boost priority for top app UI and render threads - Process.setThreadPriority(app.pid, -10); + setThreadPriority(app.pid, -10); if (app.renderThreadTid != 0) { try { - Process.setThreadPriority(app.renderThreadTid, -10); + setThreadPriority(app.renderThreadTid, -10); } catch (IllegalArgumentException e) { // thread died, ignore } @@ -21603,23 +21630,23 @@ public class ActivityManagerService extends IActivityManager.Stub // Reset VR thread to SCHED_OTHER // Safe to do even if we're not in VR mode if (app.vrThreadTid != 0) { - Process.setThreadScheduler(app.vrThreadTid, Process.SCHED_OTHER, 0); + setThreadScheduler(app.vrThreadTid, SCHED_OTHER, 0); mTopAppVrThreadTid = 0; } if (mUseFifoUiScheduling) { // Reset UI pipeline to SCHED_OTHER - Process.setThreadScheduler(app.pid, Process.SCHED_OTHER, 0); - Process.setThreadPriority(app.pid, app.savedPriority); + setThreadScheduler(app.pid, SCHED_OTHER, 0); + setThreadPriority(app.pid, app.savedPriority); if (app.renderThreadTid != 0) { - Process.setThreadScheduler(app.renderThreadTid, - Process.SCHED_OTHER, 0); - Process.setThreadPriority(app.renderThreadTid, -4); + setThreadScheduler(app.renderThreadTid, + SCHED_OTHER, 0); + setThreadPriority(app.renderThreadTid, -4); } } else { // Reset priority for top app UI and render threads - Process.setThreadPriority(app.pid, 0); + setThreadPriority(app.pid, 0); if (app.renderThreadTid != 0) { - Process.setThreadPriority(app.renderThreadTid, 0); + setThreadPriority(app.renderThreadTid, 0); } } } @@ -22729,7 +22756,7 @@ public class ActivityManagerService extends IActivityManager.Stub /** This method sends the specified signal to each of the persistent apps */ public void signalPersistentProcesses(int sig) throws RemoteException { - if (sig != Process.SIGNAL_USR1) { + if (sig != SIGNAL_USR1) { throw new SecurityException("Only SIGNAL_USR1 is allowed"); } @@ -22743,7 +22770,7 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { ProcessRecord r = mLruProcesses.get(i); if (r.thread != null && r.persistent) { - Process.sendSignal(r.pid, sig); + sendSignal(r.pid, sig); } } } @@ -23884,7 +23911,7 @@ public class ActivityManagerService extends IActivityManager.Stub final boolean updateFrameworkRes = packagesToUpdate.contains("android"); for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord app = mLruProcesses.get(i); - if (app.thread == null || app.pid == Process.myPid()) { + if (app.thread == null) { continue; } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index cbb51e1566c4..3a2941467cb6 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -229,7 +229,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo private int theme; // resource identifier of activity's theme. private int realTheme; // actual theme resource we will use, never 0. private int windowFlags; // custom window flags for preview window. - TaskRecord task; // the task this is in. + private TaskRecord task; // the task this is in. private long createTime = System.currentTimeMillis(); long displayStartTime; // when we started launching this activity long fullyDrawnStartTime; // when we started launching this activity @@ -686,9 +686,48 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo @Override protected ConfigurationContainer getParent() { + return getTask(); + } + + TaskRecord getTask() { return task; } + /** + * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent. + * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord} + * children. However, this method will clean up references to this {@link ActivityRecord} in + * {@link ActivityStack}. + * @param task The new parent {@link TaskRecord}. + */ + void setTask(TaskRecord task) { + setTask(task, false /*reparenting*/); + } + + /** + * This method should only be called by {@link TaskRecord#removeActivity(ActivityRecord)}. + */ + void setTask(TaskRecord task, boolean reparenting) { + // Do nothing if the {@link TaskRecord} is the same as the current {@link getTask}. + if (task != null && task == getTask()) { + return; + } + + final ActivityStack stack = getStack(); + + // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this + // {@link ActivityRecord} from its current {@link ActivityStack}. + if (!reparenting && stack != null && (task == null || stack != task.getStack())) { + stack.onActivityRemovedFromStack(this); + } + + this.task = task; + + if (!reparenting) { + onParentChanged(); + } + } + static class Token extends IApplicationToken.Stub { private final WeakReference<ActivityRecord> weakActivity; @@ -925,8 +964,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // Must reparent first in window manager mWindowContainerController.reparent(newTask.getWindowContainerController(), position); - // Remove the activity from the old task and add it to the new task - prevTask.removeActivity(this); + // Remove the activity from the old task and add it to the new task. + prevTask.removeActivity(this, true /*reparenting*/); newTask.addActivityAtIndex(position, this); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index ee37463d0980..f13b11e65a88 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -116,6 +116,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.Display; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.os.BatteryStatsImpl; import com.android.server.Watchdog; @@ -725,7 +726,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (r == null) { return null; } - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); final ActivityStack stack = r.getStack(); if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) { if (stack != this) Slog.w(TAG, @@ -934,7 +935,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls=" + taskIntent.getComponent().flattenToShortString() - + "/aff=" + r.task.rootAffinity + " to new cls=" + + "/aff=" + r.getTask().rootAffinity + " to new cls=" + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity); // TODO Refactor to remove duplications. Check if logic can be simplified. if (taskIntent != null && taskIntent.getComponent() != null && @@ -1049,8 +1050,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai void addRecentActivityLocked(ActivityRecord r) { if (r != null) { - mRecentTasks.addLocked(r.task); - r.task.touchActiveTime(); + final TaskRecord task = r.getTask(); + mRecentTasks.addLocked(task); + task.touchActiveTime(); } } @@ -1226,11 +1228,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0 || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null; prev.state = ActivityState.PAUSING; - prev.task.touchActiveTime(); + prev.getTask().touchActiveTime(); clearLaunchTime(prev); final ActivityRecord next = mStackSupervisor.topRunningActivityLocked(); if (mService.mHasRecents - && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) { + && (next == null || next.noDisplay || next.getTask() != prev.getTask() + || uiSleeping)) { prev.mUpdateTaskThumbnailWhenHidden = true; } stopFullyDrawnTraceIfNeeded(); @@ -1457,7 +1460,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Find the first visible activity above the passed activity and if it is translucent return it // otherwise return null; ActivityRecord findNextTranslucentActivity(ActivityRecord r) { - TaskRecord task = r.task; + TaskRecord task = r.getTask(); if (task == null) { return null; } @@ -1604,7 +1607,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Otherwise, the docked stack is always visible, except in the case where the top // running activity task in the focus stack doesn't support any form of resizing but we // show it for the home task even though it's not resizable. - final TaskRecord task = r != null ? r.task : null; + final TaskRecord task = r != null ? r.getTask() : null; return task == null || task.supportsSplitScreen() || task.isHomeTask() ? STACK_VISIBLE : STACK_INVISIBLE; } @@ -2157,8 +2160,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mResumedActivity = r; r.state = ActivityState.RESUMED; mService.setResumedActivityUncheckLocked(r, reason); - r.task.touchActiveTime(); - mRecentTasks.addLocked(r.task); + final TaskRecord task = r.getTask(); + task.touchActiveTime(); + mRecentTasks.addLocked(task); } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { @@ -2207,8 +2211,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - final TaskRecord nextTask = next.task; - final TaskRecord prevTask = prev != null ? prev.task : null; + final TaskRecord nextTask = next.getTask(); + final TaskRecord prevTask = prev != null ? prev.getTask() : null; if (prevTask != null && prevTask.getStack() == this && prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) { if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); @@ -2373,7 +2377,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai anim = false; mWindowManager.prepareAppTransition(TRANSIT_NONE, false); } else { - mWindowManager.prepareAppTransition(prev.task == next.task + mWindowManager.prepareAppTransition(prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_CLOSE : TRANSIT_TASK_CLOSE, false); } @@ -2385,7 +2389,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai anim = false; mWindowManager.prepareAppTransition(TRANSIT_NONE, false); } else { - mWindowManager.prepareAppTransition(prev.task == next.task + mWindowManager.prepareAppTransition(prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_OPEN : next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND @@ -2522,7 +2526,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai next.notifyAppResumed(next.stopped, allowSavedSurface); EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, - System.identityHashCode(next), next.task.taskId, next.shortComponentName); + System.identityHashCode(next), next.getTask().taskId, + next.shortComponentName); next.sleeping = false; mService.showUnsupportedZoomDialogIfNeededLocked(next); @@ -2696,9 +2701,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return; } - // If the task was launched from the assistant stack, set the return type to assistant final ActivityStack lastStack = mStackSupervisor.getLastStack(); - if (lastStack != null && lastStack.isAssistantStack()) { + + // If there is no last task, do not set task to return to + if (lastStack == null) { + return; + } + + // If the task was launched from the assistant stack, set the return type to assistant + if (lastStack.isAssistantStack()) { task.setTaskToReturnTo(ASSISTANT_ACTIVITY_TYPE); return; } @@ -2721,7 +2732,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, boolean newTask, boolean keepCurTransition, ActivityOptions options) { - TaskRecord rTask = r.task; + TaskRecord rTask = r.getTask(); final int taskId = rTask.taskId; // mLaunchTaskBehind tasks get placed at the back of the task stack. if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) { @@ -2740,7 +2751,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // All activities in task are finishing. continue; } - if (task == r.task) { + if (task == rTask) { // Here it is! Now, if this is not yet visible to the // user, then just add it without starting; it will // get started when the user navigates back to it. @@ -2762,13 +2773,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // If we are not placing the new activity frontmost, we do not want to deliver the // onUserLeaving callback to the actual frontmost activity - if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) { + final TaskRecord activityTask = r.getTask(); + if (task == activityTask && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) { mStackSupervisor.mUserLeaving = false; if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, "startActivity() behind front, mUserLeaving=false"); } - task = r.task; + task = activityTask; // Slot the activity into the history stack and proceed if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task, @@ -2795,7 +2807,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } else { // If a new task is being launched, then mark the existing top activity as // supporting picture-in-picture while pausing - if (focusedTopActivity != null) { + if (focusedTopActivity != null && + focusedTopActivity.getStack().getStackId() != PINNED_STACK_ID) { focusedTopActivity.supportsPictureInPictureWhilePausing = true; } transit = TRANSIT_TASK_OPEN; @@ -2829,11 +2842,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // "has the same starting icon" as the next one. This allows the // window manager to keep the previous window it had previously // created, if it still had one. - ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked(); + TaskRecord prevTask = r.getTask(); + ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked(); if (prev != null) { // We don't want to reuse the previous starting preview if: // (1) The current activity is in a different task. - if (prev.task != r.task) { + if (prev.getTask() != prevTask) { prev = null; } // (2) The current activity is already displayed. @@ -2852,7 +2866,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) { - return topFocusedActivity != null && r.task != topFocusedActivity.task; + return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask(); } /** @@ -2919,20 +2933,20 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ? mTaskHistory.get(0).mActivities.get(0) : null; if (bottom != null && target.taskAffinity != null - && target.taskAffinity.equals(bottom.task.affinity)) { + && target.taskAffinity.equals(bottom.getTask().affinity)) { // If the activity currently at the bottom has the // same task affinity as the one we are moving, // then merge it into the same task. - targetTask = bottom.task; + targetTask = bottom.getTask(); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target - + " out to bottom task " + bottom.task); + + " out to bottom task " + targetTask); } else { targetTask = createTaskRecord( mStackSupervisor.getNextTaskIdForUserLocked(target.userId), target.info, null, null, null, false, target.mActivityType); targetTask.affinityIntent = target.intent; if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target - + " out to new task " + target.task); + + " out to new task " + targetTask); } boolean noOptions = canMoveOptions; @@ -2954,7 +2968,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai "Removing activity " + p + " from task=" + task + " adding to task=" + targetTask + " Callers=" + Debug.getCallers(4)); if (DEBUG_TASKS) Slog.v(TAG_TASKS, - "Pushing next activity " + p + " out to target's task " + target.task); + "Pushing next activity " + p + " out to target's task " + target); p.reparent(targetTask, 0 /* position - bottom */, "resetTargetTaskIfNeeded"); } @@ -3125,13 +3139,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai boolean forceReset = (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; if (ACTIVITY_INACTIVE_RESET_TIME > 0 - && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) { + && taskTop.getTask().getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) { if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) { forceReset = true; } } - final TaskRecord task = taskTop.task; + final TaskRecord task = taskTop.getTask(); /** False until we evaluate the TaskRecord associated with taskTop. Switches to true * for remaining tasks. Used for later tasks to reparent to task. */ @@ -3214,7 +3228,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // stack as long as there is a running activity. return; } else { - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); final boolean isAssistantOrOverAssistant = task.getStack().isAssistantStack() || task.isOverAssistantStack(); if (r.frontOfTask && task == topTask() && @@ -3373,10 +3387,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } Slog.w(TAG, " Force finishing activity " + r.intent.getComponent().flattenToShortString()); - int taskNdx = mTaskHistory.indexOf(r.task); - int activityNdx = r.task.mActivities.indexOf(r); + finishedTask = r.getTask(); + int taskNdx = mTaskHistory.indexOf(finishedTask); + final TaskRecord task = finishedTask; + int activityNdx = task.mActivities.indexOf(r); finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false); - finishedTask = r.task; + finishedTask = task; // Also terminate any activities below it that aren't yet // stopped, to avoid a situation where one will get // re-start our crashing activity once it gets resumed again. @@ -3446,7 +3462,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } final boolean finishActivityAffinityLocked(ActivityRecord r) { - ArrayList<ActivityRecord> activities = r.task.mActivities; + ArrayList<ActivityRecord> activities = r.getTask().mActivities; for (int index = activities.indexOf(r); index >= 0; --index) { ActivityRecord cur = activities.get(index); if (!Objects.equals(cur.taskAffinity, r.taskAffinity)) { @@ -3511,7 +3527,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mWindowManager.deferSurfaceLayout(); try { r.makeFinishingLocked(); - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, r.userId, System.identityHashCode(r), task.taskId, r.shortComponentName, reason); @@ -3700,23 +3716,24 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) { // Basic case: for simple app-centric recents, we need to recreate // the task if the affinity has changed. - if (srec == null || srec.task.affinity == null || - !srec.task.affinity.equals(destAffinity)) { + if (srec == null || srec.getTask().affinity == null || + !srec.getTask().affinity.equals(destAffinity)) { return true; } // Document-centric case: an app may be split in to multiple documents; // they need to re-create their task if this current activity is the root // of a document, unless simply finishing it will return them to the the // correct app behind. - if (srec.frontOfTask && srec.task != null && srec.task.getBaseIntent() != null - && srec.task.getBaseIntent().isDocument()) { + final TaskRecord task = srec.getTask(); + if (srec.frontOfTask && task != null && task.getBaseIntent() != null + && task.getBaseIntent().isDocument()) { // Okay, this activity is at the root of its task. What to do, what to do... - if (srec.task.getTaskToReturnTo() != ActivityRecord.APPLICATION_ACTIVITY_TYPE) { + if (task.getTaskToReturnTo() != ActivityRecord.APPLICATION_ACTIVITY_TYPE) { // Finishing won't return to an application, so we need to recreate. return true; } // We now need to get the task below it to determine what to do. - int taskIdx = mTaskHistory.indexOf(srec.task); + int taskIdx = mTaskHistory.indexOf(task); if (taskIdx <= 0) { Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec); return false; @@ -3726,7 +3743,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return true; } TaskRecord prevTask = mTaskHistory.get(taskIdx); - if (!srec.task.affinity.equals(prevTask.affinity)) { + if (!task.affinity.equals(prevTask.affinity)) { // These are different apps, so need to recreate. return true; } @@ -3736,7 +3753,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { - final TaskRecord task = srec.task; + final TaskRecord task = srec.getTask(); final ArrayList<ActivityRecord> activities = task.mActivities; final int start = activities.indexOf(srec); if (!mTaskHistory.contains(task) || (start < 0)) { @@ -3815,6 +3832,22 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai Binder.restoreCallingIdentity(origId); return foundParentInTask; } + + /** + * Remove any state associated with the {@link ActivityRecord}. This should be called whenever + * an activity moves away from the stack. + */ + void onActivityRemovedFromStack(ActivityRecord r) { + if (mResumedActivity == r) { + mResumedActivity = null; + } + if (mPausingActivity == r) { + mPausingActivity = null; + } + + removeTimeoutsForActivityLocked(r); + } + /** * Perform the common clean-up of an activity record. This is called both * as part of destroyActivityLocked() (when destroying the client-side @@ -3825,12 +3858,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * Note: Call before #removeActivityFromHistoryLocked. */ private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) { - if (mResumedActivity == r) { - mResumedActivity = null; - } - if (mPausingActivity == r) { - mPausingActivity = null; - } + onActivityRemovedFromStack(r); r.deferRelaunchUntilPaused = false; r.frozenBeforeDestroy = false; @@ -3897,7 +3925,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r); r.app = null; r.removeWindowContainer(); - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); final boolean lastActivity = task != null ? task.removeActivity(r) : false; // If we are removing the last activity in the task, not including task overlay activities, // then fall through into the block below to remove the entire task itself @@ -4043,7 +4071,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai + ", app=" + (r.app != null ? r.app.processName : "(null)")); EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, r.userId, System.identityHashCode(r), - r.task.taskId, r.shortComponentName, reason); + r.getTask().taskId, r.shortComponentName, reason); boolean removedFromHistory = false; @@ -4275,7 +4303,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai Slog.w(TAG, "Force removing " + r + ": app died, no saved state"); EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, r.userId, System.identityHashCode(r), - r.task.taskId, r.shortComponentName, + r.getTask().taskId, r.shortComponentName, "proc died without state saved"); if (r.state == ActivityState.RESUMED) { mService.updateUsageStats(r, false); @@ -4403,7 +4431,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } // If a new task is moved to the front, then mark the existing top activity as supporting // picture-in-picture while paused - if (topActivity != null) { + if (topActivity != null && topActivity.getStack().getStackId() != PINNED_STACK_ID) { topActivity.supportsPictureInPictureWhilePausing = true; } @@ -4529,7 +4557,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } - final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null; + final TaskRecord task = mResumedActivity != null ? mResumedActivity.getTask() : null; if (prevIsHome || (task == tr && canGoHome) || (numTasks <= 1 && isOnHomeDisplay())) { if (!mService.mBooting && !mService.mBooted) { // Not ready yet! @@ -4570,7 +4598,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return; } - final TaskRecord startTask = start.task; + final TaskRecord startTask = start.getTask(); boolean behindFullscreen = false; boolean updatedConfig = false; @@ -4578,7 +4606,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final TaskRecord task = mTaskHistory.get(taskIndex); final ArrayList<ActivityRecord> activities = task.mActivities; int activityIndex = - (start.task == task) ? activities.indexOf(start) : activities.size() - 1; + (start.getTask() == task) ? activities.indexOf(start) : activities.size() - 1; for (; activityIndex >= 0; --activityIndex) { final ActivityRecord r = activities.get(activityIndex); updatedConfig |= r.ensureActivityConfigurationLocked(0 /* globalChanges */, @@ -4739,7 +4767,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai || filterByClasses.contains(r.realActivity.getClassName()))) || (packageName == null && r.userId == userId); if ((userId == UserHandle.USER_ALL || r.userId == userId) - && (sameComponent || r.task == lastTask) + && (sameComponent || r.getTask() == lastTask) && (r.app == null || evenPersistent || !r.app.persistent)) { if (!doit) { if (r.finishing) { @@ -4765,7 +4793,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } r.app = null; } - lastTask = r.task; + lastTask = r.getTask(); if (finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop", true)) { // r has been deleted from mActivities, accommodate. @@ -4816,7 +4844,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_ALL) Slog.v( TAG, r.intent.getComponent().flattenToShortString() - + ": task=" + r.task); + + ": task=" + r.getTask()); } RunningTaskInfo ci = new RunningTaskInfo(); @@ -4832,8 +4860,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai topTask = false; } - if (top.task != null) { - ci.description = top.task.lastDescription; + if (top.getTask() != null) { + ci.description = top.getTask().lastDescription; } ci.numActivities = numActivities; ci.numRunning = numRunning; @@ -4982,9 +5010,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai task.removeWindowContainer(); } - final ActivityRecord r = mResumedActivity; - if (r != null && r.task == task) { - mResumedActivity = null; + for (ActivityRecord record : task.mActivities) { + onActivityRemovedFromStack(record); } final int taskNdx = mTaskHistory.indexOf(task); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index f16849ddc672..b72cd73e85cf 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -164,6 +164,7 @@ import android.view.Display; import android.view.InputEvent; import android.view.Surface; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.ReferrerIntent; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -173,6 +174,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.wm.StackWindowController; import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; @@ -553,9 +555,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - public ActivityStackSupervisor(ActivityManagerService service) { + public ActivityStackSupervisor(ActivityManagerService service, Looper looper) { mService = service; - mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper()); + mHandler = new ActivityStackSupervisorHandler(looper); mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext); mKeyguardController = new KeyguardController(service, this); } @@ -722,7 +724,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } if (prev != null) { - prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE); + prev.getTask().setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE); } mHomeStack.moveHomeStackTaskToTop(); @@ -1314,7 +1316,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mService.updateLruProcessLocked(app, true, null); mService.updateOomAdjLocked(); - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE || task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) { setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false); @@ -2622,7 +2624,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } for (int k = 0; k < proc.activities.size(); k++) { - TaskRecord otherTask = proc.activities.get(k).task; + TaskRecord otherTask = proc.activities.get(k).getTask(); if (tr.taskId != otherTask.taskId && otherTask.inRecents) { // Don't kill process(es) that has an activity in a different task that is // also in recents. @@ -2837,7 +2839,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP); try { - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); if (r == task.getStack().getVisibleBehindActivity()) { // An activity can't be pinned and visible behind at the same time. Go ahead and @@ -2910,7 +2912,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); final ActivityStack stack = r.getStack(); if (stack == null) { Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r=" @@ -3203,7 +3205,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Called when WindowManager has finished animating the launchingBehind activity to the back. private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) { - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); final ActivityStack stack = task.getStack(); r.mLaunchTaskBehind = false; @@ -3216,7 +3218,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // task has been shown briefly final ActivityRecord top = stack.topActivity(); if (top != null) { - top.task.touchActiveTime(); + top.getTask().touchActiveTime(); } } @@ -3315,17 +3317,19 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r); continue; } - if (r.task != null) { - if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + r.task + + final TaskRecord task = r.getTask(); + if (task != null) { + if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task + " from " + r); if (firstTask == null) { - firstTask = r.task; - } else if (firstTask != r.task) { + firstTask = task; + } else if (firstTask != task) { if (tasks == null) { tasks = new ArraySet<>(); tasks.add(firstTask); } - tasks.add(r.task); + tasks.add(task); } } } @@ -3664,8 +3668,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D pw.println(header2); header2 = null; } - if (lastTask != r.task) { - lastTask = r.task; + if (lastTask != r.getTask()) { + lastTask = r.getTask(); pw.print(prefix); pw.print(full ? "* " : " "); pw.println(lastTask); @@ -4080,7 +4084,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } final ActivityRecord r = topRunningActivityLocked(); - final TaskRecord task = r != null ? r.task : null; + final TaskRecord task = r != null ? r.getTask() : null; if (mLockTaskModeTasks.isEmpty() && task != null && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) { // This task must have just been authorized. @@ -4390,19 +4394,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D synchronized (mService) { mStackId = stackId; mActivityDisplay = activityDisplay; - switch (mStackId) { - case PINNED_STACK_ID: - new PinnedActivityStack(this, mRecentTasks, onTop); - break; - default: - new ActivityStack(this, mRecentTasks, onTop); - break; - } mIdString = "ActivtyContainer{" + mStackId + "}"; + + createStack(stackId, onTop); if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this); } } + protected void createStack(int stackId, boolean onTop) { + switch (stackId) { + case PINNED_STACK_ID: + new PinnedActivityStack(this, mRecentTasks, onTop); + break; + default: + new ActivityStack(this, mRecentTasks, onTop); + break; + } + } + /** * Adds the stack to specified display. Also calls WindowManager to do the same from * {@link ActivityStack#reparent(ActivityDisplay, boolean)}. @@ -4926,7 +4935,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(), ActivityManager.START_TASK_TO_FRONT, - sourceRecord != null ? sourceRecord.task.getStackId() : INVALID_STACK_ID, + sourceRecord != null ? sourceRecord.getTask().getStackId() : INVALID_STACK_ID, sourceRecord, task.getStack()); return ActivityManager.START_TASK_TO_FRONT; } diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java index 547161ac4169..cafc4f0ecc96 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java @@ -188,10 +188,10 @@ class ActivityStartInterceptor { } ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity(); - if (homeActivityRecord != null && homeActivityRecord.task != null) { + 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. - mActivityOptions.setLaunchTaskId(homeActivityRecord.task.taskId); + mActivityOptions.setLaunchTaskId(homeActivityRecord.getTask().taskId); } final UserInfo parent = mUserManager.getProfileParent(mUserId); diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 18e74080490d..b4085697f2da 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -79,7 +79,6 @@ import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStack.STACK_INVISIBLE; import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; -import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS; @@ -87,8 +86,6 @@ import static com.android.server.am.EventLogTags.AM_NEW_INTENT; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; -import static java.lang.Integer.MAX_VALUE; - import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -335,7 +332,7 @@ class ActivityStarter { } if (err == ActivityManager.START_SUCCESS && sourceRecord != null - && sourceRecord.task.voiceSession != null) { + && sourceRecord.getTask().voiceSession != null) { // If this activity is being launched as part of a voice session, we need // to ensure that it is safe to do so. If the upcoming activity will also // be part of the voice session, we can only launch it if it has explicitly @@ -575,7 +572,7 @@ class ActivityStarter { // visibility instead of using this flag. final boolean noDisplayActivityOverHome = sourceRecord != null && sourceRecord.noDisplay - && sourceRecord.task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE; + && sourceRecord.getTask().getTaskToReturnTo() == HOME_ACTIVITY_TYPE; if (startedActivityStackId == DOCKED_STACK_ID && (prevFocusedStackId == HOME_STACK_ID || noDisplayActivityOverHome)) { final ActivityStack homeStack = mSupervisor.getStack(HOME_STACK_ID); @@ -625,7 +622,7 @@ class ActivityStarter { FLAG_ACTIVITY_TASK_ON_HOME); ActivityOptions options = (optionsBundle != null ? new ActivityOptions(optionsBundle) : ActivityOptions.makeBasic()); - options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId); + options.setLaunchTaskId(mSupervisor.getHomeActivity().getTask().taskId); mService.mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT); } @@ -763,7 +760,7 @@ class ActivityStarter { newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName); newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, - hist.task.taskId); + hist.getTask().taskId); } newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP, aInfo.packageName); @@ -967,8 +964,8 @@ class ActivityStarter { // If we are not able to proceed, disassociate the activity from the task. Leaving an // activity in an incomplete state can lead to issues, such as performing operations // without a window container. - if (result != START_SUCCESS && mStartActivity.task != null) { - mStartActivity.task.removeActivity(mStartActivity); + if (result != START_SUCCESS && mStartActivity.getTask() != null) { + mStartActivity.getTask().removeActivity(mStartActivity); } mService.mWindowManager.continueSurfaceLayout(); } @@ -1002,7 +999,7 @@ class ActivityStarter { // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but // still needs to be a lock task mode violation since the task gets cleared out and // the device would otherwise leave the locked task. - if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task, + if (mSupervisor.isLockTaskModeViolation(mReusedActivity.getTask(), (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) { mSupervisor.showLockTaskToast(); @@ -1010,13 +1007,13 @@ class ActivityStarter { return START_RETURN_LOCK_TASK_MODE_VIOLATION; } - if (mStartActivity.task == null) { - mStartActivity.task = mReusedActivity.task; + if (mStartActivity.getTask() == null) { + mStartActivity.setTask(mReusedActivity.getTask()); } - if (mReusedActivity.task.intent == null) { + if (mReusedActivity.getTask().intent == null) { // This task was started because of movement of the activity based on affinity... // Now that we are actually launching it, we can assign the base intent. - mReusedActivity.task.setIntent(mStartActivity); + mReusedActivity.getTask().setIntent(mStartActivity); } // This code path leads to delivering a new intent, we want to make sure we schedule it @@ -1025,7 +1022,7 @@ class ActivityStarter { if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 || isDocumentLaunchesIntoExisting(mLaunchFlags) || mLaunchSingleInstance || mLaunchSingleTask) { - final TaskRecord task = mReusedActivity.task; + final TaskRecord task = mReusedActivity.getTask(); // In this situation we want to remove all activities from the task up to the one // being started. In most cases this means we are resetting the task to its initial @@ -1037,17 +1034,17 @@ class ActivityStarter { // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The // task reference is needed in the call below to // {@link setTargetStackAndMoveToFrontIfNeeded}. - if (mReusedActivity.task == null) { - mReusedActivity.task = task; + if (mReusedActivity.getTask() == null) { + mReusedActivity.setTask(task); } if (top != null) { if (top.frontOfTask) { // Activity aliases may mean we use different intents for the top activity, // so make sure the task now has the identity of the new intent. - top.task.setIntent(mStartActivity); + top.getTask().setIntent(mStartActivity); } - ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task); + ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask()); top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); } @@ -1098,7 +1095,7 @@ class ActivityStarter { && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop || mLaunchSingleTask); if (dontStart) { - ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task); + ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask()); // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; if (mDoResume) { @@ -1116,14 +1113,14 @@ class ActivityStarter { // Don't use mStartActivity.task to show the toast. We're not starting a new activity // but reusing 'top'. Fields in mStartActivity may not be fully initialized. mSupervisor.handleNonResizableTaskIfNeeded( - top.task, preferredLaunchStackId, topStack.mStackId); + top.getTask(), preferredLaunchStackId, topStack.mStackId); return START_DELIVERED_TO_TOP; } boolean newTask = false; final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null) - ? mSourceRecord.task : null; + ? mSourceRecord.getTask() : null; // Should this be considered a new task? int result = START_SUCCESS; @@ -1150,14 +1147,15 @@ class ActivityStarter { mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent, mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid)); if (mSourceRecord != null) { - mStartActivity.task.setTaskToReturnTo(mSourceRecord); + mStartActivity.getTask().setTaskToReturnTo(mSourceRecord); } if (newTask) { EventLog.writeEvent( - EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId); + EventLogTags.AM_CREATE_TASK, mStartActivity.userId, + mStartActivity.getTask().taskId); } ActivityStack.logStartActivity( - EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task); + EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask()); mTargetStack.mLastPausedActivity = null; sendPowerHintForLaunchStartIfNeeded(false /* forceSend */); @@ -1165,7 +1163,8 @@ class ActivityStarter { mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition, mOptions); if (mDoResume) { - final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked(); + final ActivityRecord topTaskActivity = + mStartActivity.getTask().topRunningActivityLocked(); if (!mTargetStack.isFocusable() || (topTaskActivity != null && topTaskActivity.mTaskOverlay && mStartActivity != topTaskActivity)) { @@ -1197,7 +1196,7 @@ class ActivityStarter { mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack); mSupervisor.handleNonResizableTaskIfNeeded( - mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId); + mStartActivity.getTask(), preferredLaunchStackId, mTargetStack.mStackId); return START_SUCCESS; } @@ -1424,7 +1423,7 @@ class ActivityStarter { + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent); mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; mNewTaskInfo = mSourceRecord.info; - mNewTaskIntent = mSourceRecord.task.intent; + mNewTaskIntent = mSourceRecord.getTask().intent; } mSourceRecord = null; mSourceStack = null; @@ -1516,15 +1515,16 @@ class ActivityStarter { ActivityRecord curTop = (focusStack == null) ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop); - if (curTop != null - && (curTop.task != intentActivity.task || curTop.task != focusStack.topTask()) + final TaskRecord topTask = curTop != null ? curTop.getTask() : null; + if (topTask != null + && (topTask != intentActivity.getTask() || topTask != focusStack.topTask()) && !mAvoidMoveToFront) { mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); if (mSourceRecord == null || (mSourceStack.topActivity() != null && - mSourceStack.topActivity().task == mSourceRecord.task)) { + mSourceStack.topActivity().getTask() == mSourceRecord.getTask())) { // We really do want to push this one into the user's face, right now. if (mLaunchTaskBehind && mSourceRecord != null) { - intentActivity.setTaskToAffiliateWith(mSourceRecord.task); + intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask()); } mMovedOtherTask = true; @@ -1539,13 +1539,13 @@ class ActivityStarter { == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); if (!willClearTask) { final ActivityStack launchStack = getLaunchStack( - mStartActivity, mLaunchFlags, mStartActivity.task, mOptions); + mStartActivity, mLaunchFlags, mStartActivity.getTask(), mOptions); + final TaskRecord intentTask = intentActivity.getTask(); if (launchStack == null || launchStack == mTargetStack) { // We only want to move to the front, if we aren't going to launch on a // different stack. If we launch on a different stack, we will put the // task on top there. - mTargetStack.moveTaskToFrontLocked( - intentActivity.task, mNoAnimation, mOptions, + mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront"); mMovedToFront = true; } else if (launchStack.mStackId == DOCKED_STACK_ID @@ -1553,7 +1553,7 @@ class ActivityStarter { if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { // If we want to launch adjacent and mTargetStack is not the computed // launch stack - move task to top of computed stack. - intentActivity.task.reparent(launchStack.mStackId, ON_TOP, + intentTask.reparent(launchStack.mStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, "launchToSide"); } else { @@ -1561,8 +1561,8 @@ class ActivityStarter { // We choose to move task to front instead of launching it adjacent // when specific stack was requested explicitly and it appeared to be // adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set. - mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation, - mOptions, mStartActivity.appTimeTracker, + mTargetStack.moveTaskToFrontLocked(intentTask, + mNoAnimation, mOptions, mStartActivity.appTimeTracker, "bringToFrontInsteadOfAdjacentLaunch"); } mMovedToFront = true; @@ -1570,7 +1570,7 @@ class ActivityStarter { // Target and computed stacks are on different displays and we've // found a matching task - move the existing instance to that display and // move it to front. - intentActivity.task.reparent(launchStack.mStackId, ON_TOP, + intentActivity.getTask().reparent(launchStack.mStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, "reparentToDisplay"); mMovedToFront = true; @@ -1582,7 +1582,7 @@ class ActivityStarter { intentActivity.showStartingWindow(null /* prev */, false /* newTask */, true /* taskSwitch */); } - updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack); + updateTaskReturnToType(intentActivity.getTask(), mLaunchFlags, focusStack); } } if (!mMovedToFront && mDoResume) { @@ -1591,7 +1591,7 @@ class ActivityStarter { mTargetStack.moveToFront("intentActivityFound"); } - mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.task, INVALID_STACK_ID, + mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), INVALID_STACK_ID, mTargetStack.mStackId); // If the caller has requested that the target task be reset, then do so. @@ -1635,7 +1635,7 @@ class ActivityStarter { // launching another activity. // TODO(b/36119896): We shouldn't trigger activity launches in this path since we are // already launching one. - final TaskRecord task = intentActivity.task; + final TaskRecord task = intentActivity.getTask(); task.performClearTaskLocked(); mReuseTask = task; mReuseTask.setIntent(mStartActivity); @@ -1646,7 +1646,7 @@ class ActivityStarter { mMovedOtherTask = true; } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 || mLaunchSingleInstance || mLaunchSingleTask) { - ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity, + ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity, mLaunchFlags); if (top == null) { // A special case: we need to start the activity because it is not currently @@ -1655,11 +1655,11 @@ class ActivityStarter { mAddingToTask = true; // We are no longer placing the activity in the task we previously thought we were. - mStartActivity.task = null; + mStartActivity.setTask(null); // Now pretend like this activity is being started by the top of its task, so it // is put in the right place. mSourceRecord = intentActivity; - final TaskRecord task = mSourceRecord.task; + final TaskRecord task = mSourceRecord.getTask(); if (task != null && task.getStack() == null) { // Target stack got cleared when we all activities were removed above. // Go ahead and reset it. @@ -1669,7 +1669,7 @@ class ActivityStarter { !mLaunchTaskBehind /* toTop */, "startActivityUnchecked"); } } - } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) { + } else if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) { // In this case the top activity on the task is the same as the one being launched, // so we take that as a request to bring the task to the foreground. If the top // activity in the task is the root activity, deliver this new intent to it if it @@ -1677,13 +1677,13 @@ class ActivityStarter { if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop) && intentActivity.realActivity.equals(mStartActivity.realActivity)) { ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, - intentActivity.task); + intentActivity.getTask()); if (intentActivity.frontOfTask) { - intentActivity.task.setIntent(mStartActivity); + intentActivity.getTask().setIntent(mStartActivity); } intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); - } else if (!intentActivity.task.isSameIntentFilter(mStartActivity)) { + } else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) { // In this case we are launching the root activity of the task, but with a // different intent. We should start a new instance on top. mAddingToTask = true; @@ -1696,13 +1696,13 @@ class ActivityStarter { // current task. mAddingToTask = true; mSourceRecord = intentActivity; - } else if (!intentActivity.task.rootWasReset) { + } else if (!intentActivity.getTask().rootWasReset) { // In this case we are launching into an existing task that has not yet been started // from its front door. The current task has been brought to the front. Ideally, // we'd probably like to place this new task at the bottom of its stack, but that's // a little hard to do with the current organization of the code so for now we'll // just drop it. - intentActivity.task.setIntent(mStartActivity); + intentActivity.getTask().setIntent(mStartActivity); } } @@ -1736,11 +1736,11 @@ class ActivityStarter { mService.resizeStack( stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); } else { - mStartActivity.task.updateOverrideConfiguration(mLaunchBounds); + mStartActivity.getTask().updateOverrideConfiguration(mLaunchBounds); } } if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity - + " in new task " + mStartActivity.task); + + " in new task " + mStartActivity.getTask()); } else { addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask"); } @@ -1749,7 +1749,7 @@ class ActivityStarter { mStartActivity.setTaskToAffiliateWith(taskToAffiliate); } - if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) { + if (mSupervisor.isLockTaskModeViolation(mStartActivity.getTask())) { Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity); return START_RETURN_LOCK_TASK_MODE_VIOLATION; } @@ -1758,7 +1758,7 @@ class ActivityStarter { // If stack id is specified in activity options, usually it means that activity is // launched not from currently focused stack (e.g. from SysUI or from shell) - in // that case we check the target stack. - updateTaskReturnToType(mStartActivity.task, mLaunchFlags, + updateTaskReturnToType(mStartActivity.getTask(), mLaunchFlags, preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack); } if (mDoResume) { @@ -1768,19 +1768,19 @@ class ActivityStarter { } private int setTaskFromSourceRecord() { - if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) { + if (mSupervisor.isLockTaskModeViolation(mSourceRecord.getTask())) { Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity); return START_RETURN_LOCK_TASK_MODE_VIOLATION; } - final TaskRecord sourceTask = mSourceRecord.task; + final TaskRecord sourceTask = mSourceRecord.getTask(); final ActivityStack sourceStack = mSourceRecord.getStack(); // We only want to allow changing stack if the target task is not the top one, // otherwise we would move the launching task to the other side, rather than show // two side by side. final boolean moveStackAllowed = sourceStack.topTask() != sourceTask; if (moveStackAllowed) { - mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, + mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.getTask(), mOptions); } @@ -1805,7 +1805,7 @@ class ActivityStarter { ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags); mKeepCurTransition = true; if (top != null) { - ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task); + ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask()); top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); // For paranoia, make sure we have correctly resumed the top activity. mTargetStack.mLastPausedActivity = null; @@ -1821,7 +1821,7 @@ class ActivityStarter { // stack if so. final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity); if (top != null) { - final TaskRecord task = top.task; + final TaskRecord task = top.getTask(); task.moveActivityToFrontLocked(top); top.updateOptionsLocked(mOptions); ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task); @@ -1838,7 +1838,7 @@ class ActivityStarter { // the same task as the one that is starting it. addOrReparentStartingActivity(sourceTask, "setTaskFromSourceRecord"); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity - + " in existing task " + mStartActivity.task + " from source " + mSourceRecord); + + " in existing task " + mStartActivity.getTask() + " from source " + mSourceRecord); return START_SUCCESS; } @@ -1861,7 +1861,7 @@ class ActivityStarter { || mLaunchSingleTop || mLaunchSingleTask) { mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront"); - ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task); + ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask()); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and the client said not to do // anything if that is the case, so this is it! @@ -1901,7 +1901,7 @@ class ActivityStarter { addOrReparentStartingActivity(mInTask, "setTaskFromInTask"); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity - + " in explicit task " + mStartActivity.task); + + " in explicit task " + mStartActivity.getTask()); return START_SUCCESS; } @@ -1913,17 +1913,17 @@ class ActivityStarter { mTargetStack.moveToFront("addingToTopTask"); } final ActivityRecord prev = mTargetStack.topActivity(); - final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord( + final TaskRecord task = (prev != null) ? prev.getTask() : mTargetStack.createTaskRecord( mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info, mIntent, null, null, true, mStartActivity.mActivityType); addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask"); mTargetStack.positionChildWindowContainerAtTop(task); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity - + " in new guessed " + mStartActivity.task); + + " in new guessed " + mStartActivity.getTask()); } private void addOrReparentStartingActivity(TaskRecord parent, String reason) { - if (mStartActivity.task == null || mStartActivity.task == parent) { + if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) { parent.addActivityToTop(mStartActivity); } else { mStartActivity.reparent(parent, parent.mActivities.size() /* top */, reason); @@ -1973,7 +1973,7 @@ class ActivityStarter { private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds, int launchFlags, ActivityOptions aOptions) { - final TaskRecord task = r.task; + final TaskRecord task = r.getTask(); ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions); if (stack != null) { return stack; diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 21c131c3616f..ba72dcf23c98 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -98,6 +98,7 @@ class AppErrors { AppErrors(Context context, ActivityManagerService service) { + context.assertRuntimeOverlayThemable(); mService = service; mContext = context; } diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java index 5f7f67a8a5e8..347a357aae04 100644 --- a/services/core/java/com/android/server/am/BaseErrorDialog.java +++ b/services/core/java/com/android/server/am/BaseErrorDialog.java @@ -34,6 +34,7 @@ class BaseErrorDialog extends AlertDialog { public BaseErrorDialog(Context context) { super(context, com.android.internal.R.style.Theme_Dialog_AppError); + context.assertRuntimeOverlayThemable(); getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, diff --git a/services/core/java/com/android/server/am/PersistentConnection.java b/services/core/java/com/android/server/am/PersistentConnection.java new file mode 100644 index 000000000000..c34c097cb696 --- /dev/null +++ b/services/core/java/com/android/server/am/PersistentConnection.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2017 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.am; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.IBinder; +import android.os.UserHandle; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; + +/** + * Connects to a given service component on a given user. + * + * - Call {@link #connect()} to create a connection. + * - Call {@link #disconnect()} to disconnect. Make sure to disconnect when the user stops. + * + * Add onConnected/onDisconnected callbacks as needed. + */ +public abstract class PersistentConnection<T> { + private final Object mLock = new Object(); + + private final String mTag; + private final Context mContext; + private final Handler mHandler; + private final int mUserId; + private final ComponentName mComponentName; + + @GuardedBy("mLock") + private boolean mStarted; + + @GuardedBy("mLock") + private boolean mIsConnected; + + @GuardedBy("mLock") + private T mService; + + private final ServiceConnection mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mLock) { + Slog.i(mTag, "Connected: " + mComponentName.flattenToShortString() + + " u" + mUserId); + + mIsConnected = true; + mService = asInterface(service); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + synchronized (mLock) { + Slog.i(mTag, "Disconnected: " + mComponentName.flattenToShortString() + + " u" + mUserId); + + cleanUpConnectionLocked(); + } + } + }; + + public PersistentConnection(@NonNull String tag, @NonNull Context context, + @NonNull Handler handler, int userId, @NonNull ComponentName componentName) { + mTag = tag; + mContext = context; + mHandler = handler; + mUserId = userId; + mComponentName = componentName; + } + + public final ComponentName getComponentName() { + return mComponentName; + } + + /** + * @return whether connected. + */ + public final boolean isConnected() { + synchronized (mLock) { + return mIsConnected; + } + } + + /** + * @return the service binder interface. + */ + public final T getServiceBinder() { + synchronized (mLock) { + return mService; + } + } + + /** + * Connects to the service. + */ + public final void connect() { + synchronized (mLock) { + if (mStarted) { + return; + } + mStarted = true; + + final Intent service = new Intent().setComponent(mComponentName); + + final boolean success = mContext.bindServiceAsUser(service, mServiceConnection, + Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, + mHandler, UserHandle.of(mUserId)); + + if (!success) { + Slog.e(mTag, "Binding: " + service.getComponent() + " u" + mUserId + + " failed."); + } + } + } + + private void cleanUpConnectionLocked() { + mIsConnected = false; + mService = null; + } + + /** + * Disconnect from the service. + */ + public final void disconnect() { + synchronized (mLock) { + if (!mStarted) { + return; + } + Slog.i(mTag, "Stopping: " + mComponentName.flattenToShortString() + " u" + mUserId); + mStarted = false; + mContext.unbindService(mServiceConnection); + + cleanUpConnectionLocked(); + } + } + + /** Must be implemented by a subclass to convert an {@link IBinder} to a stub. */ + protected abstract T asInterface(IBinder binder); + + public void dump(String prefix, PrintWriter pw) { + synchronized (mLock) { + pw.print(prefix); + pw.print(mComponentName.flattenToShortString()); + pw.print(mStarted ? " [started]" : " [not started]"); + pw.print(mIsConnected ? " [connected]" : " [not connected]"); + pw.println(); + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 40effff77166..0dc678813338 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -350,58 +350,58 @@ final class ProcessList { String procState; switch (curProcState) { case ActivityManager.PROCESS_STATE_PERSISTENT: - procState = "P "; + procState = "PER "; break; case ActivityManager.PROCESS_STATE_PERSISTENT_UI: - procState = "PU"; + procState = "PERU"; break; case ActivityManager.PROCESS_STATE_TOP: - procState = "T "; + procState = "TOP"; break; case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE: - procState = "SB"; + procState = "BFGS"; break; case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE: - procState = "SF"; + procState = "FGS "; break; case ActivityManager.PROCESS_STATE_TOP_SLEEPING: - procState = "TS"; + procState = "TPSL"; break; case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: - procState = "IF"; + procState = "IMPF"; break; case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: - procState = "IB"; + procState = "IMPB"; break; case ActivityManager.PROCESS_STATE_BACKUP: - procState = "BU"; + procState = "BKUP"; break; case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: - procState = "HW"; + procState = "HVY "; break; case ActivityManager.PROCESS_STATE_SERVICE: - procState = "S "; + procState = "SVC "; break; case ActivityManager.PROCESS_STATE_RECEIVER: - procState = "R "; + procState = "RCVR"; break; case ActivityManager.PROCESS_STATE_HOME: - procState = "HO"; + procState = "HOME"; break; case ActivityManager.PROCESS_STATE_LAST_ACTIVITY: - procState = "LA"; + procState = "LAST"; break; case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: - procState = "CA"; + procState = "CAC "; break; case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: - procState = "Ca"; + procState = "CACC"; break; case ActivityManager.PROCESS_STATE_CACHED_EMPTY: - procState = "CE"; + procState = "CEM "; break; case ActivityManager.PROCESS_STATE_NONEXISTENT: - procState = "N "; + procState = "NONE"; break; default: procState = "??"; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 2d2720458fbb..3c5c5fd0cfe4 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -287,7 +287,9 @@ final class ProcessRecord { pw.print(" setSchedGroup="); pw.print(setSchedGroup); pw.print(" systemNoUi="); pw.print(systemNoUi); pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel); - pw.print(prefix); pw.print("vrThreadTid="); pw.print(vrThreadTid); + if (vrThreadTid != 0) { + pw.print(prefix); pw.print("vrThreadTid="); pw.println(vrThreadTid); + } pw.print(prefix); pw.print("curProcState="); pw.print(curProcState); pw.print(" repProcState="); pw.print(repProcState); pw.print(" pssProcState="); pw.print(pssProcState); diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 27a2461a8827..c7f20b9ff904 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -660,17 +660,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta // we are coming from in WM before we reparent because it became empty. mWindowContainerController.reparent(toStack.getWindowContainerController(), position); - // Reset the resumed activity on the previous stack - if (wasResumed) { - sourceStack.mResumedActivity = null; - } - - // Reset the paused activity on the previous stack - if (wasPaused) { - sourceStack.mPausingActivity = null; - sourceStack.removeTimeoutsForActivityLocked(r); - } - // Move the task sourceStack.removeTask(this, reason, REMOVE_TASK_MODE_MOVING); toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason); @@ -1212,14 +1201,13 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta * be in the current task or unparented to any task. */ void addActivityAtIndex(int index, ActivityRecord r) { - if (r.task != null && r.task != this) { + TaskRecord task = r.getTask(); + if (task != null && task != this) { throw new IllegalArgumentException("Can not add r=" + " to task=" + this - + " current parent=" + r.task); + + " current parent=" + task); } - // TODO(b/36505427): Maybe make task private to ActivityRecord so we can also do - // onParentChanged() within the setter? - r.task = this; - r.onParentChanged(); + + r.setTask(this); // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. if (!mActivities.remove(r) && r.fullscreen) { @@ -1274,15 +1262,21 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta } /** - * @return true if this was the last activity in the task + * Removes the specified activity from this task. + * @param r The {@link ActivityRecord} to remove. + * @return true if this was the last activity in the task. */ boolean removeActivity(ActivityRecord r) { - if (r.task != this) { + return removeActivity(r, false /*reparenting*/); + } + + boolean removeActivity(ActivityRecord r, boolean reparenting) { + if (r.getTask() != this) { throw new IllegalArgumentException( "Activity=" + r + " does not belong to task=" + this); } - r.task = null; + r.setTask(null /*task*/, reparenting); if (mActivities.remove(r) && r.fullscreen) { // Was previously in list. @@ -1437,7 +1431,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta TaskThumbnail getTaskThumbnailLocked() { if (mStack != null) { final ActivityRecord resumedActivity = mStack.mResumedActivity; - if (resumedActivity != null && resumedActivity.task == this) { + if (resumedActivity != null && resumedActivity.getTask() == this) { final Bitmap thumbnail = resumedActivity.screenshotActivityLocked(); setLastThumbnailLocked(thumbnail); } @@ -1619,6 +1613,9 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta String iconFilename = null; int colorPrimary = 0; int colorBackground = 0; + int statusBarColor = 0; + int navigationBarColor = 0; + boolean topActivity = true; for (--activityNdx; activityNdx >= 0; --activityNdx) { final ActivityRecord r = mActivities.get(activityNdx); if (r.taskDescription != null) { @@ -1631,13 +1628,16 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta if (colorPrimary == 0) { colorPrimary = r.taskDescription.getPrimaryColor(); } - if (colorBackground == 0) { + if (topActivity) { colorBackground = r.taskDescription.getBackgroundColor(); + statusBarColor = r.taskDescription.getStatusBarColor(); + navigationBarColor = r.taskDescription.getNavigationBarColor(); } } + topActivity = false; } lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary, - colorBackground); + colorBackground, statusBarColor, navigationBarColor); if (mWindowContainerController != null) { mWindowContainerController.setTaskDescription(lastTaskDescription); } @@ -1953,7 +1953,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta task.updateOverrideConfiguration(bounds); for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { - activities.get(activityNdx).task = task; + activities.get(activityNdx).setTask(task); } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 70e56b09de13..c11f5316f769 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -55,6 +55,7 @@ import android.hardware.hdmi.HdmiTvClient; import android.hardware.usb.UsbManager; import android.media.AudioAttributes; import android.media.AudioDevicePort; +import android.media.AudioFocusInfo; import android.media.AudioSystem; import android.media.AudioFormat; import android.media.AudioManager; @@ -5634,8 +5635,9 @@ public class AudioService extends IAudioService.Stub clientId, callingPackageName, flags); } - public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) { - return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa); + public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa, + String callingPackageName) { + return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName); } public void unregisterAudioFocusClient(String clientId) { @@ -5650,6 +5652,7 @@ public class AudioService extends IAudioService.Stub return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr); } + //========================================================================================== private boolean readCameraSoundForced() { return SystemProperties.getBoolean("audio.camerasound.force", false) || mContext.getResources().getBoolean( @@ -6430,7 +6433,7 @@ public class AudioService extends IAudioService.Stub // Audio policy management //========================================================================================== public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb, - boolean hasFocusListener) { + boolean hasFocusListener, boolean isFocusPolicy) { AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback); if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder() @@ -6452,7 +6455,8 @@ public class AudioService extends IAudioService.Stub Slog.e(TAG, "Cannot re-register policy"); return null; } - AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener); + AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener, + isFocusPolicy); pcb.asBinder().linkToDeath(app, 0/*flags*/); regId = app.getRegistrationId(); mAudioPolicies.put(pcb.asBinder(), app); @@ -6650,15 +6654,21 @@ public class AudioService extends IAudioService.Stub * is handling ducking for audio focus. */ int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT; + boolean mIsFocusPolicy = false; AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token, - boolean hasFocusListener) { + boolean hasFocusListener, boolean isFocusPolicy) { super(config); setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++)); mPolicyCallback = token; mHasFocusListener = hasFocusListener; if (mHasFocusListener) { mMediaFocusControl.addFocusFollower(mPolicyCallback); + // can only ever be true if there is a focus listener + if (isFocusPolicy) { + mIsFocusPolicy = true; + mMediaFocusControl.setFocusPolicy(mPolicyCallback); + } } connectMixes(); } @@ -6676,6 +6686,9 @@ public class AudioService extends IAudioService.Stub } void release() { + if (mIsFocusPolicy) { + mMediaFocusControl.unsetFocusPolicy(mPolicyCallback); + } if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) { mMediaFocusControl.setDuckingInExtPolicyAvailable(false); } @@ -6690,6 +6703,22 @@ public class AudioService extends IAudioService.Stub } }; + //====================== + // Audio policy: focus + //====================== + /** */ + public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) { + synchronized (mAudioPolicies) { + if (!mAudioPolicies.containsKey(pcb.asBinder())) { + throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch"); + } + return mMediaFocusControl.dispatchFocusChange(afi, focusChange); + } + } + + //====================== + // misc + //====================== private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies = new HashMap<IBinder, AudioPolicyProxy>(); private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index 5275c0524d54..bcaa29593304 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -33,7 +33,7 @@ import java.io.PrintWriter; * @hide * Class to handle all the information about a user of audio focus. The lifecycle of each * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus - * stack to its release. + * stack, or the map of focus owners for an external focus policy, to its release. */ public class FocusRequester { @@ -101,6 +101,21 @@ public class FocusRequester { mFocusController = ctlr; } + FocusRequester(AudioFocusInfo afi, IAudioFocusDispatcher afl, + IBinder source, AudioFocusDeathHandler hdlr, @NonNull MediaFocusControl ctlr) { + mAttributes = afi.getAttributes(); + mClientId = afi.getClientId(); + mPackageName = afi.getPackageName(); + mCallingUid = afi.getClientUid(); + mFocusGainRequest = afi.getGainRequest(); + mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; + mGrantFlags = afi.getFlags(); + + mFocusDispatcher = afl; + mSourceRef = source; + mDeathHandler = hdlr; + mFocusController = ctlr; + } boolean hasSameClient(String otherClient) { try { @@ -118,6 +133,10 @@ public class FocusRequester { return (mSourceRef != null) && mSourceRef.equals(ib); } + boolean hasSameDispatcher(IAudioFocusDispatcher fd) { + return (mFocusDispatcher != null) && mFocusDispatcher.equals(fd); + } + boolean hasSamePackage(String pack) { try { return mPackageName.compareTo(pack) == 0; @@ -369,6 +388,35 @@ public class FocusRequester { } } + int dispatchFocusChange(int focusChange) { + if (mFocusDispatcher == null) { + if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: no focus dispatcher"); } + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + if (focusChange == AudioManager.AUDIOFOCUS_NONE) { + if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: AUDIOFOCUS_NONE"); } + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } else if ((focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK + || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE + || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT + || focusChange == AudioManager.AUDIOFOCUS_GAIN) + && (mFocusGainRequest != focusChange)){ + Log.w(TAG, "focus gain was requested with " + mFocusGainRequest + + ", dispatching " + focusChange); + } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK + || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT + || focusChange == AudioManager.AUDIOFOCUS_LOSS) { + mFocusLossReceived = focusChange; + } + try { + mFocusDispatcher.dispatchAudioFocusChange(focusChange, mClientId); + } catch (android.os.RemoteException e) { + Log.v(TAG, "dispatchFocusChange: error talking to focus listener", e); + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + } + AudioFocusInfo toAudioFocusInfo() { return new AudioFocusInfo(mAttributes, mCallingUid, mClientId, mPackageName, mFocusGainRequest, mFocusLossReceived, mGrantFlags); diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index b3f1548d4d92..821e78a27e33 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -16,6 +16,7 @@ package com.android.server.audio; +import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.media.AudioAttributes; @@ -23,6 +24,7 @@ import android.media.AudioFocusInfo; import android.media.AudioManager; import android.media.AudioSystem; import android.media.IAudioFocusDispatcher; +import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.IAudioPolicyCallback; import android.os.Binder; import android.os.IBinder; @@ -32,7 +34,10 @@ import android.util.Log; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; import java.util.Stack; import java.text.DateFormat; @@ -43,6 +48,7 @@ import java.text.DateFormat; public class MediaFocusControl implements PlayerFocusEnforcer { private static final String TAG = "MediaFocusControl"; + static final boolean DEBUG = false; /** * set to true so the framework enforces ducking itself, without communicating to apps @@ -155,6 +161,13 @@ public class MediaFocusControl implements PlayerFocusEnforcer { while(stackIterator.hasNext()) { stackIterator.next().dump(pw); } + pw.println("\n"); + if (mFocusPolicy == null) { + pw.println("No external focus policy\n"); + } else { + pw.println("External focus policy: "+ mFocusPolicy + ", focus owners:\n"); + dumpExtFocusPolicyFocusOwners(pw); + } } pw.println("\n"); pw.println(" Notify on duck: " + mNotifyFocusOwnerOnDuck + "\n"); @@ -234,6 +247,31 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } /** + * Helper function for external focus policy: + * Called synchronized on mAudioFocusLock + * Remove focus listeners from the list of potential focus owners for a particular client when + * it has died. + */ + private void removeFocusEntryForExtPolicy(IBinder cb) { + if (mFocusOwnersForFocusPolicy.isEmpty()) { + return; + } + boolean released = false; + final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet(); + final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator(); + while (ownerIterator.hasNext()) { + final Entry<String, FocusRequester> owner = ownerIterator.next(); + final FocusRequester fr = owner.getValue(); + if (fr.hasSameBinder(cb)) { + ownerIterator.remove(); + fr.release(); + notifyExtFocusPolicyFocusAbandon_syncAf(fr.toAudioFocusInfo()); + break; + } + } + } + + /** * Helper function: * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. * The implementation guarantees that a state where focus cannot be immediately reassigned @@ -297,7 +335,11 @@ public class MediaFocusControl implements PlayerFocusEnforcer { public void binderDied() { synchronized(mAudioFocusLock) { - removeFocusStackEntryOnDeath(mCb); + if (mFocusPolicy != null) { + removeFocusEntryForExtPolicy(mCb); + } else { + removeFocusStackEntryOnDeath(mCb); + } } } } @@ -353,6 +395,34 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } + private IAudioPolicyCallback mFocusPolicy = null; + + // Since we don't have a stack of focus owners when using an external focus policy, we keep + // track of all the focus requesters in this map, with their clientId as the key. This is + // used both for focus dispatch and death handling + private HashMap<String, FocusRequester> mFocusOwnersForFocusPolicy = + new HashMap<String, FocusRequester>(); + + void setFocusPolicy(IAudioPolicyCallback policy) { + if (policy == null) { + return; + } + synchronized (mAudioFocusLock) { + mFocusPolicy = policy; + } + } + + void unsetFocusPolicy(IAudioPolicyCallback policy) { + if (policy == null) { + return; + } + synchronized (mAudioFocusLock) { + if (mFocusPolicy == policy) { + mFocusPolicy = null; + } + } + } + /** * @param pcb non null */ @@ -409,6 +479,100 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } + /** + * Called synchronized on mAudioFocusLock + * @param afi + * @param requestResult + * @return true if the external audio focus policy (if any) is handling the focus request + */ + boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi, int requestResult, + IAudioFocusDispatcher fd, IBinder cb) { + if (mFocusPolicy == null) { + return false; + } + if (DEBUG) { + Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId() + + " dispatcher=" + fd); + } + final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId()); + if (existingFr != null) { + if (!existingFr.hasSameDispatcher(fd)) { + existingFr.release(); + final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb); + mFocusOwnersForFocusPolicy.put(afi.getClientId(), + new FocusRequester(afi, fd, cb, hdlr, this)); + } + } else if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED + || requestResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { + // new focus (future) focus owner to keep track of + final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb); + mFocusOwnersForFocusPolicy.put(afi.getClientId(), + new FocusRequester(afi, fd, cb, hdlr, this)); + } + try { + //oneway + mFocusPolicy.notifyAudioFocusRequest(afi, requestResult); + } catch (RemoteException e) { + Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback " + + mFocusPolicy.asBinder(), e); + } + return true; + } + + /** + * Called synchronized on mAudioFocusLock + * @param afi + * @param requestResult + * @return true if the external audio focus policy (if any) is handling the focus request + */ + boolean notifyExtFocusPolicyFocusAbandon_syncAf(AudioFocusInfo afi) { + if (mFocusPolicy == null) { + return false; + } + final FocusRequester fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId()); + if (fr != null) { + fr.release(); + } + try { + //oneway + mFocusPolicy.notifyAudioFocusAbandon(afi); + } catch (RemoteException e) { + Log.e(TAG, "Can't call notifyAudioFocusAbandon() on IAudioPolicyCallback " + + mFocusPolicy.asBinder(), e); + } + return true; + } + + /** see AudioManager.dispatchFocusChange(AudioFocusInfo afi, int focusChange, AudioPolicy ap) */ + int dispatchFocusChange(AudioFocusInfo afi, int focusChange) { + if (DEBUG) { + Log.v(TAG, "dispatchFocusChange " + focusChange + " to afi client=" + + afi.getClientId()); + } + synchronized (mAudioFocusLock) { + if (mFocusPolicy == null) { + if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); } + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId()); + if (fr == null) { + if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); } + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + return fr.dispatchFocusChange(focusChange); + } + } + + private void dumpExtFocusPolicyFocusOwners(PrintWriter pw) { + final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet(); + final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator(); + while (ownerIterator.hasNext()) { + final Entry<String, FocusRequester> owner = ownerIterator.next(); + final FocusRequester fr = owner.getValue(); + fr.dump(pw); + } + } + protected int getCurrentAudioFocus() { synchronized(mAudioFocusLock) { if (mFocusStack.empty()) { @@ -487,10 +651,23 @@ public class MediaFocusControl implements PlayerFocusEnforcer { & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); if (enteringRingOrCall) { mRingOrCallActive = true; } + final AudioFocusInfo afiForExtPolicy; + if (mFocusPolicy != null) { + // construct AudioFocusInfo as it will be communicated to audio focus policy + afiForExtPolicy = new AudioFocusInfo(aa, Binder.getCallingUid(), + clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/, + flags); + } else { + afiForExtPolicy = null; + } + + // handle delayed focus boolean focusGrantDelayed = false; if (!canReassignAudioFocus()) { if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) { - return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + final int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED; + notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, result, fd, cb); + return result; } else { // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be // granted right now, so the requester will be inserted in the focus stack @@ -499,6 +676,14 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } + // external focus policy: delay request for focus gain? + final int resultWithExtPolicy = AudioManager.AUDIOFOCUS_REQUEST_DELAYED; + if (notifyExtFocusPolicyFocusRequest_syncAf( + afiForExtPolicy, resultWithExtPolicy, fd, cb)) { + // stop handling focus request here as it is handled by external audio focus policy + return resultWithExtPolicy; + } + // handle the potential premature death of the new holder of the focus // (premature death == death before abandoning focus) // Register for client death notification @@ -569,7 +754,8 @@ public class MediaFocusControl implements PlayerFocusEnforcer { /** * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes) * */ - protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa) { + protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa, + String callingPackageName) { // AudioAttributes are currently ignored, to be used for zones Log.i(TAG, " AudioFocus abandonAudioFocus() from uid/pid " + Binder.getCallingUid() + "/" + Binder.getCallingPid() @@ -577,6 +763,16 @@ public class MediaFocusControl implements PlayerFocusEnforcer { try { // this will take care of notifying the new focus owner if needed synchronized(mAudioFocusLock) { + // external focus policy? + if (mFocusPolicy != null) { + final AudioFocusInfo afi = new AudioFocusInfo(aa, Binder.getCallingUid(), + clientId, callingPackageName, 0 /*gainRequest*/, 0 /*lossReceived*/, + 0 /*flags*/); + if (notifyExtFocusPolicyFocusAbandon_syncAf(afi)) { + return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + } + } + boolean exitingRingOrCall = mRingOrCallActive & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); if (exitingRingOrCall) { mRingOrCallActive = false; } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index a1a74377cf62..ddd918fdcc5d 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -339,6 +339,18 @@ public final class DisplayManagerService extends SystemService { } } + /** + * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo) + */ + private void getNonOverrideDisplayInfoInternal(int displayId, DisplayInfo outInfo) { + synchronized (mSyncRoot) { + final LogicalDisplay display = mLogicalDisplays.get(displayId); + if (display != null) { + display.getNonOverrideDisplayInfoLocked(outInfo); + } + } + } + private void performTraversalInTransactionFromWindowManagerInternal() { synchronized (mSyncRoot) { if (!mPendingTraversal) { @@ -1663,6 +1675,11 @@ public final class DisplayManagerService extends SystemService { } @Override + public void getNonOverrideDisplayInfo(int displayId, DisplayInfo outInfo) { + getNonOverrideDisplayInfoInternal(displayId, outInfo); + } + + @Override public void performTraversalInTransactionFromWindowManager() { performTraversalInTransactionFromWindowManagerInternal(); } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index a947b4106794..addad0b413a3 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -17,6 +17,7 @@ package com.android.server.display; import android.graphics.Rect; +import android.hardware.display.DisplayManagerInternal; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; @@ -62,7 +63,18 @@ final class LogicalDisplay { private final int mDisplayId; private final int mLayerStack; - private DisplayInfo mOverrideDisplayInfo; // set by the window manager + /** + * Override information set by the window manager. Will be reported instead of {@link #mInfo} + * if not null. + * @see #setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo) + * @see #getDisplayInfoLocked() + */ + private DisplayInfo mOverrideDisplayInfo; + /** + * Current display info. Initialized with {@link #mBaseDisplayInfo}. Set to {@code null} if + * needs to be updated. + * @see #getDisplayInfoLocked() + */ private DisplayInfo mInfo; // The display device that this logical display is based on and which @@ -142,6 +154,13 @@ final class LogicalDisplay { } /** + * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo) + */ + void getNonOverrideDisplayInfoLocked(DisplayInfo outInfo) { + outInfo.copyFrom(mBaseDisplayInfo); + } + + /** * Sets overridden logical display information from the window manager. * This method can be used to adjust application insets, rotation, and other * properties that the window manager takes care of. diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 9e4432d25c0b..dc2ebb4451b2 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -27,4 +27,15 @@ public abstract class NetworkPolicyManagerInternal { * Resets all policies associated with a given user. */ public abstract void resetUserState(int userId); + + /** + * @return true if the given uid is restricted from doing networking on metered networks. + */ + public abstract boolean isUidRestrictedOnMeteredNetworks(int uid); + + /** + * @return true if networking is blocked on the given interface for the given uid according + * to current networking policies. + */ + public abstract boolean isUidNetworkingBlocked(int uid, String ifname); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 4e1166b71d67..02e106e92aeb 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -248,8 +248,8 @@ import java.util.concurrent.TimeUnit; */ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { static final String TAG = "NetworkPolicy"; - private static final boolean LOGD = false; - private static final boolean LOGV = false; + private static final boolean LOGD = true; // UNDO + private static final boolean LOGV = true; // UNDO private static final int VERSION_INIT = 1; private static final int VERSION_ADDED_SNOOZE = 2; @@ -428,9 +428,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidState = new SparseIntArray(); - /** Higher priority listener before general event dispatch */ - private INetworkPolicyListener mConnectivityListener; - private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<>(); @@ -2237,15 +2234,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void setConnectivityListener(INetworkPolicyListener listener) { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - if (mConnectivityListener != null) { - throw new IllegalStateException("Connectivity listener already registered"); - } - mConnectivityListener = listener; - } - - @Override public void registerListener(INetworkPolicyListener listener) { // TODO: create permission for observing network policy mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); @@ -3556,7 +3544,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MSG_RULES_CHANGED: { final int uid = msg.arg1; final int uidRules = msg.arg2; - dispatchUidRulesChanged(mConnectivityListener, uid, uidRules); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); @@ -3567,7 +3554,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } case MSG_METERED_IFACES_CHANGED: { final String[] meteredIfaces = (String[]) msg.obj; - dispatchMeteredIfacesChanged(mConnectivityListener, meteredIfaces); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); @@ -3598,7 +3584,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } case MSG_RESTRICT_BACKGROUND_CHANGED: { final boolean restrictBackground = msg.arg1 != 0; - dispatchRestrictBackgroundChanged(mConnectivityListener, restrictBackground); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); @@ -3616,7 +3601,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int policy = msg.arg2; final Boolean notifyApp = (Boolean) msg.obj; // First notify internal listeners... - dispatchUidPoliciesChanged(mConnectivityListener, uid, policy); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); @@ -4049,6 +4033,74 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } } + + /** + * @return true if the given uid is restricted from doing networking on metered networks. + */ + @Override + public boolean isUidRestrictedOnMeteredNetworks(int uid) { + final int uidRules; + final boolean isBackgroundRestricted; + synchronized (mUidRulesFirstLock) { + uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); + isBackgroundRestricted = mRestrictBackground; + } + return isBackgroundRestricted + && !hasRule(uidRules, RULE_ALLOW_METERED) + && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED); + } + + /** + * @return true if networking is blocked on the given interface for the given uid according + * to current networking policies. + */ + @Override + public boolean isUidNetworkingBlocked(int uid, String ifname) { + final int uidRules; + final boolean isBackgroundRestricted; + final boolean isNetworkMetered; + synchronized (mUidRulesFirstLock) { + uidRules = mUidRules.get(uid, RULE_NONE); + isBackgroundRestricted = mRestrictBackground; + synchronized (mNetworkPoliciesSecondLock) { + isNetworkMetered = mMeteredIfaces.contains(ifname); + } + } + if (hasRule(uidRules, RULE_REJECT_ALL)) { + if (LOGV) logUidStatus(uid, "blocked by power restrictions"); + return true; + } + if (!isNetworkMetered) { + if (LOGV) logUidStatus(uid, "allowed on unmetered network"); + return false; + } + if (hasRule(uidRules, RULE_REJECT_METERED)) { + if (LOGV) logUidStatus(uid, "blacklisted on metered network"); + return true; + } + if (hasRule(uidRules, RULE_ALLOW_METERED)) { + if (LOGV) logUidStatus(uid, "whitelisted on metered network"); + return false; + } + if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) { + if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network"); + return false; + } + if (isBackgroundRestricted) { + if (LOGV) logUidStatus(uid, "blocked when background is restricted"); + return true; + } + if (LOGV) logUidStatus(uid, "allowed by default"); + return false; + } + } + + private static boolean hasRule(int uidRules, int rule) { + return (uidRules & rule) != 0; + } + + private static void logUidStatus(int uid, String descr) { + Slog.d(TAG, String.format("uid %d is %s", uid, descr)); } /** diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 5bdef9ea7d49..3705946008f1 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -325,13 +325,11 @@ final class OverlayManagerServiceImpl { // Disable all other overlays. allOverlays.remove(oi); for (int i = 0; i < allOverlays.size(); i++) { - mSettings.setEnabled(allOverlays.get(i).packageName, userId, false); + // TODO: Optimize this to only send updates after all changes. + setEnabled(allOverlays.get(i).packageName, false, userId); } - final PackageInfo targetPackage = - mPackageManager.getPackageInfo(oi.targetPackageName, userId); - mSettings.setEnabled(packageName, userId, enable); - updateState(targetPackage, overlayPackage, userId); + setEnabled(packageName, enable, userId); return true; } catch (OverlayManagerSettings.BadKeyException e) { return false; diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index e1426fdcf3ef..f79f6f40294c 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -242,18 +242,8 @@ public class LauncherAppsService extends SystemService { try { UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); if (callingUserInfo.isManagedProfile()) { - - // STOPSHIP Remove the whitelist. - if ("com.google.android.talk".equals(callingPackage) - || "com.google.android.quicksearchbox".equals(callingPackage) - || "com.google.android.googlequicksearchbox".equals(callingPackage) - ) { - return false; - } - // STOPSHIP Change it to 'e'. - Slog.wtfStack(TAG, message + " by " + callingPackage + " for another profile " + Slog.w(TAG, message + " by " + callingPackage + " for another profile " + targetUserId + " from " + callingUserId); - return false; } @@ -445,8 +435,8 @@ public class LauncherAppsService extends SystemService { @Override public ParceledListSlice getShortcuts(String callingPackage, long changedSince, - String packageName, List shortcutIds, ComponentName componentName, Intent intent, - int flags, UserHandle targetUser) { + String packageName, List shortcutIds, ComponentName componentName, int flags, + UserHandle targetUser) { ensureShortcutPermission(callingPackage); if (!canAccessProfile(callingPackage, targetUser, "Cannot get shortcuts") || !isUserEnabled(targetUser)) { @@ -457,17 +447,11 @@ public class LauncherAppsService extends SystemService { "To query by shortcut ID, package name must also be set"); } - if ((flags & ShortcutQuery.FLAG_MATCH_CHOOSER) == 0 - && intent != null) { - throw new IllegalArgumentException("Supplied an intent in the query, but did " - + "not request chooser targets"); - } - // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below. return new ParceledListSlice<>((List<ShortcutInfo>) mShortcutServiceInternal.getShortcuts(getCallingUserId(), callingPackage, changedSince, packageName, shortcutIds, - componentName, intent, flags, targetUser.getIdentifier())); + componentName, flags, targetUser.getIdentifier())); } @Override @@ -915,7 +899,6 @@ public class LauncherAppsService extends SystemService { cookie.packageName, /* changedSince= */ 0, packageName, /* shortcutIds=*/ null, /* component= */ null, - /* intent= */ null, ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY | ShortcutQuery.FLAG_GET_ALL_KINDS , userId); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 365a8e87d3ed..578b10ab1d5d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -842,11 +842,11 @@ public class PackageManagerService extends IPackageManager.Stub { /** The service connection to the ephemeral resolver */ final EphemeralResolverConnection mInstantAppResolverConnection; + /** Component used to show resolver settings for Instant Apps */ + final ComponentName mInstantAppResolverSettingsComponent; /** Component used to install ephemeral applications */ ComponentName mInstantAppInstallerComponent; - /** Component used to show resolver settings for Instant Apps */ - ComponentName mInstantAppResolverSettingsComponent; ActivityInfo mInstantAppInstallerActivity; final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo(); @@ -2385,6 +2385,10 @@ public class PackageManagerService extends IPackageManager.Stub { final VersionInfo ver = mSettings.getInternalVersion(); mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint); + if (mIsUpgrade) { + logCriticalInfo(Log.INFO, + "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT); + } // when upgrading from pre-M, promote system app permissions from install to runtime mPromoteSystemApps = @@ -2803,11 +2807,13 @@ public class PackageManagerService extends IPackageManager.Stub { } mInstantAppResolverConnection = new EphemeralResolverConnection(mContext, ephemeralResolverComponent); + mInstantAppResolverSettingsComponent = + getEphemeralResolverSettingsLPr(ephemeralResolverComponent); } else { mInstantAppResolverConnection = null; + mInstantAppResolverSettingsComponent = null; } updateInstantAppInstallerLocked(); - mInstantAppResolverSettingsComponent = getEphemeralResolverSettingsLPr(); // Read and update the usage of dex files. // Do this at the end of PM init so that all the packages have their @@ -3115,35 +3121,18 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private @Nullable ComponentName getEphemeralResolverSettingsLPr() { - final Intent intent = new Intent(Intent.ACTION_EPHEMERAL_RESOLVER_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - final int resolveFlags = - MATCH_DIRECT_BOOT_AWARE - | MATCH_DIRECT_BOOT_UNAWARE - | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0); - final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null, - resolveFlags, UserHandle.USER_SYSTEM); - Iterator<ResolveInfo> iter = matches.iterator(); - while (iter.hasNext()) { - final ResolveInfo rInfo = iter.next(); - final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName); - if (ps != null) { - final PermissionsState permissionsState = ps.getPermissionsState(); - if (permissionsState.hasPermission(Manifest.permission.ACCESS_INSTANT_APPS, 0)) { - continue; - } - } - iter.remove(); - } - if (matches.size() == 0) { + private @Nullable ComponentName getEphemeralResolverSettingsLPr( + @NonNull ComponentName resolver) { + final Intent intent = new Intent(Intent.ACTION_EPHEMERAL_RESOLVER_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .setPackage(resolver.getPackageName()); + final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; + final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null, resolveFlags, + UserHandle.USER_SYSTEM); + if (matches.isEmpty()) { return null; - } else if (matches.size() == 1) { - return matches.get(0).getComponentInfo().getComponentName(); - } else { - throw new RuntimeException( - "There must be at most one ephemeral resolver settings; found " + matches); } + return matches.get(0).getComponentInfo().getComponentName(); } private void primeDomainVerificationsLPw(int userId) { @@ -16961,6 +16950,15 @@ public class PackageManagerService extends IPackageManager.Stub { return; } + // Shared libraries for the package need to be updated. + synchronized (mPackages) { + try { + updateSharedLibrariesLPr(pkg, null); + } catch (PackageManagerException e) { + Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); + } + } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); // Do not run PackageDexOptimizer through the local performDexOpt // method because `pkg` may not be in `mPackages` yet. @@ -17009,6 +17007,7 @@ public class PackageManagerService extends IPackageManager.Stub { args.user, installerPackageName, volumeUuid, res, args.installReason); } } + synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 6f7e0de4b8ee..5035e6820be8 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -20,7 +20,6 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.ShortcutInfo; import android.content.res.Resources; @@ -32,7 +31,6 @@ import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.pm.ShortcutService.ShortcutOperation; @@ -70,9 +68,6 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String TAG_EXTRAS = "extras"; private static final String TAG_SHORTCUT = "shortcut"; private static final String TAG_CATEGORIES = "categories"; - private static final String TAG_CHOOSER_EXTRAS = "chooser-extras"; - private static final String TAG_CHOOSER_INTENT_FILTERS = "chooser-intent-filters"; - private static final String TAG_CHOOSER_COMPONENT_NAMES = "chooser-component-names"; private static final String ATTR_NAME = "name"; private static final String ATTR_CALL_COUNT = "call-count"; @@ -96,7 +91,6 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String ATTR_ICON_RES_ID = "icon-res"; private static final String ATTR_ICON_RES_NAME = "icon-resname"; private static final String ATTR_BITMAP_PATH = "bitmap-path"; - private static final String ATTR_COMPONENT_NAMES = "component-names"; private static final String NAME_CATEGORIES = "categories"; @@ -206,7 +200,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (shortcut != null) { mShortcutUser.mService.removeIcon(getPackageUserId(), shortcut); shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED - | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CHOOSER); + | ShortcutInfo.FLAG_MANIFEST); } return shortcut; } @@ -232,7 +226,7 @@ class ShortcutPackage extends ShortcutPackageItem { Preconditions.checkArgument(newShortcut.isEnabled(), "add/setDynamicShortcuts() cannot publish disabled shortcuts"); - addCorrectDynamicFlags(newShortcut); + newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC); final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId()); @@ -256,17 +250,6 @@ class ShortcutPackage extends ShortcutPackageItem { addShortcutInner(newShortcut); } - // TODO: Sample code & JavaDoc for ShortcutManager needs updating to reflect the fact that - // Chooser shortcuts are not always dynamic. - public void addCorrectDynamicFlags(@NonNull ShortcutInfo shortcut) { - if (shortcut.getIntent() != null) { - shortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC); - } - if (!ArrayUtils.isEmpty(shortcut.getChooserIntentFilters())) { - shortcut.addFlags(ShortcutInfo.FLAG_CHOOSER); - } - } - /** * Remove all shortcuts that aren't pinned nor dynamic. */ @@ -299,11 +282,11 @@ class ShortcutPackage extends ShortcutPackageItem { boolean changed = false; for (int i = mShortcuts.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.valueAt(i); - if (si.isDynamic() || si.isChooser()) { + if (si.isDynamic()) { changed = true; si.setTimestamp(now); - si.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_CHOOSER); + si.clearFlags(ShortcutInfo.FLAG_DYNAMIC); si.setRank(0); // It may still be pinned, so clear the rank. } } @@ -372,8 +355,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (oldShortcut.isPinned()) { oldShortcut.setRank(0); - oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST - | ShortcutInfo.FLAG_CHOOSER); + oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST); if (disable) { oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED); } @@ -1133,8 +1115,8 @@ class ShortcutPackage extends ShortcutPackageItem { // Don't adjust ranks for manifest shortcuts. continue; } - // At this point, it must be dynamic or a chooser. - if (!si.isDynamicOrChooser()) { + // At this point, it must be dynamic. + if (!si.isDynamic()) { s.wtf("Non-dynamic shortcut found."); continue; } @@ -1311,7 +1293,7 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_FLAGS, si.getFlags() & ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES - | ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_CHOOSER)); + | ShortcutInfo.FLAG_DYNAMIC)); } else { // When writing for backup, ranks shouldn't be saved, since shortcuts won't be restored // as dynamic. @@ -1334,36 +1316,15 @@ class ShortcutPackage extends ShortcutPackageItem { } final Intent[] intentsNoExtras = si.getIntentsNoExtras(); final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases(); - if (intentsNoExtras != null) { - final int numIntents = intentsNoExtras.length; - for (int i = 0; i < numIntents; i++) { - out.startTag(null, TAG_INTENT); - ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); - ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); - out.endTag(null, TAG_INTENT); - } - } - ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); - - ShortcutService.writeTagExtra(out, TAG_CHOOSER_EXTRAS, si.getChooserExtras()); - - final IntentFilter[] intentFilters = si.getChooserIntentFilters(); - if (intentFilters != null) { - for (int i = 0; i < intentFilters.length; i++) { - out.startTag(null, TAG_CHOOSER_INTENT_FILTERS); - intentFilters[i].writeToXml(out); - out.endTag(null, TAG_CHOOSER_INTENT_FILTERS); - } + final int numIntents = intentsNoExtras.length; + for (int i = 0; i < numIntents; i++) { + out.startTag(null, TAG_INTENT); + ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); + ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); + out.endTag(null, TAG_INTENT); } - final ComponentName[] componentNames = si.getChooserComponentNames(); - if (componentNames != null) { - for (int i = 0; i < componentNames.length; i++) { - out.startTag(null, TAG_CHOOSER_COMPONENT_NAMES); - ShortcutService.writeAttr(out, ATTR_COMPONENT_NAMES, componentNames[i]); - out.endTag(null, TAG_CHOOSER_COMPONENT_NAMES); - } - } + ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); out.endTag(null, TAG_SHORTCUT); } @@ -1436,9 +1397,6 @@ class ShortcutPackage extends ShortcutPackageItem { String iconResName; String bitmapPath; ArraySet<String> categories = null; - PersistableBundle chooserExtras; - List<IntentFilter> chooserIntentFilters = new ArrayList<>(); - List<ComponentName> chooserComponentNames = new ArrayList<>(); id = ShortcutService.parseStringAttribute(parser, ATTR_ID); activityComponent = ShortcutService.parseComponentNameAttribute(parser, @@ -1499,18 +1457,6 @@ class ShortcutPackage extends ShortcutPackageItem { } } continue; - case TAG_CHOOSER_EXTRAS: - chooserExtras = PersistableBundle.restoreFromXml(parser); - continue; - case TAG_CHOOSER_COMPONENT_NAMES: - chooserComponentNames.add(ShortcutService.parseComponentNameAttribute(parser, - ATTR_ACTIVITY)); - continue; - case TAG_CHOOSER_INTENT_FILTERS: - IntentFilter toAdd = new IntentFilter(); - toAdd.readFromXml(parser); - chooserIntentFilters.add(toAdd); - continue; } throw ShortcutService.throwForInvalidTag(depth, tag); } @@ -1604,10 +1550,10 @@ class ShortcutPackage extends ShortcutPackageItem { // Verify each shortcut's status. for (int i = mShortcuts.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.valueAt(i); - if (!(si.isDeclaredInManifest() || si.isDynamicOrChooser() || si.isPinned())) { + if (!(si.isDeclaredInManifest() || si.isDynamic() || si.isPinned())) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() - + " is not manifest, dynamic, chooser or pinned."); + + " is not manifest, dynamic or pinned."); } if (si.isDeclaredInManifest() && si.isDynamic()) { failed = true; @@ -1649,11 +1595,6 @@ class ShortcutPackage extends ShortcutPackageItem { Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has a dummy target activity"); } - if (si.getIntent() == null && !si.isChooser()) { - failed = true; - Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() - + " has a null intent, but is not a chooser"); - } } if (failed) { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 9bf689527864..7c89e1ccb7c8 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -27,7 +27,6 @@ import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -65,7 +64,6 @@ import android.os.FileUtils; import android.os.Handler; import android.os.LocaleList; import android.os.Looper; -import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; @@ -1754,7 +1752,6 @@ public class ShortcutService extends IShortcutService.Stub { ps.clearAllImplicitRanks(); assignImplicitRanks(newShortcuts); - // TODO: Consider removing Chooser fields. If so, the FLAG_CHOOSER should be removed for (int i = 0; i < size; i++) { final ShortcutInfo source = newShortcuts.get(i); fixUpIncomingShortcutInfo(source, /* forUpdate= */ true); @@ -1794,13 +1791,6 @@ public class ShortcutService extends IShortcutService.Stub { if (replacingIcon || source.hasStringResources()) { fixUpShortcutResourceNamesAndValues(target); } - - // While updating, we keep the dynamic flag as it previously was, but refresh the - // chooser flag. - // TODO: If we support clearing Chooser fields, we should also remove the flag. - if (target.getChooserIntentFilters() != null) { - target.addFlags(ShortcutInfo.FLAG_CHOOSER); - } } // Lastly, adjust the ranks. @@ -1864,7 +1854,6 @@ public class ShortcutService extends IShortcutService.Stub { return true; } - // TODO: Ensure non-launchable shortcuts can not be pinned @Override public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut, IntentSender resultIntent, int userId) { @@ -2020,7 +2009,7 @@ public class ShortcutService extends IShortcutService.Stub { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - ShortcutInfo::isDynamicOrChooser); + ShortcutInfo::isDynamic); } } @@ -2213,14 +2202,6 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { throwIfUserLockedL(userId); - // For the chooser, we just check is the system is calling. - // STOPSHIP: We need to implement a new permission here rather than this terrible check. - // The packageName check is to try to distinguish between when an actual - // launcher is making the call, and when it's the system. - if (isCallerSystem() && packageName.equals("android")) { - return true; - } - final ShortcutUser user = getUserShortcutsLocked(userId); // Always trust the cached component. @@ -2393,7 +2374,7 @@ public class ShortcutService extends IShortcutService.Stub { public List<ShortcutInfo> getShortcuts(int launcherUserId, @NonNull String callingPackage, long changedSince, @Nullable String packageName, @Nullable List<String> shortcutIds, - @Nullable ComponentName componentName, @Nullable Intent intent, + @Nullable ComponentName componentName, int queryFlags, int userId) { final ArrayList<ShortcutInfo> ret = new ArrayList<>(); @@ -2415,13 +2396,13 @@ public class ShortcutService extends IShortcutService.Stub { if (packageName != null) { getShortcutsInnerLocked(launcherUserId, callingPackage, packageName, shortcutIds, changedSince, - componentName, intent, queryFlags, userId, ret, cloneFlag); + componentName, queryFlags, userId, ret, cloneFlag); } else { final List<String> shortcutIdsF = shortcutIds; getUserShortcutsLocked(userId).forAllPackages(p -> { getShortcutsInnerLocked(launcherUserId, callingPackage, p.getPackageName(), shortcutIdsF, changedSince, - componentName, intent, queryFlags, userId, ret, cloneFlag); + componentName, queryFlags, userId, ret, cloneFlag); }); } } @@ -2430,7 +2411,7 @@ public class ShortcutService extends IShortcutService.Stub { private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage, @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince, - @Nullable ComponentName componentName, Intent intent, int queryFlags, + @Nullable ComponentName componentName, int queryFlags, int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) { final ArraySet<String> ids = shortcutIds == null ? null : new ArraySet<>(shortcutIds); @@ -2455,15 +2436,6 @@ public class ShortcutService extends IShortcutService.Stub { return false; } } - if (intent != null - && !si.hasMatchingFilter(mContext.getContentResolver(), intent)) { - return false; - } - - if (((queryFlags & ShortcutQuery.FLAG_MATCH_CHOOSER) != 0) - && si.isChooser()) { - return true; - } if (((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0) && si.isDynamic()) { return true; @@ -3449,6 +3421,11 @@ public class ShortcutService extends IShortcutService.Stub { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; + dumpNoCheck(fd, pw, args); + } + + @VisibleForTesting + void dumpNoCheck(FileDescriptor fd, PrintWriter pw, String[] args) { boolean checkin = false; boolean clear = false; if (args != null) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index b507df0b8447..95fb5af37b60 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2945,6 +2945,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mStatusBar = win; mStatusBarController.setWindow(win); + setKeyguardOccludedLw(mKeyguardOccluded, true /* force */); break; case TYPE_NAVIGATION_BAR: mContext.enforceCallingOrSelfPermission( @@ -3832,7 +3833,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPendingKeyguardOccluded = occluded; mKeyguardOccludedChanged = true; } else { - setKeyguardOccludedLw(occluded); + setKeyguardOccludedLw(occluded, false /* force */); } } @@ -3841,7 +3842,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded=" + mPendingKeyguardOccluded); mKeyguardOccludedChanged = false; - if (setKeyguardOccludedLw(mPendingKeyguardOccluded)) { + if (setKeyguardOccludedLw(mPendingKeyguardOccluded, false /* force */)) { return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER; } } @@ -5254,11 +5255,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - // Don't allow snapshots to influence SystemUI visibility flags. - // TODO: Revisit this once SystemUI flags for snapshots are handled correctly boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type < FIRST_SYSTEM_WINDOW - && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0; + && attrs.type < FIRST_SYSTEM_WINDOW; final int stackId = win.getStackId(); if (mTopFullscreenOpaqueWindowState == null && visible) { if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) { @@ -5475,23 +5473,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { * * @return Whether the flags have changed and we have to redo the layout. */ - private boolean setKeyguardOccludedLw(boolean isOccluded) { + private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force) { if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded); boolean wasOccluded = mKeyguardOccluded; boolean showing = mKeyguardDelegate.isShowing(); if (wasOccluded && !isOccluded && showing) { mKeyguardOccluded = false; mKeyguardDelegate.setOccluded(false, true /* animate */); - mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD; - if (!mKeyguardDelegate.hasLockscreenWallpaper()) { - mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER; + if (mStatusBar != null) { + mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD; + if (!mKeyguardDelegate.hasLockscreenWallpaper()) { + mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER; + } } return true; } else if (!wasOccluded && isOccluded && showing) { mKeyguardOccluded = true; mKeyguardDelegate.setOccluded(true, false /* animate */); - mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD; - mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER; + if (mStatusBar != null) { + mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD; + mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER; + } return true; } else if (wasOccluded != isOccluded) { mKeyguardOccluded = isOccluded; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 9c4e700c87d3..a60dae7c7914 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2671,11 +2671,11 @@ public final class PowerManagerService extends SystemService public void run() { synchronized (this) { if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) { - ShutdownThread.rebootSafeMode(mContext, confirm); + ShutdownThread.rebootSafeMode(getUiContext(), confirm); } else if (haltMode == HALT_MODE_REBOOT) { - ShutdownThread.reboot(mContext, reason, confirm); + ShutdownThread.reboot(getUiContext(), reason, confirm); } else { - ShutdownThread.shutdown(mContext, reason, confirm); + ShutdownThread.shutdown(getUiContext(), reason, confirm); } } } diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 841e2a158c4f..864e83ef1f86 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -79,7 +79,7 @@ public final class ShutdownThread extends Thread { private static final int SHUTDOWN_VIBRATE_MS = 500; // state tracking - private static Object sIsStartedGuard = new Object(); + private static final Object sIsStartedGuard = new Object(); private static boolean sIsStarted = false; private static boolean mReboot; @@ -121,7 +121,8 @@ public final class ShutdownThread extends Thread { * state etc. Must be called from a Looper thread in which its UI * is shown. * - * @param context Context used to display the shutdown progress dialog. + * @param context Context used to display the shutdown progress dialog. This must be a context + * suitable for displaying UI (aka Themable). * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null. * @param confirm true if user confirmation is needed before shutting down. */ @@ -132,7 +133,11 @@ public final class ShutdownThread extends Thread { shutdownInner(context, confirm); } - static void shutdownInner(final Context context, boolean confirm) { + private static void shutdownInner(final Context context, boolean confirm) { + // ShutdownThread is called from many places, so best to verify here that the context passed + // in is themed. + context.assertRuntimeOverlayThemable(); + // ensure that only one thread is trying to power down. // any additional calls are just returned synchronized (sIsStartedGuard) { @@ -204,7 +209,8 @@ public final class ShutdownThread extends Thread { * state etc. Must be called from a Looper thread in which its UI * is shown. * - * @param context Context used to display the shutdown progress dialog. + * @param context Context used to display the shutdown progress dialog. This must be a context + * suitable for displaying UI (aka Themable). * @param reason code to pass to the kernel (e.g. "recovery"), or null. * @param confirm true if user confirmation is needed before shutting down. */ @@ -220,7 +226,8 @@ public final class ShutdownThread extends Thread { * Request a reboot into safe mode. Must be called from a Looper thread in which its UI * is shown. * - * @param context Context used to display the shutdown progress dialog. + * @param context Context used to display the shutdown progress dialog. This must be a context + * suitable for displaying UI (aka Themable). * @param confirm true if user confirmation is needed before shutting down. */ public static void rebootSafeMode(final Context context, boolean confirm) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 212bd61dbc9a..218d21826d93 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -16,6 +16,7 @@ package com.android.server.statusbar; +import android.app.ActivityThread; import android.app.StatusBarManager; import android.content.ComponentName; import android.content.Context; @@ -61,6 +62,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { private static final boolean SPEW = false; private final Context mContext; + private final WindowManagerService mWindowManager; private Handler mHandler = new Handler(); private NotificationDelegate mNotificationDelegate; @@ -777,10 +779,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub { long identity = Binder.clearCallingIdentity(); try { mHandler.post(() -> { + // ShutdownThread displays UI, so give it a UI context. + Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext(); if (safeMode) { - ShutdownThread.rebootSafeMode(mContext, false); + ShutdownThread.rebootSafeMode(uiContext, false); } else { - ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, false); + ShutdownThread.reboot(uiContext, PowerManager.SHUTDOWN_USER_REQUESTED, false); } }); } finally { diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java index 963a5723b433..40bb4961a2bf 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java +++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java @@ -17,6 +17,8 @@ package com.android.server.statusbar; import android.content.ComponentName; import android.os.RemoteException; import android.os.ShellCommand; +import android.service.quicksettings.TileService; + import com.android.internal.statusbar.IStatusBarService; import java.io.PrintWriter; @@ -48,6 +50,10 @@ public class StatusBarShellCommand extends ShellCommand { return runRemoveTile(); case "click-tile": return runClickTile(); + case "check-support": + final PrintWriter pw = getOutPrintWriter(); + pw.println(String.valueOf(TileService.isQuickSettingsSupported())); + return 0; default: return handleDefaultCommands(cmd); } @@ -113,5 +119,8 @@ public class StatusBarShellCommand extends ShellCommand { pw.println(" click-tile COMPONENT"); pw.println(" Click on a TileService of the specified component"); pw.println(""); + pw.println(" check-support"); + pw.println(" Check if this device supports QS + APIs"); + pw.println(""); } } diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 4b4be40880ee..2bc3c5f9abba 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -566,7 +566,7 @@ public class AppWindowContainerController return false; } - mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot()); + mContainer.startingData = new SnapshotStartingData(mService, snapshot); scheduleAddStartingWindow(); return true; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 3c68e4ff4e7f..4ebf1fcb7206 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -180,11 +180,23 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // Mapping from a token IBinder to a WindowToken object on this display. private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap(); + // Initial display metrics. int mInitialDisplayWidth = 0; int mInitialDisplayHeight = 0; int mInitialDisplayDensity = 0; + + /** + * Overridden display size. Initialized with {@link #mInitialDisplayWidth} + * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size". + * @see WindowManagerService#setForcedDisplaySize(int, int, int) + */ int mBaseDisplayWidth = 0; int mBaseDisplayHeight = 0; + /** + * Overridden display density for current user. Initialized with {@link #mInitialDisplayDensity} + * but can be set from Settings or via shell command "adb shell wm density". + * @see WindowManagerService#setForcedDisplayDensityForUser(int, int, int) + */ int mBaseDisplayDensity = 0; boolean mDisplayScalingDisabled; private final DisplayInfo mDisplayInfo = new DisplayInfo(); @@ -1497,8 +1509,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void updateDisplayInfo() { + // Check if display metrics changed and update base values if needed. + updateBaseDisplayMetricsIfNeeded(); + mDisplay.getDisplayInfo(mDisplayInfo); mDisplay.getMetrics(mDisplayMetrics); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { mTaskStackContainers.get(i).updateDisplayInfo(null); } @@ -1514,10 +1530,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } - mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth; - mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight; - mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi; - mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight); + updateBaseDisplayMetrics(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, + mDisplayInfo.logicalDensityDpi); + mInitialDisplayWidth = mDisplayInfo.logicalWidth; + mInitialDisplayHeight = mDisplayInfo.logicalHeight; + mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi; } void getLogicalDisplayRect(Rect out) { @@ -1547,6 +1564,42 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + /** + * If display metrics changed, overrides are not set and it's not just a rotation - update base + * values. + */ + private void updateBaseDisplayMetricsIfNeeded() { + // Get real display metrics without overrides from WM. + mService.mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mDisplayInfo); + final int orientation = mDisplayInfo.rotation; + final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270); + final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth; + final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight; + final int newDensity = mDisplayInfo.logicalDensityDpi; + + final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth + || mInitialDisplayHeight != newHeight + || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi; + + if (displayMetricsChanged) { + // Check if display size or density is forced. + final boolean isDisplaySizeForced = mBaseDisplayWidth != mInitialDisplayWidth + || mBaseDisplayHeight != mInitialDisplayHeight; + final boolean isDisplayDensityForced = mBaseDisplayDensity != mInitialDisplayDensity; + + // If there is an override set for base values - use it, otherwise use new values. + updateBaseDisplayMetrics(isDisplaySizeForced ? mBaseDisplayWidth : newWidth, + isDisplaySizeForced ? mBaseDisplayHeight : newHeight, + isDisplayDensityForced ? mBaseDisplayDensity : newDensity); + + // Real display metrics changed, so we should also update initial values. + mInitialDisplayWidth = newWidth; + mInitialDisplayHeight = newHeight; + mInitialDisplayDensity = newDensity; + mService.reconfigureDisplayLocked(this); + } + } + /** Sets the maximum width the screen resolution can be */ void setMaxUiWidth(int width) { if (DEBUG_DISPLAY) { @@ -2867,7 +2920,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (stack != null) { stack.getBounds(frame); } - } else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) { + + // We want to screenshot with the exact bounds of the surface of the app. Thus, + // intersect it with the frame. + frame.intersect(w.mFrame); + }else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) { final Rect wf = w.mFrame; final Rect cr = w.mContentInsets; int left = wf.left + cr.left; diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java index e73d4d2559fb..35f35db5ada3 100644 --- a/services/core/java/com/android/server/wm/SnapshotStartingData.java +++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import android.app.ActivityManager.TaskSnapshot; import android.graphics.GraphicBuffer; import android.view.WindowManagerPolicy.StartingSurface; @@ -25,9 +26,9 @@ import android.view.WindowManagerPolicy.StartingSurface; class SnapshotStartingData extends StartingData { private final WindowManagerService mService; - private final GraphicBuffer mSnapshot; + private final TaskSnapshot mSnapshot; - SnapshotStartingData(WindowManagerService service, GraphicBuffer snapshot) { + SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) { super(service); mService = service; mSnapshot = snapshot; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 3ffb093ba386..b816d8199aa6 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -17,15 +17,14 @@ package com.android.server.wm; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; -import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; +import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static com.android.server.EventLogTags.WM_TASK_REMOVED; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -40,7 +39,6 @@ import android.view.DisplayInfo; import android.view.Surface; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.EventLogTags; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index b8d0b8c096fe..48b01f40fc65 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -28,6 +28,7 @@ import android.app.ActivityManager.StackId; import android.app.ActivityManager.TaskSnapshot; import android.graphics.Canvas; import android.graphics.GraphicBuffer; +import android.graphics.Rect; import android.os.Environment; import android.util.ArraySet; import android.view.WindowManagerPolicy.StartingSurface; @@ -152,7 +153,7 @@ class TaskSnapshotController { * MANAGER LOCK WHEN CALLING THIS METHOD! */ StartingSurface createStartingSurface(AppWindowToken token, - GraphicBuffer snapshot) { + TaskSnapshot snapshot) { return TaskSnapshotSurface.create(mService, token, snapshot); } @@ -166,8 +167,17 @@ class TaskSnapshotController { if (buffer == null) { return null; } + final WindowState mainWindow = top.findMainWindow(); return new TaskSnapshot(buffer, top.getConfiguration().orientation, - top.findMainWindow().mStableInsets, false /* reduced */, 1f /* scale */); + minRect(mainWindow.mContentInsets, mainWindow.mStableInsets), false /* reduced */, + 1f /* scale */); + } + + private Rect minRect(Rect rect1, Rect rect2) { + return new Rect(Math.min(rect1.left, rect2.left), + Math.min(rect1.top, rect2.top), + Math.min(rect1.right, rect2.right), + Math.min(rect1.bottom, rect2.bottom)); } /** diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 04403e2712c1..1591e480af4f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -16,20 +16,35 @@ package com.android.server.wm; -import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; -import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.graphics.Color.WHITE; +import static android.graphics.Color.alpha; +import static android.view.SurfaceControl.HIDDEN; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; +import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; +import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES; +import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; +import static android.view.WindowManager.LayoutParams.FLAG_SCALED; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; +import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; +import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; +import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES; +import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; +import static com.android.internal.policy.DecorView.getColorViewLeftInset; +import static com.android.internal.policy.DecorView.getColorViewTopInset; +import static com.android.internal.policy.DecorView.getNavigationBarRect; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.ActivityManager.TaskDescription; -import android.graphics.Bitmap; +import android.app.ActivityManager.TaskSnapshot; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.GraphicBuffer; import android.graphics.Paint; import android.graphics.Rect; @@ -37,17 +52,22 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.SystemClock; import android.util.MergedConfiguration; import android.util.Slog; import android.view.IWindowSession; import android.view.Surface; +import android.view.SurfaceControl; +import android.view.SurfaceSession; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy.StartingSurface; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.policy.DecorView; import com.android.internal.view.BaseIWindow; /** @@ -57,19 +77,57 @@ import com.android.internal.view.BaseIWindow; */ class TaskSnapshotSurface implements StartingSurface { + private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450; + + /** + * When creating the starting window, we use the exact same layout flags such that we end up + * with a window with the exact same dimensions etc. However, these flags are not used in layout + * and might cause other side effects so we exclude them. + */ + private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE + | FLAG_NOT_TOUCHABLE + | FLAG_NOT_TOUCH_MODAL + | FLAG_ALT_FOCUSABLE_IM + | FLAG_NOT_FOCUSABLE + | FLAG_HARDWARE_ACCELERATED + | FLAG_IGNORE_CHEEK_PRESSES + | FLAG_LOCAL_FOCUS_MODE + | FLAG_SLIPPERY + | FLAG_WATCH_OUTSIDE_TOUCH + | FLAG_SPLIT_TOUCH + | FLAG_SCALED + | FLAG_SECURE; + private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM; private static final int MSG_REPORT_DRAW = 0; private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s"; private final Window mWindow; private final Surface mSurface; + private SurfaceControl mChildSurfaceControl; private final IWindowSession mSession; private final WindowManagerService mService; + private final Rect mTaskBounds; + private final Rect mStableInsets = new Rect(); + private final Rect mContentInsets = new Rect(); + private final Rect mFrame = new Rect(); + private final TaskSnapshot mSnapshot; + private final CharSequence mTitle; private boolean mHasDrawn; private boolean mReportNextDraw; - private Paint mFillBackgroundPaint = new Paint(); + private long mShownTime; + private final Handler mHandler; + private final boolean mSizeMismatch; + private final Paint mBackgroundPaint = new Paint(); + private final Paint mStatusBarPaint = new Paint(); + private final Paint mNavigationBarPaint = new Paint(); + private final int mStatusBarColor; + private final int mNavigationBarColor; + private final int mSysUiVis; + private final int mWindowFlags; + private final int mWindowPrivateFlags; static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token, - GraphicBuffer snapshot) { + TaskSnapshot snapshot) { final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); final Window window = new Window(); @@ -78,32 +136,51 @@ class TaskSnapshotSurface implements StartingSurface { final Surface surface = new Surface(); final Rect tmpRect = new Rect(); final Rect tmpFrame = new Rect(); + final Rect taskBounds; + final Rect tmpContentInsets = new Rect(); + final Rect tmpStableInsets = new Rect(); final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration(); - int fillBackgroundColor = Color.WHITE; + int backgroundColor = WHITE; + int statusBarColor = 0; + int navigationBarColor = 0; + final int sysUiVis; + final int windowFlags; + final int windowPrivateFlags; synchronized (service.mWindowMap) { + final WindowState mainWindow = token.findMainWindow(); + if (mainWindow == null) { + Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token=" + + token); + return null; + } + sysUiVis = mainWindow.getSystemUiVisibility(); + windowFlags = mainWindow.getAttrs().flags; + windowPrivateFlags = mainWindow.getAttrs().privateFlags; + layoutParams.type = TYPE_APPLICATION_STARTING; - layoutParams.format = snapshot.getFormat(); - layoutParams.flags = FLAG_LAYOUT_INSET_DECOR - | FLAG_LAYOUT_IN_SCREEN + layoutParams.format = snapshot.getSnapshot().getFormat(); + layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES) | FLAG_NOT_FOCUSABLE - | FLAG_NOT_TOUCHABLE - | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + | FLAG_NOT_TOUCHABLE; layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT; layoutParams.token = token.token; layoutParams.width = LayoutParams.MATCH_PARENT; layoutParams.height = LayoutParams.MATCH_PARENT; - - // TODO: Inherit behavior whether to draw behind status bar/nav bar. - layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + layoutParams.systemUiVisibility = sysUiVis; final Task task = token.getTask(); if (task != null) { - layoutParams.setTitle(String.format(TITLE_FORMAT,task.mTaskId)); + layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId)); final TaskDescription taskDescription = task.getTaskDescription(); if (taskDescription != null) { - fillBackgroundColor = taskDescription.getBackgroundColor(); + backgroundColor = taskDescription.getBackgroundColor(); + statusBarColor = taskDescription.getStatusBarColor(); + navigationBarColor = taskDescription.getNavigationBarColor(); } + taskBounds = new Rect(); + task.getBounds(taskBounds); + } else { + taskBounds = null; } } try { @@ -118,31 +195,57 @@ class TaskSnapshotSurface implements StartingSurface { // Local call. } final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window, - surface, fillBackgroundColor); + surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor, + navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds); window.setOuter(snapshotSurface); try { session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame, - tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpMergedConfiguration, - surface); + tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect, + tmpMergedConfiguration, surface); } catch (RemoteException e) { // Local call. } - snapshotSurface.drawSnapshot(snapshot); + snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets); + snapshotSurface.drawSnapshot(); return snapshotSurface; } @VisibleForTesting TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface, - int fillBackgroundColor) { + TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor, + int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags, + Rect taskBounds) { mService = service; + mHandler = new Handler(mService.mH.getLooper()); mSession = WindowManagerGlobal.getWindowSession(); mWindow = window; mSurface = surface; - mFillBackgroundPaint.setColor(fillBackgroundColor); + mSnapshot = snapshot; + mTitle = title; + mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE); + mTaskBounds = taskBounds; + mSysUiVis = sysUiVis; + mWindowFlags = windowFlags; + mWindowPrivateFlags = windowPrivateFlags; + mSizeMismatch = (mFrame.width() != snapshot.getSnapshot().getWidth() + || mFrame.height() != snapshot.getSnapshot().getHeight()); + mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags, + service.mContext.getColor(R.color.system_bar_background_semi_transparent), + statusBarColor); + mNavigationBarColor = navigationBarColor; + mStatusBarPaint.setColor(mStatusBarColor); + mNavigationBarPaint.setColor(navigationBarColor); } @Override public void remove() { + synchronized (mService.mWindowMap) { + final long now = SystemClock.uptimeMillis(); + if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) { + mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS); + return; + } + } try { mSession.remove(mWindow); } catch (RemoteException e) { @@ -150,31 +253,149 @@ class TaskSnapshotSurface implements StartingSurface { } } - private void drawSnapshot(GraphicBuffer snapshot) { - mSurface.attachAndQueueBuffer(snapshot); + @VisibleForTesting + void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) { + mFrame.set(frame); + mContentInsets.set(contentInsets); + mStableInsets.set(stableInsets); + } + + private void drawSnapshot() { + final GraphicBuffer buffer = mSnapshot.getSnapshot(); + if (mSizeMismatch) { + // The dimensions of the buffer and the window don't match, so attaching the buffer + // will fail. Better create a child window with the exact dimensions and fill the parent + // window with the background color! + drawSizeMismatchSnapshot(buffer); + } else { + drawSizeMatchSnapshot(buffer); + } final boolean reportNextDraw; synchronized (mService.mWindowMap) { + mShownTime = SystemClock.uptimeMillis(); mHasDrawn = true; reportNextDraw = mReportNextDraw; } if (reportNextDraw) { reportDrawn(); } + } + + private void drawSizeMatchSnapshot(GraphicBuffer buffer) { + mSurface.attachAndQueueBuffer(buffer); + mSurface.release(); + } + + private void drawSizeMismatchSnapshot(GraphicBuffer buffer) { + final SurfaceSession session = new SurfaceSession(mSurface); + + // Keep a reference to it such that it doesn't get destroyed when finalized. + mChildSurfaceControl = new SurfaceControl(session, + mTitle + " - task-snapshot-surface", + buffer.getWidth(), buffer.getHeight(), buffer.getFormat(), HIDDEN); + Surface surface = new Surface(); + surface.copyFrom(mChildSurfaceControl); + + // Clip off ugly navigation bar. + final Rect crop = calculateSnapshotCrop(); + final Rect frame = calculateSnapshotFrame(crop); + SurfaceControl.openTransaction(); + try { + // We can just show the surface here as it will still be hidden as the parent is + // still hidden. + mChildSurfaceControl.show(); + mChildSurfaceControl.setWindowCrop(crop); + mChildSurfaceControl.setPosition(frame.left, frame.top); + } finally { + SurfaceControl.closeTransaction(); + } + surface.attachAndQueueBuffer(buffer); + surface.release(); + + final Canvas c = mSurface.lockCanvas(null); + drawBackgroundAndBars(c, frame); + mSurface.unlockCanvasAndPost(c); mSurface.release(); } @VisibleForTesting - void fillEmptyBackground(Canvas c, Bitmap b) { - final boolean fillHorizontally = c.getWidth() > b.getWidth(); - final boolean fillVertically = c.getHeight() > b.getHeight(); + Rect calculateSnapshotCrop() { + final Rect rect = new Rect(); + rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight()); + final Rect insets = mSnapshot.getContentInsets(); + + // Let's remove all system decorations except the status bar, but only if the task is at the + // very top of the screen. + rect.inset(insets.left, mTaskBounds.top != 0 ? insets.top : 0, insets.right, insets.bottom); + return rect; + } + + @VisibleForTesting + Rect calculateSnapshotFrame(Rect crop) { + final Rect frame = new Rect(crop); + + // By default, offset it to to top/left corner + frame.offsetTo(-crop.left, -crop.top); + + // However, we also need to make space for the navigation bar on the left side. + final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left, + mContentInsets.left); + frame.offset(colorViewLeftInset, 0); + return frame; + } + + @VisibleForTesting + void drawBackgroundAndBars(Canvas c, Rect frame) { + final int statusBarHeight = getStatusBarColorViewHeight(); + final boolean fillHorizontally = c.getWidth() > frame.right; + final boolean fillVertically = c.getHeight() > frame.bottom; if (fillHorizontally) { - c.drawRect(b.getWidth(), 0, c.getWidth(), fillVertically - ? b.getHeight() - : c.getHeight(), - mFillBackgroundPaint); + c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0, + c.getWidth(), fillVertically + ? frame.bottom + : c.getHeight(), + mBackgroundPaint); } if (fillVertically) { - c.drawRect(0, b.getHeight(), c.getWidth(), c.getHeight(), mFillBackgroundPaint); + c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint); + } + drawStatusBarBackground(c, frame, statusBarHeight); + drawNavigationBarBackground(c); + } + + private int getStatusBarColorViewHeight() { + final boolean forceStatusBarBackground = + (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0; + if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible( + mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) { + return getColorViewTopInset(mStableInsets.top, mContentInsets.top); + } else { + return 0; + } + } + + private boolean isNavigationBarColorViewVisible() { + return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible( + mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */); + } + + @VisibleForTesting + void drawStatusBarBackground(Canvas c, Rect frame, int statusBarHeight) { + if (statusBarHeight > 0 && c.getWidth() > frame.right) { + final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right, + mContentInsets.right); + c.drawRect(frame.right, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint); + } + } + + @VisibleForTesting + void drawNavigationBarBackground(Canvas c) { + final Rect navigationBarRect = new Rect(); + getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets, + navigationBarRect); + final boolean visible = isNavigationBarColorViewVisible(); + if (visible && !navigationBarRect.isEmpty()) { + c.drawRect(navigationBarRect, mNavigationBarPaint); } } @@ -211,10 +432,10 @@ class TaskSnapshotSurface implements StartingSurface { } }; - private static class Window extends BaseIWindow { + @VisibleForTesting + static class Window extends BaseIWindow { private TaskSnapshotSurface mOuter; - public void setOuter(TaskSnapshotSurface outer) { mOuter = outer; } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 57fb81ce0b2d..57eaa2b2ad8d 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -17,17 +17,15 @@ package com.android.server.wm; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; 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; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION; -import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE; import android.content.Context; +import android.os.Handler; import android.os.Trace; import android.util.Slog; import android.util.SparseArray; @@ -36,6 +34,9 @@ import android.view.Choreographer; import android.view.SurfaceControl; import android.view.WindowManagerPolicy; +import com.android.internal.view.SurfaceFlingerVsyncChoreographer; +import com.android.server.DisplayThread; + import java.io.PrintWriter; /** @@ -82,20 +83,31 @@ public class WindowAnimator { // check if some got replaced and can be removed. private boolean mRemoveReplacedWindows = false; + private long mCurrentFrameTime; + private final Runnable mAnimationTick; + private final SurfaceFlingerVsyncChoreographer mSfChoreographer; + WindowAnimator(final WindowManagerService service) { mService = service; mContext = service.mContext; mPolicy = service.mPolicy; mWindowPlacerLocked = service.mWindowPlacerLocked; - - mAnimationFrameCallback = new Choreographer.FrameCallback() { - public void doFrame(long frameTimeNs) { - synchronized (mService.mWindowMap) { - mService.mAnimationScheduled = false; - animateLocked(frameTimeNs); - } + final Handler handler = DisplayThread.getHandler(); + + // TODO: Multi-display: If displays have different vsync tick, have a separate tick per + // display. + mSfChoreographer = new SurfaceFlingerVsyncChoreographer(handler, + mService.getDefaultDisplayContentLocked().getDisplay()); + mAnimationTick = () -> { + synchronized (mService.mWindowMap) { + mService.mAnimationScheduled = false; + animateLocked(mCurrentFrameTime); } }; + mAnimationFrameCallback = frameTimeNs -> { + mCurrentFrameTime = frameTimeNs; + mSfChoreographer.scheduleAtSfVsync(mAnimationTick); + }; } void addDisplayLocked(final int displayId) { diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java index 84ffc35b4651..c4a68377bc36 100644 --- a/services/core/java/com/android/server/wm/WindowContainerController.java +++ b/services/core/java/com/android/server/wm/WindowContainerController.java @@ -33,7 +33,7 @@ class WindowContainerController<E extends WindowContainer, I extends WindowConta final WindowManagerService mService; final RootWindowContainer mRoot; - final HashMap<IBinder, WindowState> mWindowMap; + final WindowHashMap mWindowMap; // The window container this controller owns. E mContainer; diff --git a/services/core/java/com/android/server/wm/WindowHashMap.java b/services/core/java/com/android/server/wm/WindowHashMap.java new file mode 100644 index 000000000000..49bba4145996 --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowHashMap.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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 android.os.IBinder; + +import java.util.HashMap; + +/** + * Subclass of HashMap such that we can instruct the compiler to boost our thread priority when + * locking this class. See makefile. + */ +class WindowHashMap extends HashMap<IBinder, WindowState> { +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 95fbbb89a649..1be051270e16 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.Manifest.permission.MANAGE_APP_TOKENS; +import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; @@ -25,6 +26,11 @@ import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_USER_HANDLE; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SHELL_UID; +import static android.os.Process.SYSTEM_UID; +import static android.os.Process.THREAD_PRIORITY_DISPLAY; +import static android.os.Process.myPid; import static android.os.UserHandle.USER_NULL; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.DOCKED_INVALID; @@ -60,6 +66,8 @@ import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.LockGuard.INDEX_WINDOW; +import static com.android.server.LockGuard.installLock; import static com.android.server.wm.AppTransition.TRANSIT_UNSET; import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END; import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START; @@ -102,6 +110,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManagerInternal; +import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.IActivityManager; import android.content.BroadcastReceiver; @@ -124,7 +133,6 @@ import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.input.InputManager; import android.net.Uri; -import android.os.PowerSaveState; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -138,7 +146,7 @@ import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.PowerManagerInternal; -import android.os.Process; +import android.os.PowerSaveState; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; @@ -150,10 +158,10 @@ import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; import android.util.ArraySet; -import android.util.MergedConfiguration; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; +import android.util.MergedConfiguration; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -214,7 +222,7 @@ import com.android.server.DisplayThread; import com.android.server.EventLogTags; import com.android.server.FgThread; import com.android.server.LocalServices; -import com.android.server.LockGuard; +import com.android.server.ThreadPriorityBooster; import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.input.InputManagerService; @@ -238,10 +246,7 @@ import java.net.Socket; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; - -import static android.Manifest.permission.READ_FRAME_BUFFER; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { @@ -407,7 +412,7 @@ public class WindowManagerService extends IWindowManager.Stub * This is also used as the lock for all of our state. * NOTE: Never call into methods that lock ActivityManagerService while holding this object. */ - final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>(); + final WindowHashMap mWindowMap = new WindowHashMap(); /** * List of window tokens that have finished starting their application, @@ -847,6 +852,16 @@ public class WindowManagerService extends IWindowManager.Stub // since they won't be notified through the app window animator. final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>(); + private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster( + THREAD_PRIORITY_DISPLAY, INDEX_WINDOW); + + static void boostPriorityForLockedSection() { + sThreadPriorityBooster.boost(); + } + + static void resetPriorityAfterLockedSection() { + sThreadPriorityBooster.reset(); + } void openSurfaceTransaction() { synchronized (mWindowMap) { @@ -935,7 +950,7 @@ public class WindowManagerService extends IWindowManager.Stub private WindowManagerService(Context context, InputManagerService inputManager, boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy) { - LockGuard.installLock(this, LockGuard.INDEX_WINDOW); + installLock(this, INDEX_WINDOW); mRoot = new RootWindowContainer(this); mContext = context; mHaveInputMethods = haveInputMethods; @@ -1580,7 +1595,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void enableSurfaceTrace(ParcelFileDescriptor pfd) { final int callingUid = Binder.getCallingUid(); - if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { + if (callingUid != SHELL_UID && callingUid != ROOT_UID) { throw new SecurityException("Only shell can call enableSurfaceTrace"); } @@ -1592,8 +1607,8 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void disableSurfaceTrace() { final int callingUid = Binder.getCallingUid(); - if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID && - callingUid != Process.SYSTEM_UID) { + if (callingUid != SHELL_UID && callingUid != ROOT_UID && + callingUid != SYSTEM_UID) { throw new SecurityException("Only shell can call disableSurfaceTrace"); } synchronized (mWindowMap) { @@ -1607,7 +1622,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setScreenCaptureDisabled(int userId, boolean disabled) { int callingUid = Binder.getCallingUid(); - if (callingUid != Process.SYSTEM_UID) { + if (callingUid != SYSTEM_UID) { throw new SecurityException("Only system can call setScreenCaptureDisabled."); } @@ -2263,7 +2278,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean checkCallingPermission(String permission, String func) { // Quick check: if the calling permission is me, it's all okay. - if (Binder.getCallingPid() == Process.myPid()) { + if (Binder.getCallingPid() == myPid()) { return true; } @@ -2916,7 +2931,7 @@ public class WindowManagerService extends IWindowManager.Stub } // If this isn't coming from the system then don't allow disabling the lockscreen // to bypass security. - if (Binder.getCallingUid() != Process.SYSTEM_UID && isKeyguardSecure()) { + if (Binder.getCallingUid() != SYSTEM_UID && isKeyguardSecure()) { Log.d(TAG_WM, "current mode is SecurityMode, ignore disableKeyguard"); return; } @@ -3196,19 +3211,25 @@ public class WindowManagerService extends IWindowManager.Stub // Called by window manager policy. Not exposed externally. @Override public void shutdown(boolean confirm) { - ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); + // Pass in the UI context, since ShutdownThread requires it (to show UI). + ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(), + PowerManager.SHUTDOWN_USER_REQUESTED, confirm); } // Called by window manager policy. Not exposed externally. @Override public void reboot(boolean confirm) { - ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); + // Pass in the UI context, since ShutdownThread requires it (to show UI). + ShutdownThread.reboot(ActivityThread.currentActivityThread().getSystemUiContext(), + PowerManager.SHUTDOWN_USER_REQUESTED, confirm); } // Called by window manager policy. Not exposed externally. @Override public void rebootSafeMode(boolean confirm) { - ShutdownThread.rebootSafeMode(mContext, confirm); + // Pass in the UI context, since ShutdownThread requires it (to show UI). + ShutdownThread.rebootSafeMode(ActivityThread.currentActivityThread().getSystemUiContext(), + confirm); } public void setCurrentProfileIds(final int[] currentProfileIds) { @@ -5312,8 +5333,8 @@ public class WindowManagerService extends IWindowManager.Stub if (displayContent.mBaseDisplayWidth != width || displayContent.mBaseDisplayHeight != height) { Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height); - displayContent.mBaseDisplayWidth = width; - displayContent.mBaseDisplayHeight = height; + displayContent.updateBaseDisplayMetrics(width, height, + displayContent.mBaseDisplayDensity); } } catch (NumberFormatException ex) { } @@ -5338,8 +5359,7 @@ public class WindowManagerService extends IWindowManager.Stub // displayContent must not be null private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) { Slog.i(TAG_WM, "Using new display size: " + width + "x" + height); - displayContent.mBaseDisplayWidth = width; - displayContent.mBaseDisplayHeight = height; + displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity); reconfigureDisplayLocked(displayContent); } @@ -7052,7 +7072,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalStateException("Magnification callbacks not set!"); } } - if (Binder.getCallingPid() != android.os.Process.myPid()) { + if (Binder.getCallingPid() != myPid()) { spec.recycle(); } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 6fd95a4d4a4f..8098eeaa3c11 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2395,6 +2395,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (requestAnim) { mService.scheduleAnimationLocked(); } + if ((mAttrs.flags & FLAG_NOT_FOCUSABLE) == 0) { + mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateImWindows */); + } return true; } @@ -2437,6 +2440,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (requestAnim) { mService.scheduleAnimationLocked(); } + if (mService.mCurrentFocus == this) { + mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateImWindows */); + } return true; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java new file mode 100644 index 000000000000..97fa9d552142 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2017 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.devicepolicy; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.admin.DevicePolicyManager; +import android.app.admin.IDeviceAdminService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ParceledListSlice; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.BackgroundThread; +import com.android.server.am.PersistentConnection; + +import java.io.PrintWriter; +import java.util.List; + +/** + * Manages connections to persistent services in owner packages. + */ +public class DeviceAdminServiceController { + static final String TAG = DevicePolicyManagerService.LOG_TAG; + + static final boolean DEBUG = false; // DO NOT MERGE WITH TRUE. + + final Object mLock = new Object(); + final Context mContext; + + private final DevicePolicyManagerService mService; + private final DevicePolicyManagerService.Injector mInjector; + + private final Handler mHandler; // needed? + + static void debug(String format, Object... args) { + if (!DEBUG) { + return; + } + Slog.d(TAG, String.format(format, args)); + } + + private class DevicePolicyServiceConnection + extends PersistentConnection<IDeviceAdminService> { + public DevicePolicyServiceConnection(int userId, @NonNull ComponentName componentName) { + super(TAG, mContext, mHandler, userId, componentName); + } + + @Override + protected IDeviceAdminService asInterface(IBinder binder) { + return IDeviceAdminService.Stub.asInterface(binder); + } + } + + /** + * User-ID -> {@link PersistentConnection}. + */ + @GuardedBy("mLock") + private final SparseArray<DevicePolicyServiceConnection> mConnections = new SparseArray<>(); + + public DeviceAdminServiceController(DevicePolicyManagerService service) { + mService = service; + mInjector = service.mInjector; + mContext = mInjector.mContext; + mHandler = new Handler(BackgroundThread.get().getLooper()); + } + + /** + * Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} + * in a given package. + */ + @Nullable + private ServiceInfo findService(@NonNull String packageName, int userId) { + final Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE); + intent.setPackage(packageName); + + try { + final ParceledListSlice<ResolveInfo> pls = mInjector.getIPackageManager() + .queryIntentServices(intent, null, /* flags=*/ 0, userId); + if (pls == null) { + return null; + } + final List<ResolveInfo> list = pls.getList(); + if (list.size() == 0) { + return null; + } + // Note if multiple services are found, that's an error, even if only one of them + // is exported. + if (list.size() > 1) { + Log.e(TAG, "More than one DeviceAdminService's found in package " + + packageName + + ". They'll all be ignored."); + return null; + } + final ServiceInfo si = list.get(0).serviceInfo; + if (si.exported) { + Log.e(TAG, "DeviceAdminService must not be exported: '" + + si.getComponentName().flattenToShortString() + + "' will be ignored."); + return null; + } + return si; + } catch (RemoteException e) { + } + return null; + } + + /** + * Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} + * in an owner package and connect to it. + */ + public void startServiceForOwner(@NonNull String packageName, int userId, + @NonNull String actionForLog) { + final long token = mInjector.binderClearCallingIdentity(); + try { + synchronized (mLock) { + final ServiceInfo service = findService(packageName, userId); + if (service == null) { + debug("Owner package %s on u%d has no service.", + packageName, userId); + disconnectServiceOnUserLocked(userId, actionForLog); + return; + } + // See if it's already running. + final PersistentConnection<IDeviceAdminService> existing = + mConnections.get(userId); + if (existing != null) { + if (existing.getComponentName().equals(service.getComponentName())) { + return; + } + disconnectServiceOnUserLocked(userId, actionForLog); + } + + debug("Owner package %s on u%d has service %s for %s", + packageName, userId, + service.getComponentName().flattenToShortString(), actionForLog); + + final DevicePolicyServiceConnection conn = + new DevicePolicyServiceConnection( + userId, service.getComponentName()); + mConnections.put(userId, conn); + conn.connect(); + } + } finally { + mInjector.binderRestoreCallingIdentity(token); + } + } + + /** + * Stop an owner service on a given user. + */ + public void stopServiceForOwner(int userId, @NonNull String actionForLog) { + final long token = mInjector.binderClearCallingIdentity(); + try { + synchronized (mLock) { + disconnectServiceOnUserLocked(userId, actionForLog); + } + } finally { + mInjector.binderRestoreCallingIdentity(token); + } + } + + private void disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog) { + final DevicePolicyServiceConnection conn = mConnections.get(userId); + if (conn != null) { + debug("Stopping service for u%d if already running for %s.", + userId, actionForLog); + conn.disconnect(); + mConnections.remove(userId); + } + } + + public void dump(String prefix, PrintWriter pw) { + synchronized (mLock) { + if (mConnections.size() == 0) { + return; + } + pw.println(); + pw.print(prefix); pw.println("Owner Services:"); + for (int i = 0; i < mConnections.size(); i++) { + final int userId = mConnections.keyAt(i); + pw.print(prefix); pw.print(" "); pw.print("User: "); pw.println(userId); + + final DevicePolicyServiceConnection con = mConnections.valueAt(i); + con.dump(prefix + " ", pw); + } + } + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6f49324bfc56..bfa1b9988b2f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -140,7 +140,6 @@ import android.os.storage.StorageManager; import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; import android.provider.Settings; -import android.security.Credentials; import android.security.IKeyChainAliasCallback; import android.security.IKeyChainService; import android.security.KeyChain; @@ -194,7 +193,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.text.DateFormat; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -365,6 +363,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final UserManagerInternal mUserManagerInternal; final TelephonyManager mTelephonyManager; private final LockPatternUtils mLockPatternUtils; + private final DeviceAdminServiceController mDeviceAdminServiceController; /** * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p @@ -459,7 +458,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void onStartUser(int userHandle) { - mService.onStartUser(userHandle); + mService.handleStartUser(userHandle); + } + + @Override + public void onUnlockUser(int userHandle) { + mService.handleUnlockUser(userHandle); + } + + @Override + public void onStopUser(int userHandle) { + mService.handleStopUser(userHandle); } } @@ -1420,7 +1429,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void handlePackagesChanged(String packageName, int userHandle) { + private void handlePackagesChanged(@Nullable String packageName, int userHandle) { boolean removedAdmin = false; if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); DevicePolicyData policy = getUserData(userHandle); @@ -1434,9 +1443,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (packageName == null || packageName.equals(adminPackage)) { if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null || mIPackageManager.getReceiverInfo(aa.info.getComponent(), - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userHandle) == null) { + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, + userHandle) == null) { removedAdmin = true; policy.mAdminList.remove(i); policy.mAdminMap.remove(aa.info.getComponent()); @@ -1461,6 +1470,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + // If it's an owner package, we may need to refresh the bound connection. + final ComponentName owner = getOwnerComponent(userHandle); + if ((packageName != null) && (owner != null) + && (owner.getPackageName().equals(packageName))) { + startOwnerService(userHandle, "package-broadcast"); + } + // Persist updates if the removed package was an admin or delegate. if (removedAdmin || removedDelegate) { saveSettingsLocked(policy.mUserHandle); @@ -1791,6 +1807,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Needed when mHasFeature == false, because it controls the certificate warning text. mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler); + mDeviceAdminServiceController = new DeviceAdminServiceController(this); + if (!mHasFeature) { // Skip the rest of the initialization return; @@ -2943,7 +2961,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { loadOwners(); cleanUpOldUsers(); ensureUnknownSourcesRestrictionForProfileOwners(); - onStartUser(UserHandle.USER_SYSTEM); + handleStartUser(UserHandle.USER_SYSTEM); // Register an observer for watching for user setup complete and settings changes. mSetupContentObserver.register(); @@ -2990,10 +3008,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void onStartUser(int userId) { + void handleStartUser(int userId) { updateScreenCaptureDisabledInWindowManager(userId, getScreenCaptureDisabled(null, userId)); pushUserRestrictions(userId); + + startOwnerService(userId, "start-user"); + } + + void handleUnlockUser(int userId) { + startOwnerService(userId, "unlock-user"); + } + + void handleStopUser(int userId) { + stopOwnerService(userId, "stop-user"); + } + + private void startOwnerService(int userId, String actionForLog) { + final ComponentName owner = getOwnerComponent(userId); + if (owner != null) { + mDeviceAdminServiceController.startServiceForOwner( + owner.getPackageName(), userId, actionForLog); + } + } + + private void stopOwnerService(int userId, String actionForLog) { + mDeviceAdminServiceController.stopServiceForOwner(userId, actionForLog); } private void cleanUpOldUsers() { @@ -5078,7 +5118,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * @param callerPackage the name of the calling package. Required if {@code who} is * {@code null}. * @param reqPolicy the policy used in the API whose access permission is being checked. - * @param scoppe the delegation scope corresponding to the API being checked. + * @param scope the delegation scope corresponding to the API being checked. * @throws SecurityException if {@code who} is given and is not an owner for {@code reqPolicy}; * or when {@code who} is {@code null} and {@code callerPackage} is not a delegate * of {@code scope}. @@ -6460,6 +6500,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } finally { mInjector.binderRestoreCallingIdentity(ident); } + mDeviceAdminServiceController.startServiceForOwner( + admin.getPackageName(), userId, "set-device-owner"); + Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId); return true; } @@ -6615,6 +6658,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) { + mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-device-owner"); + if (admin != null) { admin.disableCamera = false; admin.userRestrictions = null; @@ -6692,6 +6737,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } finally { mInjector.binderRestoreCallingIdentity(id); } + mDeviceAdminServiceController.startServiceForOwner( + who.getPackageName(), userHandle, "set-profile-owner"); return true; } } @@ -6723,6 +6770,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public void clearProfileOwnerLocked(ActiveAdmin admin, int userId) { + mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-profile-owner"); + if (admin != null) { admin.disableCamera = false; admin.userRestrictions = null; @@ -7275,6 +7324,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { pw.println("Current Device Policy Manager state:"); mOwners.dump(" ", pw); + mDeviceAdminServiceController.dump(" ", pw); int userCount = mUserData.size(); for (int u = 0; u < userCount; u++) { DevicePolicyData policy = getUserData(mUserData.keyAt(u)); @@ -9624,6 +9674,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } + /** + * Return device owner or profile owner set on a given user. + */ + private @Nullable ComponentName getOwnerComponent(int userId) { + synchronized (this) { + if (mOwners.getDeviceOwnerUserId() == userId) { + return mOwners.getDeviceOwnerComponent(); + } + if (mOwners.hasProfileOwner(userId)) { + return mOwners.getProfileOwnerComponent(userId); + } + } + return null; + } + private int checkManagedUserProvisioningPreCondition(int callingUserId) { if (!hasFeatureManagedUsers()) { return CODE_MANAGED_USERS_NOT_SUPPORTED; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index da49eb37ebec..a5eac46281f3 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -475,6 +475,9 @@ public final class SystemServer { ActivityThread activityThread = ActivityThread.systemMain(); mSystemContext = activityThread.getSystemContext(); mSystemContext.setTheme(DEFAULT_SYSTEM_THEME); + + final Context systemUiContext = activityThread.getSystemUiContext(); + systemUiContext.setTheme(DEFAULT_SYSTEM_THEME); } /** @@ -1014,12 +1017,6 @@ public final class SystemServer { traceEnd(); } - if (!disableNonCoreServices) { - traceBeginAndSlog("StartFontServiceManager"); - mSystemServiceManager.startService(FontManagerService.Lifecycle.class); - traceEnd(); - } - if (!disableNonCoreServices && !disableTextServices) { traceBeginAndSlog("StartTextServicesManager"); mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class); diff --git a/services/profile-classes b/services/profile-classes index 1b304e14d8fd..b0d2da7aeba6 100644 --- a/services/profile-classes +++ b/services/profile-classes @@ -2481,7 +2481,6 @@ Landroid/text/FontConfig$Family; Landroid/text/FontConfig$Family$1; Landroid/text/FontConfig$Font; Landroid/text/FontConfig$Font$1; -Landroid/text/FontManager; Landroid/text/format/DateFormat; Landroid/text/format/Time; Landroid/text/format/Time$TimeCalculator; @@ -3132,8 +3131,6 @@ Lcom/android/internal/content/PackageHelper; Lcom/android/internal/content/PackageMonitor; Lcom/android/internal/content/ReferrerIntent; Lcom/android/internal/content/ReferrerIntent$1; -Lcom/android/internal/font/IFontManager; -Lcom/android/internal/font/IFontManager$Stub; Lcom/android/internal/graphics/drawable/AnimationScaleListDrawable; Lcom/android/internal/graphics/drawable/AnimationScaleListDrawable$AnimationScaleListState; Lcom/android/internal/hardware/AmbientDisplayConfiguration; @@ -4377,8 +4374,6 @@ Lcom/android/server/firewall/StringFilter$7; Lcom/android/server/firewall/StringFilter$8; Lcom/android/server/firewall/StringFilter$9; Lcom/android/server/firewall/StringFilter$ValueProvider; -Lcom/android/server/FontManagerService; -Lcom/android/server/FontManagerService$Lifecycle; Lcom/android/server/GestureLauncherService; Lcom/android/server/GestureLauncherService$1; Lcom/android/server/GestureLauncherService$2; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java new file mode 100644 index 000000000000..54ecab3af542 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 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.am; + +import static org.junit.Assert.assertTrue; + +import android.content.ComponentName; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.runner.RunWith; +import org.junit.Test; + +/** + * Tests for the {@link ActivityRecord} class. + * + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.am.ActivityRecordTests + */ +@MediumTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class ActivityRecordTests extends ActivityTestsBase { + private final ComponentName testActivityComponent = + ComponentName.unflattenFromString("com.foo/.BarActivity"); + @Test + public void testStackCleanupOnClearingTask() throws Exception { + final ActivityManagerService service = createActivityManagerService(); + final TestActivityStack testStack = new ActivityStackBuilder(service).build(); + final TaskRecord task = createTask(service, testActivityComponent, testStack); + final ActivityRecord record = createActivity(service, testActivityComponent, task); + + record.setTask(null); + assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); + } + + @Test + public void testStackCleanupOnActivityRemoval() throws Exception { + final ActivityManagerService service = createActivityManagerService(); + final TestActivityStack testStack = new ActivityStackBuilder(service).build(); + final TaskRecord task = createTask(service, testActivityComponent, testStack); + final ActivityRecord record = createActivity(service, testActivityComponent, task); + + task.removeActivity(record); + assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); + } + + @Test + public void testStackCleanupOnTaskRemoval() throws Exception { + final ActivityManagerService service = createActivityManagerService(); + final TestActivityStack testStack = new ActivityStackBuilder(service).build(); + final TaskRecord task = createTask(service, testActivityComponent, testStack); + final ActivityRecord record = createActivity(service, testActivityComponent, task); + + testStack.removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); + assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); + } + + @Test + public void testNoCleanupMovingActivityInSameStack() throws Exception { + final ActivityManagerService service = createActivityManagerService(); + final TestActivityStack testStack = new ActivityStackBuilder(service).build(); + final TaskRecord oldTask = createTask(service, testActivityComponent, testStack); + final ActivityRecord record = createActivity(service, testActivityComponent, oldTask); + final TaskRecord newTask = createTask(service, testActivityComponent, testStack); + + record.reparent(newTask, 0, null /*reason*/); + assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 0); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java new file mode 100644 index 000000000000..c5cc2ff22abd --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2017 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.am; + +import static org.mockito.Mockito.mock; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Handler; +import android.os.Looper; +import android.support.test.InstrumentationRegistry; +import com.android.server.AttributeCache; +import com.android.server.wm.AppWindowContainerController; +import com.android.server.wm.StackWindowController; + +import com.android.server.wm.WindowManagerService; +import com.android.server.wm.WindowTestUtils; +import org.junit.Before; +import org.mockito.MockitoAnnotations; + +/** + * A base class to handle common operations in activity related unit tests. + */ +public class ActivityTestsBase { + private final Context mContext = InstrumentationRegistry.getContext(); + private static boolean sLooperPrepared; + private Handler mHandler; + + // Grabbing an instance of {@link WindowManagerService} creates it if not present so this must + // be called at before any tests. + private final WindowManagerService mWms = WindowTestUtils.getWindowManagerService(mContext); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + if (!sLooperPrepared) { + sLooperPrepared = true; + Looper.prepare(); + } + } + + protected ActivityManagerService createActivityManagerService() { + return new TestActivityManagerService(mContext); + } + + protected static TestActivityStack createActivityStack(ActivityManagerService service, + int stackId, int displayId, boolean onTop) { + if (service.mStackSupervisor instanceof TestActivityStackSupervisor) { + final TestActivityStack stack = ((TestActivityStackSupervisor) service.mStackSupervisor) + .createTestStack(stackId, onTop); + return stack; + } + + return null; + } + + protected static ActivityRecord createActivity(ActivityManagerService service, + ComponentName component, TaskRecord task) { + Intent intent = new Intent(); + intent.setComponent(component); + final ActivityInfo aInfo = new ActivityInfo(); + aInfo.applicationInfo = new ApplicationInfo(); + aInfo.applicationInfo.packageName = component.getPackageName(); + AttributeCache.init(service.mContext); + final ActivityRecord activity = new ActivityRecord(service, null /* caller */, + 0 /* launchedFromPid */, 0, null, intent, null, + aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, + 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, + service.mStackSupervisor, null /* container */, null /* options */, + null /* sourceRecord */); + activity.mWindowContainerController = mock(AppWindowContainerController.class); + + if (task != null) { + task.addActivityToTop(activity); + } + + return activity; + } + + protected static TaskRecord createTask(ActivityManagerService service, + ComponentName component, ActivityStack stack) { + final ActivityInfo aInfo = new ActivityInfo(); + aInfo.applicationInfo = new ApplicationInfo(); + aInfo.applicationInfo.packageName = component.getPackageName(); + + Intent intent = new Intent(); + intent.setComponent(component); + + final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/, + null /*_taskDescription*/, null /*thumbnailInfo*/); + stack.addTask(task, true, "creating test task"); + task.setStack(stack); + task.createWindowContainer(true, true); + + return task; + } + + /** + * An {@link ActivityManagerService} subclass which provides a test + * {@link ActivityStackSupervisor}. + */ + protected static class TestActivityManagerService extends ActivityManagerService { + public TestActivityManagerService(Context context) { + super(context); + } + + @Override + protected ActivityStackSupervisor createStackSupervisor() { + return new TestActivityStackSupervisor(this, new Handler().getLooper()); + } + } + + /** + * 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 { + public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) { + super(service, looper); + } + + // Invoked during {@link ActivityStack} creation. + @Override + void updateUIDsPresentOnDisplay() { + } + + public TestActivityStack createTestStack(int stackId, boolean onTop) { + final ActivityDisplay display = new ActivityDisplay(); + final TestActivityContainer container = + new TestActivityContainer(stackId, display, onTop); + return container.getStack(); + } + + private class TestActivityContainer extends ActivityContainer { + private TestActivityStack mStack; + TestActivityContainer(int stackId, ActivityDisplay activityDisplay, boolean onTop) { + super(stackId, activityDisplay, onTop); + } + + @Override + protected void createStack(int stackId, boolean onTop) { + mStack = new TestActivityStack(this, null /*recentTasks*/, onTop); + } + + public TestActivityStack getStack() { + return mStack; + } + } + } + + /** + * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a + * method is called. Note that its functionality depends on the implementations of the + * construction arguments. + */ + protected static class TestActivityStack<T extends StackWindowController> + extends ActivityStack<T> { + private int mOnActivityRemovedFromStackCount = 0; + private T mContainerController; + TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer, + RecentTasks recentTasks, boolean onTop) { + super(activityContainer, recentTasks, onTop); + } + + @Override + void onActivityRemovedFromStack(ActivityRecord r) { + mOnActivityRemovedFromStackCount++; + super.onActivityRemovedFromStack(r); + } + + // Returns the number of times {@link #onActivityRemovedFromStack} has been called + public int onActivityRemovedFromStackInvocationCount() { + return mOnActivityRemovedFromStackCount; + } + + @Override + protected T createStackWindowController(int displayId, boolean onTop, + Rect outBounds) { + mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController(); + return mContainerController; + } + + @Override + T getWindowContainerController() { + return mContainerController; + } + } + + protected static class ActivityStackBuilder { + private boolean mOnTop = true; + private int mStackId = 0; + private int mDisplayId = 1; + + private final ActivityManagerService mService; + + public ActivityStackBuilder(ActivityManagerService ams) { + mService = ams; + } + + public ActivityStackBuilder setOnTop(boolean onTop) { + mOnTop = onTop; + return this; + } + + public ActivityStackBuilder setStackId(int id) { + mStackId = id; + return this; + } + + public ActivityStackBuilder setDisplayId(int id) { + mDisplayId = id; + return this; + } + + public TestActivityStack build() { + return createActivityStack(mService, mStackId, mDisplayId, mOnTop); + } + } +} 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 0f51c49bfaba..d281e5aed3cc 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -36,7 +36,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; @@ -1276,7 +1275,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { try { final ByteArrayOutputStream out = new ByteArrayOutputStream(); final PrintWriter pw = new PrintWriter(out); - mService.dump(/* fd */ null, pw, args); + mService.dumpNoCheck(/* fd */ null, pw, args); pw.close(); return out.toString(); @@ -1345,23 +1344,20 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected ShortcutInfo makeShortcut(String id) { return makeShortcut( id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); } @Deprecated // Title was renamed to short label. protected ShortcutInfo makeShortcutWithTitle(String id, String title) { return makeShortcut( id, title, /* activity =*/ null, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); } protected ShortcutInfo makeShortcutWithShortLabel(String id, String shortLabel) { return makeShortcut( id, shortLabel, /* activity =*/ null, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); } /** @@ -1370,8 +1366,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) { final ShortcutInfo s = makeShortcut( id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); s.setTimestamp(timestamp); return s; } @@ -1383,8 +1378,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { ComponentName activity) { final ShortcutInfo s = makeShortcut( id, "Title-" + id, activity, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); s.setTimestamp(timestamp); return s; } @@ -1395,27 +1389,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) { return makeShortcut( id, "Title-" + id, /* activity =*/ null, icon, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); - } - - protected ShortcutInfo makeChooserShortcut(String id, int i, boolean includeIntent) { - List<IntentFilter> filters = new ArrayList<>(); - List<ComponentName> componentNames = new ArrayList<>(); - for(int j = 0; j < i; j++) { - final IntentFilter filter = new IntentFilter(); - filter.addAction("view"); - filters.add(filter); - - componentNames.add(new ComponentName("xxxx", "yy" + i)); - } - Intent intent = null; - if (includeIntent) { - intent = makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class); - } - return makeShortcut( - id, "Title-" + id, /* activity =*/ null, /* icon */ null, - intent, /* rank =*/ 0, filters, componentNames); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); } protected ShortcutInfo makePackageShortcut(String packageName, String id) { @@ -1424,8 +1398,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { setCaller(packageName); ShortcutInfo s = makeShortcut( id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); setCaller(origCaller); // restore the caller return s; @@ -1449,52 +1422,39 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) { return makeShortcut( id, "Title-" + id, activity, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilters =*/ null, /* chooserComponentNames =*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); } protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) { return makeShortcut( id, "Title-" + id, /* activity =*/ null, /* icon =*/ null, - intent, /* rank =*/ 0, /* chooserFilters =*/ null, - /* chooserComponentNames =*/ null); - + intent, /* rank =*/ 0); } protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity, String title) { return makeShortcut( id, title, activity, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0, - /* chooserFilters =*/ null, /* chooserComponentNames =*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0); } protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity, int rank) { return makeShortcut( id, "Title-" + id, activity, /* icon =*/ null, - makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank, - /* chooserFilters =*/ null, /* chooserComponentNames =*/ null); + makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank); } /** * Make a shortcut with details. */ protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity, - Icon icon, Intent intent, int rank, @Nullable List<IntentFilter> chooserFilters, - @Nullable List<ComponentName> chooserComponentNames) { + Icon icon, Intent intent, int rank) { final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id) .setActivity(new ComponentName(mClientContext.getPackageName(), "main")) .setShortLabel(title) - .setRank(rank); - if (intent != null) { - b.setIntent(intent); - } - if (chooserFilters != null) { - for (int i = 0; i < chooserFilters.size(); i++) { - b.addChooserIntentFilter(chooserFilters.get(i), chooserComponentNames.get(i)); - } - } + .setRank(rank) + .setIntent(intent); if (icon != null) { b.setIcon(icon); } 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 dd0871ae49e0..9861aa177135 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -17,7 +17,6 @@ package com.android.server.pm; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyOrNull; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyStringOrNull; -import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllChooser; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDisabled; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned; @@ -58,7 +57,6 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -261,9 +259,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { icon1, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class, "key1", "val1", "nest", makeBundle("key", 123)), - /* weight */ 10, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 10); final ShortcutInfo si2 = makeShortcut( "shortcut2", @@ -271,18 +267,14 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* activity */ null, icon2, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), - /* weight */ 12, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 12); final ShortcutInfo si3 = makeShortcut( "shortcut3", "Title 3", /* activity */ null, icon3, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), - /* weight */ 13, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 13); assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3))); assertShortcutIds(assertAllNotKeyFieldsOnly( @@ -993,10 +985,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"), - makeShortcut("s5"), - makeChooserShortcut("s6", 2, true), - makeChooserShortcut("s7", 2, true), - makeChooserShortcut("s8", 1, true)))); + makeShortcut("s5") + ))); }); runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { assertTrue(mManager.setDynamicShortcuts(list( @@ -1004,13 +994,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"), - makeShortcut("s5"), - makeChooserShortcut("s6", 2, true), - makeChooserShortcut("s7", 2, true), - makeChooserShortcut("s8", 1, true)))); + makeShortcut("s5") + ))); }); runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> { - mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3", "s6"), + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), getCallingUser()); mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"), getCallingUser()); @@ -1023,20 +1011,19 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.removeDynamicShortcuts(list("s1")); mManager.removeDynamicShortcuts(list("s3")); mManager.removeDynamicShortcuts(list("s5")); - mManager.removeDynamicShortcuts(list("s7")); }); runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), - "s3", "s4", "s5", "s6", "s7", "s8"); + "s3", "s4", "s5"); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), - "s2", "s3", "s6"); + "s2", "s3"); }); runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), - "s2", "s4", "s6", "s8"); + "s2", "s4"); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), "s4", "s5"); @@ -1073,10 +1060,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), - "s3", "s4", "s5", "s6", "s7", "s8"); + "s3", "s4", "s5"); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), - "s2", "s3", "s6"); + "s2", "s3"); ShortcutInfo s = getCallerShortcut("s2"); assertTrue(s.hasIconResource()); @@ -1092,7 +1079,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> { assertShortcutIds(assertAllDynamic( mManager.getDynamicShortcuts()), - "s2", "s4", "s6", "s8"); + "s2", "s4"); assertShortcutIds(assertAllPinned( mManager.getPinnedShortcuts()), "s4", "s5"); @@ -1189,46 +1176,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); } - public void testUpdateShortcuts_chooser() { - runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { - assertTrue(mManager.setDynamicShortcuts(list( - makeShortcut("s1"), - makeChooserShortcut("s2", 2, false), - makeChooserShortcut("s3", 2, false) - ))); - - assertFalse(getCallerShortcut("s1").isChooser()); - assertTrue(getCallerShortcut("s2").isChooser()); - assertTrue(getCallerShortcut("s3").isChooser()); - - ShortcutInfo s = getCallerShortcut("s1"); - assertNull(s.getChooserIntentFilters()); - assertNull(s.getChooserComponentNames()); - - assertTrue(getCallerShortcut("s1").isDynamic()); - assertFalse(getCallerShortcut("s2").isDynamic()); - assertFalse(getCallerShortcut("s3").isDynamic()); - - - // Replace 2 with a chooser shortcut - mManager.updateShortcuts(list(makeChooserShortcut("s1", 2, true))); - - s = getCallerShortcut("s1"); - assertEquals(2, s.getChooserIntentFilters().length); - assertEquals(2, s.getChooserComponentNames().length); - - assertShortcutIds(assertAllChooser( - mManager.getDynamicShortcuts()), - "s1", "s2", "s3"); - - assertTrue(getCallerShortcut("s1").isDynamic()); - assertFalse(getCallerShortcut("s2").isDynamic()); - assertFalse(getCallerShortcut("s3").isDynamic()); - }); - } - - - // === Test for launcher side APIs === + // === Test for launcher side APIs === public void testGetShortcuts() { @@ -1539,17 +1487,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* icon =*/ null, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class, "key1", "val1", "nest", makeBundle("key", 123)), - /* weight */ 10, /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 10); final ShortcutInfo s1_2 = makeShortcut( - "s2", "Title 2", + "s2", + "Title 2", /* activity */ null, /* icon =*/ null, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), - /* weight */ 12, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 12); assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2))); dumpsysOnLogcat(); @@ -1562,9 +1508,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* icon =*/ null, makeIntent(Intent.ACTION_ANSWER, ShortcutActivity2.class, "key1", "val1", "nest", makeBundle("key", 123)), - /* weight */ 10, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 10); assertTrue(mManager.setDynamicShortcuts(list(s2_1))); dumpsysOnLogcat(); @@ -2733,12 +2677,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final ShortcutInfo s1_2 = makeShortcut( "s2", "Title 2", - /* activity */ null, - /* icon =*/ null, + /* activity */ null, + /* icon =*/ null, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), - /* rank */ 12, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* rank */ 12); final ShortcutInfo s1_3 = makeShortcut("s3"); @@ -2753,9 +2695,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* icon =*/ null, makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class, "key1", "val1", "nest", makeBundle("key", 123)), - /* weight */ 10, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 10); assertTrue(mManager.setDynamicShortcuts(list(s2_1))); }); @@ -3175,9 +3115,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { icon1, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class, "key1", "val1", "nest", makeBundle("key", 123)), - /* weight */ 10, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 10); final ShortcutInfo si2 = makeShortcut( "s2", @@ -3185,9 +3123,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* activity */ null, icon2, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), - /* weight */ 12, - /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 12); assertTrue(mManager.setDynamicShortcuts(list(si1, si2))); @@ -3205,8 +3141,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeComponent(ShortcutActivity.class), icon1, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class, - "key1", "val1", "nest", makeBundle("key", 123)), /* weight */ 10, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null); + "key1", "val1", "nest", makeBundle("key", 123)), + /* weight */ 10); final ShortcutInfo si2 = makeShortcut( "s2", @@ -3214,8 +3150,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* activity */ null, icon2, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), - /* weight */ 12, /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 12); assertTrue(mManager.setDynamicShortcuts(list(si1, si2))); @@ -3237,8 +3172,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { icon1, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class, "key1", "val1", "nest", makeBundle("key", 123)), - /* weight */ 10, /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 10); final ShortcutInfo si2 = makeShortcut( "s2", @@ -3246,8 +3180,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* activity */ null, icon2, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), - /* weight */ 12, /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null); + /* weight */ 12); assertTrue(mManager.setDynamicShortcuts(list(si1, si2))); @@ -6884,12 +6817,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.setDynamicShortcuts(list( makeShortcut("ms1", "title1", new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), - /* icon */ null, new Intent("action1"), /* rank */ 0, - /* chooserFilter=*/ null, /* chooserComponentNames=*/ null), + /* icon */ null, new Intent("action1"), /* rank */ 0), makeShortcut("ms2", "title2", new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), - /* icon */ null, new Intent("action1"), /* rank */ 0, /* chooserFilter=*/ null, - /* chooserComponentNames=*/ null))); + /* icon */ null, new Intent("action1"), /* rank */ 0))); }); runWithCaller(LAUNCHER_1, USER_0, () -> { 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 7c5eb07f0a78..9880caa11f85 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -34,7 +34,6 @@ import android.Manifest.permission; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.res.Resources; import android.graphics.BitmapFactory; @@ -93,6 +92,11 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertExpectException( RuntimeException.class, + "intents cannot contain null", + () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(null)); + + assertExpectException( + RuntimeException.class, "action must be set", () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent())); @@ -137,19 +141,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { "disabledMessage cannot be empty", () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage("")); - - assertExpectException( - RuntimeException.class, - "component name cannot be null", - () -> new ShortcutInfo.Builder(getTestContext(), "id") - .addChooserIntentFilter(new IntentFilter(Intent.ACTION_SEND), null)); - - assertExpectException( - RuntimeException.class, - "intent filter cannot be null", - () -> new ShortcutInfo.Builder(getTestContext(), "id") - .addChooserIntentFilter(null, new ComponentName("xxx", "s"))); - assertExpectException(NullPointerException.class, "action must be set", () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent())); @@ -248,10 +239,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { PersistableBundle pb = new PersistableBundle(); pb.putInt("k", 1); - IntentFilter chooserFilter = new IntentFilter(); - chooserFilter.addAction(Intent.ACTION_VIEW); - PersistableBundle pb2 = new PersistableBundle(); - pb2.putInt("l", 1); si = new ShortcutInfo.Builder(getTestContext()) .setId("id") @@ -264,8 +251,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setRank(123) .setExtras(pb) - .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b")) - .setChooserExtras(pb2) .build(); si.addFlags(ShortcutInfo.FLAG_PINNED); si.setBitmapPath("abc"); @@ -296,12 +281,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(null, si.getTextResName()); assertEquals(0, si.getDisabledMessageResourceId()); assertEquals(null, si.getDisabledMessageResName()); - - assertEquals(1, si.getChooserIntentFilters().length); - assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0)); - assertEquals(1, si.getChooserComponentNames().length); - assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]); - assertEquals(1, si.getChooserExtras().getInt("l")); } public void testShortcutInfoParcel_resId() { @@ -310,10 +289,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { PersistableBundle pb = new PersistableBundle(); pb.putInt("k", 1); - IntentFilter chooserFilter = new IntentFilter(); - chooserFilter.addAction(Intent.ACTION_VIEW); - PersistableBundle pb2 = new PersistableBundle(); - pb2.putInt("l", 1); si = new ShortcutInfo.Builder(getTestContext()) .setId("id") @@ -326,8 +301,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setRank(123) .setExtras(pb) - .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b")) - .setChooserExtras(pb2) .build(); si.addFlags(ShortcutInfo.FLAG_PINNED); si.setBitmapPath("abc"); @@ -364,11 +337,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { PersistableBundle pb = new PersistableBundle(); pb.putInt("k", 1); - IntentFilter chooserFilter = new IntentFilter(); - chooserFilter.addAction(Intent.ACTION_VIEW); - PersistableBundle pb2 = new PersistableBundle(); - pb2.putInt("l", 1); - ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext) .setId("id") .setActivity(new ComponentName("a", "b")) @@ -380,8 +348,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setRank(123) .setExtras(pb) - .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b")) - .setChooserExtras(pb2) .build(); sorig.addFlags(ShortcutInfo.FLAG_PINNED); sorig.setBitmapPath("abc"); @@ -411,12 +377,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(456, si.getIconResourceId()); assertEquals("string/r456", si.getIconResName()); - assertEquals(1, si.getChooserIntentFilters().length); - assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0)); - assertEquals(1, si.getChooserComponentNames().length); - assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]); - assertEquals(1, si.getChooserExtras().getInt("l")); - si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR); assertEquals(mClientContext.getPackageName(), si.getPackage()); @@ -484,10 +444,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { PersistableBundle pb = new PersistableBundle(); pb.putInt("k", 1); - IntentFilter chooserFilter = new IntentFilter(); - chooserFilter.addAction(Intent.ACTION_VIEW); - PersistableBundle pb2 = new PersistableBundle(); - pb2.putInt("l", 1); ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext) .setId("id") .setActivity(new ComponentName("a", "b")) @@ -499,8 +455,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setRank(123) .setExtras(pb) - .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b")) - .setChooserExtras(pb2) .build(); sorig.addFlags(ShortcutInfo.FLAG_PINNED); sorig.setBitmapPath("abc"); @@ -533,12 +487,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(456, si.getIconResourceId()); assertEquals("string/r456", si.getIconResName()); - assertEquals(1, si.getChooserIntentFilters().length); - assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0)); - assertEquals(1, si.getChooserComponentNames().length); - assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]); - assertEquals(1, si.getChooserExtras().getInt("l")); - si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR); assertEquals(mClientContext.getPackageName(), si.getPackage()); @@ -654,10 +602,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException { PersistableBundle pb = new PersistableBundle(); pb.putInt("k", 1); - IntentFilter chooserFilter = new IntentFilter(); - chooserFilter.addAction(Intent.ACTION_VIEW); - PersistableBundle pb2 = new PersistableBundle(); - pb2.putInt("l", 1); ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext()) .setId("id") .setActivity(new ComponentName("a", "b")) @@ -769,12 +713,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(999, si.getRank()); - PersistableBundle pb3 = new PersistableBundle(); - pb3.putInt("x", 99); + PersistableBundle pb2 = new PersistableBundle(); + pb2.putInt("x", 99); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") - .setExtras(pb3).build()); + .setExtras(pb2).build()); assertEquals("text", si.getText()); assertEquals(99, si.getExtras().getInt("x")); } @@ -2096,16 +2040,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(expected, dumpCheckin()); } - public void testDumpsysNoPermission() { - assertExpectException(SecurityException.class, "android.permission.DUMP", - () -> mService.dump(null, new PrintWriter(new StringWriter()), null)); - - // System can call it without the permission. - runWithSystemUid(() -> { - mService.dump(null, new PrintWriter(new StringWriter()), null); - }); - } - /** * Make sure the legacy file format that only supported a single intent per shortcut * can still be read. diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java index 2ccaefc4512e..25004de60676 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java @@ -44,7 +44,8 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { @Test public void testRemoveContainer() throws Exception { - final TestAppWindowContainerController controller = createAppWindowController(); + final WindowTestUtils.TestAppWindowContainerController controller = + createAppWindowController(); // Assert token was added to display. assertNotNull(sDisplayContent.getWindowToken(controller.mToken.asBinder())); @@ -61,7 +62,8 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { @Test public void testSetOrientation() throws Exception { - final TestAppWindowContainerController controller = createAppWindowController(); + final WindowTestUtils.TestAppWindowContainerController controller = + createAppWindowController(); // Assert orientation is unspecified to start. assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation()); @@ -92,7 +94,8 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { @Test public void testCreateRemoveStartingWindow() throws Exception { - final TestAppWindowContainerController controller = createAppWindowController(); + final WindowTestUtils.TestAppWindowContainerController controller = + createAppWindowController(); controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false); waitUntilHandlerIdle(); @@ -105,8 +108,10 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { @Test public void testTransferStartingWindow() throws Exception { - final TestAppWindowContainerController controller1 = createAppWindowController(); - final TestAppWindowContainerController controller2 = createAppWindowController(); + final WindowTestUtils.TestAppWindowContainerController controller1 = + createAppWindowController(); + final WindowTestUtils.TestAppWindowContainerController controller2 = + createAppWindowController(); controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false); waitUntilHandlerIdle(); @@ -120,8 +125,10 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { @Test public void testTransferStartingWindowWhileCreating() throws Exception { - final TestAppWindowContainerController controller1 = createAppWindowController(); - final TestAppWindowContainerController controller2 = createAppWindowController(); + final WindowTestUtils.TestAppWindowContainerController controller1 = + createAppWindowController(); + final WindowTestUtils.TestAppWindowContainerController controller2 = + createAppWindowController(); sPolicy.setRunnableWhenAddingSplashScreen(() -> { // Surprise, ...! Transfer window in the middle of the creation flow. @@ -140,16 +147,16 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { public void testReparent() throws Exception { final StackWindowController stackController = createStackControllerOnDisplay(sDisplayContent); - final TestTaskWindowContainerController taskController1 = - new TestTaskWindowContainerController(stackController); - final TestAppWindowContainerController appWindowController1 = createAppWindowController( - taskController1); - final TestTaskWindowContainerController taskController2 = - new TestTaskWindowContainerController(stackController); - final TestAppWindowContainerController appWindowController2 = createAppWindowController( - taskController2); - final TestTaskWindowContainerController taskController3 = - new TestTaskWindowContainerController(stackController); + final WindowTestUtils.TestTaskWindowContainerController taskController1 = + new WindowTestUtils.TestTaskWindowContainerController(stackController); + final WindowTestUtils.TestAppWindowContainerController appWindowController1 = + createAppWindowController(taskController1); + final WindowTestUtils.TestTaskWindowContainerController taskController2 = + new WindowTestUtils.TestTaskWindowContainerController(stackController); + final WindowTestUtils.TestAppWindowContainerController appWindowController2 = + createAppWindowController(taskController2); + final WindowTestUtils.TestTaskWindowContainerController taskController3 = + new WindowTestUtils.TestTaskWindowContainerController(stackController); try { appWindowController1.reparent(taskController1, 0); @@ -169,16 +176,18 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { // Reparent the app window and ensure that it is moved appWindowController1.reparent(taskController2, 0); assertEquals(taskController2.mContainer, appWindowController1.mContainer.getParent()); - assertEquals(0, ((TestAppWindowToken) appWindowController1.mContainer).positionInParent()); - assertEquals(1, ((TestAppWindowToken) appWindowController2.mContainer).positionInParent()); + assertEquals(0, ((WindowTestUtils.TestAppWindowToken) appWindowController1.mContainer) + .positionInParent()); + assertEquals(1, ((WindowTestUtils.TestAppWindowToken) appWindowController2.mContainer) + .positionInParent()); } - private TestAppWindowContainerController createAppWindowController() { - return createAppWindowController(new TestTaskWindowContainerController()); + private WindowTestUtils.TestAppWindowContainerController createAppWindowController() { + return createAppWindowController(new WindowTestUtils.TestTaskWindowContainerController()); } - private TestAppWindowContainerController createAppWindowController( - TestTaskWindowContainerController taskController) { - return new TestAppWindowContainerController(taskController); + private WindowTestUtils.TestAppWindowContainerController createAppWindowController( + WindowTestUtils.TestTaskWindowContainerController taskController) { + return new WindowTestUtils.TestAppWindowContainerController(taskController); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index 2003b91bcfad..7a7ca3f4000a 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -51,7 +51,8 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testAddWindow_Order() throws Exception { - final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent); + final WindowTestUtils.TestAppWindowToken token = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); assertEquals(0, token.getWindowsCount()); @@ -78,7 +79,8 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testFindMainWindow() throws Exception { - final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent); + final WindowTestUtils.TestAppWindowToken token = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); assertNull(token.findMainWindow()); @@ -102,12 +104,13 @@ public class AppWindowTokenTests extends WindowTestsBase { // Create an app window with token on a display. final TaskStack stack = createTaskStackOnDisplay(sDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final TestAppWindowToken appWindowToken = new TestAppWindowToken(sDisplayContent); + final WindowTestUtils.TestAppWindowToken appWindowToken = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); task.addChild(appWindowToken, 0); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("AppWindow"); - final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken); + final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken); appWindowToken.addWindow(appWindow); // Set initial orientation and update. @@ -137,12 +140,13 @@ public class AppWindowTokenTests extends WindowTestsBase { final DisplayContent defaultDisplayContent = sWm.getDefaultDisplayContentLocked(); final TaskStack stack = createTaskStackOnDisplay(defaultDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final TestAppWindowToken appWindowToken = new TestAppWindowToken(defaultDisplayContent); + final WindowTestUtils.TestAppWindowToken appWindowToken = + new WindowTestUtils.TestAppWindowToken(defaultDisplayContent); task.addChild(appWindowToken, 0); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("AppWindow"); - final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken); + final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken); appWindowToken.addWindow(appWindow); // Set initial orientation and update. @@ -165,7 +169,8 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testGetOrientation() throws Exception { - final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent); + final WindowTestUtils.TestAppWindowToken token = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); token.setFillsParent(false); diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index e3ccd6eef105..d7d365e72480 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -175,7 +175,7 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(dc, stack.getDisplayContent()); final Task task = createTaskInStack(stack, 0 /* userId */); - final TestAppWindowToken token = new TestAppWindowToken(dc); + final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc); task.addChild(token, 0); assertEquals(dc, task.getDisplayContent()); assertEquals(dc, token.getDisplayContent()); diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java index b0eba0b99567..13098f64bfac 100644 --- a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java @@ -16,12 +16,7 @@ package com.android.server.wm; -import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; - import android.graphics.Rect; -import android.hardware.display.DisplayManagerGlobal; -import android.view.Display; -import android.view.DisplayInfo; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,8 +43,8 @@ public class StackWindowControllerTests extends WindowTestsBase { public void testRemoveContainer() throws Exception { final StackWindowController stackController = createStackControllerOnDisplay(sDisplayContent); - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(stackController); + final WindowTestUtils.TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(stackController); final TaskStack stack = stackController.mContainer; final Task task = taskController.mContainer; @@ -68,11 +63,11 @@ public class StackWindowControllerTests extends WindowTestsBase { public void testRemoveContainer_deferRemoval() throws Exception { final StackWindowController stackController = createStackControllerOnDisplay(sDisplayContent); - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(stackController); + final WindowTestUtils.TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(stackController); final TaskStack stack = stackController.mContainer; - final TestTask task = (TestTask) taskController.mContainer; + final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer; // Stack removal is deferred if one of its child is animating. task.setLocalIsAnimating(true); @@ -96,9 +91,9 @@ public class StackWindowControllerTests extends WindowTestsBase { final StackWindowController stack1Controller = createStackControllerOnDisplay(sDisplayContent); final TaskStack stack1 = stack1Controller.mContainer; - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(stack1Controller); - final TestTask task1 = (TestTask) taskController.mContainer; + final WindowTestUtils.TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(stack1Controller); + final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer; task1.mOnDisplayChangedCalled = false; // Create second display and put second stack on it. diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index aab75ee1699b..717ddf26eb2f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; @@ -24,15 +27,19 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; +import android.app.ActivityManager.TaskSnapshot; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.GraphicBuffer; +import android.graphics.PixelFormat; +import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.view.Surface; + +import com.android.server.wm.TaskSnapshotSurface.Window; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,59 +55,174 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { private TaskSnapshotSurface mSurface; - @Before - public void setUp() { - mSurface = new TaskSnapshotSurface(null, null, null, Color.WHITE); + private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis, + int windowFlags, Rect taskBounds) { + final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888, + GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER); + final TaskSnapshot snapshot = new TaskSnapshot(buffer, + ORIENTATION_PORTRAIT, contentInsets, false, 1.0f); + mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test", + Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds); + } + + private void setupSurface(int width, int height) { + setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + new Rect(0, 0, width, height)); } @Test public void fillEmptyBackground_fillHorizontally() throws Exception { + setupSurface(200, 100); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(200); when(mockCanvas.getHeight()).thenReturn(100); - final Bitmap b = Bitmap.createBitmap(100, 200, Config.ARGB_8888); - mSurface.fillEmptyBackground(mockCanvas, b); + mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200)); verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any()); } @Test public void fillEmptyBackground_fillVertically() throws Exception { + setupSurface(100, 200); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(200); - final Bitmap b = Bitmap.createBitmap(200, 100, Config.ARGB_8888); - mSurface.fillEmptyBackground(mockCanvas, b); + mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100)); verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any()); } @Test public void fillEmptyBackground_fillBoth() throws Exception { + setupSurface(200, 200); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(200); when(mockCanvas.getHeight()).thenReturn(200); - final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - mSurface.fillEmptyBackground(mockCanvas, b); + mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100)); verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any()); verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any()); } @Test public void fillEmptyBackground_dontFill_sameSize() throws Exception { + setupSurface(100, 100); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - mSurface.fillEmptyBackground(mockCanvas, b); + mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100)); verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any()); } @Test public void fillEmptyBackground_dontFill_bitmapLarger() throws Exception { + setupSurface(100, 100); + final Canvas mockCanvas = mock(Canvas.class); + when(mockCanvas.getWidth()).thenReturn(100); + when(mockCanvas.getHeight()).thenReturn(100); + mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200)); + verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any()); + } + + @Test + public void testCalculateSnapshotCrop() { + setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100)); + assertEquals(new Rect(0, 0, 100, 90), mSurface.calculateSnapshotCrop()); + } + + @Test + public void testCalculateSnapshotCrop_taskNotOnTop() { + setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 100)); + assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop()); + } + + @Test + public void testCalculateSnapshotCrop_navBarLeft() { + setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100)); + assertEquals(new Rect(10, 0, 100, 100), mSurface.calculateSnapshotCrop()); + } + + @Test + public void testCalculateSnapshotCrop_navBarRight() { + setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100)); + assertEquals(new Rect(0, 0, 90, 100), mSurface.calculateSnapshotCrop()); + } + + @Test + public void testCalculateSnapshotFrame() { + setupSurface(100, 100); + final Rect insets = new Rect(0, 10, 0, 10); + mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets); + assertEquals(new Rect(0, -10, 100, 70), + mSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90))); + } + + @Test + public void testCalculateSnapshotFrame_navBarLeft() { + setupSurface(100, 100); + final Rect insets = new Rect(10, 10, 0, 0); + mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets); + assertEquals(new Rect(0, -10, 90, 80), + mSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100))); + } + + @Test + public void testDrawStatusBarBackground() { + setupSurface(100, 100); + final Rect insets = new Rect(0, 10, 10, 0); + mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - final Bitmap b = Bitmap.createBitmap(200, 200, Config.ARGB_8888); - mSurface.fillEmptyBackground(mockCanvas, b); + mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100), 10); + verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any()); + } + + @Test + public void testDrawStatusBarBackground_nope() { + setupSurface(100, 100); + final Rect insets = new Rect(0, 10, 10, 0); + mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets); + final Canvas mockCanvas = mock(Canvas.class); + when(mockCanvas.getWidth()).thenReturn(100); + when(mockCanvas.getHeight()).thenReturn(100); + mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100), 10); verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any()); } + + @Test + public void testDrawNavigationBarBackground() { + final Rect insets = new Rect(0, 10, 0, 10); + setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + new Rect(0, 0, 100, 100)); + mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets); + final Canvas mockCanvas = mock(Canvas.class); + when(mockCanvas.getWidth()).thenReturn(100); + when(mockCanvas.getHeight()).thenReturn(100); + mSurface.drawNavigationBarBackground(mockCanvas); + verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any()); + } + + @Test + public void testDrawNavigationBarBackground_left() { + final Rect insets = new Rect(10, 10, 0, 0); + setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + new Rect(0, 0, 100, 100)); + mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets); + final Canvas mockCanvas = mock(Canvas.class); + when(mockCanvas.getWidth()).thenReturn(100); + when(mockCanvas.getHeight()).thenReturn(100); + mSurface.drawNavigationBarBackground(mockCanvas); + verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any()); + } + + @Test + public void testDrawNavigationBarBackground_right() { + final Rect insets = new Rect(0, 10, 10, 0); + setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + new Rect(0, 0, 100, 100)); + mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets); + final Canvas mockCanvas = mock(Canvas.class); + when(mockCanvas.getWidth()).thenReturn(100); + when(mockCanvas.getHeight()).thenReturn(100); + mSurface.drawNavigationBarBackground(mockCanvas); + verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any()); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java index 462bd68dc420..82ea2313e8d7 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java @@ -56,7 +56,7 @@ public class TaskStackContainersTests extends WindowTestsBase { // Stack should contain visible app window to be considered visible. final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */); assertFalse(mPinnedStack.isVisible()); - final TestAppWindowToken pinnedApp = new TestAppWindowToken(sDisplayContent); + final WindowTestUtils.TestAppWindowToken pinnedApp = new WindowTestUtils.TestAppWindowToken(sDisplayContent); pinnedTask.addChild(pinnedApp, 0 /* addPos */); assertTrue(mPinnedStack.isVisible()); } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java index 9dbd8a617eec..267e5f77e709 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java @@ -16,9 +16,6 @@ package com.android.server.wm; -import android.content.pm.ActivityInfo; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,12 +64,14 @@ public class TaskStackTests extends WindowTestsBase { public void testClosingAppDifferentStackOrientation() throws Exception { final TaskStack stack = createTaskStackOnDisplay(sDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent); + WindowTestUtils.TestAppWindowToken appWindowToken1 = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); task1.addChild(appWindowToken1, 0); appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); final Task task2 = createTaskInStack(stack, 1 /* userId */); - TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent); + WindowTestUtils.TestAppWindowToken appWindowToken2 = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); task2.addChild(appWindowToken2, 0); appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT); @@ -85,12 +84,14 @@ public class TaskStackTests extends WindowTestsBase { public void testMoveTaskToBackDifferentStackOrientation() throws Exception { final TaskStack stack = createTaskStackOnDisplay(sDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent); + WindowTestUtils.TestAppWindowToken appWindowToken1 = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); task1.addChild(appWindowToken1, 0); appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); final Task task2 = createTaskInStack(stack, 1 /* userId */); - TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent); + WindowTestUtils.TestAppWindowToken appWindowToken2 = + new WindowTestUtils.TestAppWindowToken(sDisplayContent); task2.addChild(appWindowToken2, 0); appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java index f79908e906c7..1819c56735eb 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java @@ -16,14 +16,9 @@ package com.android.server.wm; -import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; - -import android.hardware.display.DisplayManagerGlobal; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.view.Display; -import android.view.DisplayInfo; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,10 +40,10 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { @Test public void testRemoveContainer() throws Exception { - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(); - final TestAppWindowContainerController appController = - new TestAppWindowContainerController(taskController); + final WindowTestUtils.TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(); + final WindowTestUtils.TestAppWindowContainerController appController = + new WindowTestUtils.TestAppWindowContainerController(taskController); taskController.removeContainer(); // Assert that the container was removed. @@ -58,12 +53,12 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { @Test public void testRemoveContainer_deferRemoval() throws Exception { - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(); - final TestAppWindowContainerController appController = - new TestAppWindowContainerController(taskController); + final WindowTestUtils.TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(); + final WindowTestUtils.TestAppWindowContainerController appController = + new WindowTestUtils.TestAppWindowContainerController(taskController); - final TestTask task = (TestTask) taskController.mContainer; + final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer; final AppWindowToken app = appController.mContainer; task.mShouldDeferRemoval = true; @@ -85,12 +80,12 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { public void testReparent() throws Exception { final StackWindowController stackController1 = createStackControllerOnDisplay(sDisplayContent); - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(stackController1); + final WindowTestUtils.TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(stackController1); final StackWindowController stackController2 = createStackControllerOnDisplay(sDisplayContent); - final TestTaskWindowContainerController taskController2 = - new TestTaskWindowContainerController(stackController2); + final WindowTestUtils.TestTaskWindowContainerController taskController2 = + new WindowTestUtils.TestTaskWindowContainerController(stackController2); boolean gotException = false; try { @@ -114,8 +109,8 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { taskController.reparent(stackController2, 0); assertEquals(stackController2.mContainer, taskController.mContainer.getParent()); - assertEquals(0, ((TestTask) taskController.mContainer).positionInParent()); - assertEquals(1, ((TestTask) taskController2.mContainer).positionInParent()); + assertEquals(0, ((WindowTestUtils.TestTask) taskController.mContainer).positionInParent()); + assertEquals(1, ((WindowTestUtils.TestTask) taskController2.mContainer).positionInParent()); } @Test @@ -124,9 +119,9 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { final StackWindowController stack1Controller = createStackControllerOnDisplay(sDisplayContent); final TaskStack stack1 = stack1Controller.mContainer; - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(stack1Controller); - final TestTask task1 = (TestTask) taskController.mContainer; + final WindowTestUtils.TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(stack1Controller); + final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer; task1.mOnDisplayChangedCalled = false; assertEquals(sDisplayContent, stack1.getDisplayContent()); @@ -134,9 +129,10 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { final DisplayContent dc = createNewDisplay(); final StackWindowController stack2Controller = createStackControllerOnDisplay(dc); final TaskStack stack2 = stack2Controller.mContainer; - final TestTaskWindowContainerController taskController2 = - new TestTaskWindowContainerController(stack2Controller); - final TestTask task2 = (TestTask) taskController2.mContainer; + final WindowTestUtils.TestTaskWindowContainerController taskController2 = + new WindowTestUtils.TestTaskWindowContainerController(stack2Controller); + final WindowTestUtils.TestTask task2 = + (WindowTestUtils.TestTask) taskController2.mContainer; // Reparent and check state taskController.reparent(stack2Controller, 0); diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java index cf8af6716d34..0eaf5bc3e940 100644 --- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java @@ -46,7 +46,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testFlow() throws Exception { - final AppWindowToken token = new TestAppWindowToken(sDisplayContent); + final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent); sWm.mUnknownAppVisibilityController.notifyLaunched(token); sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token); sWm.mUnknownAppVisibilityController.notifyRelayouted(token); @@ -58,8 +58,8 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testMultiple() throws Exception { - final AppWindowToken token1 = new TestAppWindowToken(sDisplayContent); - final AppWindowToken token2 = new TestAppWindowToken(sDisplayContent); + final AppWindowToken token1 = new WindowTestUtils.TestAppWindowToken(sDisplayContent); + final AppWindowToken token2 = new WindowTestUtils.TestAppWindowToken(sDisplayContent); sWm.mUnknownAppVisibilityController.notifyLaunched(token1); sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1); sWm.mUnknownAppVisibilityController.notifyLaunched(token2); @@ -74,7 +74,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testClear() throws Exception { - final AppWindowToken token = new TestAppWindowToken(sDisplayContent); + final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent); sWm.mUnknownAppVisibilityController.notifyLaunched(token); sWm.mUnknownAppVisibilityController.clear();; assertTrue(sWm.mUnknownAppVisibilityController.allResolved()); @@ -82,7 +82,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testAppRemoved() throws Exception { - final AppWindowToken token = new TestAppWindowToken(sDisplayContent); + final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent); sWm.mUnknownAppVisibilityController.notifyLaunched(token); sWm.mUnknownAppVisibilityController.appRemoved(token); assertTrue(sWm.mUnknownAppVisibilityController.allResolved()); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java index 2e6eac091ba8..a2aa058ac063 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java @@ -102,7 +102,7 @@ public class WindowFrameTests extends WindowTestsBase { // Just any non zero value. sWm.mSystemDecorLayer = 10000; - mWindowToken = new TestAppWindowToken(sWm.getDefaultDisplayContentLocked()); + mWindowToken = new WindowTestUtils.TestAppWindowToken(sWm.getDefaultDisplayContentLocked()); mStubStack = new TaskStack(sWm, 0); } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java new file mode 100644 index 000000000000..3a443575332e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2017 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 android.app.ActivityManager; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Binder; +import android.os.IBinder; +import android.view.IApplicationToken; +import android.view.IWindow; +import android.view.WindowManager; + +import static android.app.AppOpsManager.OP_NONE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.res.Configuration.EMPTY; +import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static org.mockito.Mockito.mock; + +/** + * A collection of static functions that can be referenced by other test packages to provide access + * to WindowManager related test functionality. + */ +public class WindowTestUtils { + public static int sNextTaskId = 0; + + /** + * Retrieves an instance of {@link WindowManagerService}, creating it if necessary. + */ + public static WindowManagerService getWindowManagerService(Context context) { + return TestWindowManagerPolicy.getWindowManagerService(context); + } + + /** + * Creates a mock instance of {@link StackWindowController}. + */ + public static StackWindowController createMockStackWindowContainerController() { + StackWindowController controller = mock(StackWindowController.class); + controller.mContainer = mock(TestTaskStack.class); + return controller; + } + + /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ + public static Task createTaskInStack(WindowManagerService service, TaskStack stack, + int userId) { + final Task newTask = new Task(WindowTestUtils.sNextTaskId++, stack, userId, service, null, + EMPTY, 0, false, + false, new ActivityManager.TaskDescription(), null); + stack.addTask(newTask, POSITION_TOP); + return newTask; + } + + /** + * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not + * normally be mocked out. + */ + public static class TestTaskStack extends TaskStack { + TestTaskStack(WindowManagerService service, int stackId) { + super(service, stackId); + } + + @Override + void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) { + // Do nothing. + } + } + + /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ + public static class TestAppWindowToken extends AppWindowToken { + + TestAppWindowToken(DisplayContent dc) { + super(WindowTestsBase.sWm, null, false, dc, true /* fillsParent */, + null /* overrideConfig */, null /* bounds */); + } + + TestAppWindowToken(WindowManagerService service, IApplicationToken token, + boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, + boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, + int rotationAnimationHint, int configChanges, boolean launchTaskBehind, + boolean alwaysFocusable, AppWindowContainerController controller, + Configuration overrideConfig, Rect bounds) { + super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, + showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, + launchTaskBehind, alwaysFocusable, controller, overrideConfig, bounds); + } + + int getWindowsCount() { + return mChildren.size(); + } + + boolean hasWindow(WindowState w) { + return mChildren.contains(w); + } + + WindowState getFirstChild() { + return mChildren.getFirst(); + } + + WindowState getLastChild() { + return mChildren.getLast(); + } + + int positionInParent() { + return getParent().mChildren.indexOf(this); + } + } + + /* Used so we can gain access to some protected members of the {@link WindowToken} class */ + public static class TestWindowToken extends WindowToken { + int adj = 0; + + TestWindowToken(int type, DisplayContent dc) { + this(type, dc, false /* persistOnEmpty */); + } + + TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { + super(WindowTestsBase.sWm, mock(IBinder.class), type, persistOnEmpty, dc, + false /* ownerCanManageAppTokens */); + } + + int getWindowsCount() { + return mChildren.size(); + } + + boolean hasWindow(WindowState w) { + return mChildren.contains(w); + } + + @Override + int getAnimLayerAdjustment() { + return adj; + } + } + + /* Used so we can gain access to some protected members of the {@link Task} class */ + public static class TestTask extends Task { + boolean mShouldDeferRemoval = false; + boolean mOnDisplayChangedCalled = false; + private boolean mUseLocalIsAnimating = false; + private boolean mIsAnimating = false; + + TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, + Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, + boolean homeTask, TaskWindowContainerController controller) { + super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode, + supportsPictureInPicture, homeTask, new ActivityManager.TaskDescription(), + controller); + } + + boolean shouldDeferRemoval() { + return mShouldDeferRemoval; + } + + int positionInParent() { + return getParent().mChildren.indexOf(this); + } + + @Override + void onDisplayChanged(DisplayContent dc) { + super.onDisplayChanged(dc); + mOnDisplayChangedCalled = true; + } + + @Override + boolean isAnimating() { + return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating(); + } + + void setLocalIsAnimating(boolean isAnimating) { + mUseLocalIsAnimating = true; + mIsAnimating = isAnimating; + } + } + + /** + * Used so we can gain access to some protected members of {@link TaskWindowContainerController} + * class. + */ + public static class TestTaskWindowContainerController extends TaskWindowContainerController { + + TestTaskWindowContainerController() { + this(WindowTestsBase.createStackControllerOnDisplay(WindowTestsBase.sDisplayContent)); + } + + TestTaskWindowContainerController(StackWindowController stackController) { + super(sNextTaskId++, new TaskWindowContainerListener() { + @Override + public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { + + } + + @Override + public void requestResize(Rect bounds, int resizeMode) { + + } + }, stackController, 0 /* userId */, null /* bounds */, + EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, + false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/, + true /* showForAllUsers */, new ActivityManager.TaskDescription(), WindowTestsBase.sWm); + } + + @Override + TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds, + Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, + boolean homeTask, ActivityManager.TaskDescription taskDescription) { + return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode, + supportsPictureInPicture, homeTask, this); + } + } + + public static class TestAppWindowContainerController extends AppWindowContainerController { + + final IApplicationToken mToken; + + TestAppWindowContainerController(TestTaskWindowContainerController taskController) { + this(taskController, new TestIApplicationToken()); + } + + TestAppWindowContainerController(TestTaskWindowContainerController taskController, + IApplicationToken token) { + super(taskController, token, null /* listener */, 0 /* index */, + SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */, + true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */, + false /* launchTaskBehind */, false /* alwaysFocusable */, + 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */, + 0 /* inputDispatchingTimeoutNanos */, WindowTestsBase.sWm, null /* overrideConfig */, + null /* bounds */); + mToken = token; + } + + @Override + AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, + boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, + boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, + int rotationAnimationHint, int configChanges, boolean launchTaskBehind, + boolean alwaysFocusable, AppWindowContainerController controller, + Configuration overrideConfig, Rect bounds) { + return new TestAppWindowToken(service, token, voiceInteraction, dc, + inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, + orientation, + rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, + controller, overrideConfig, bounds); + } + + AppWindowToken getAppWindowToken() { + return (AppWindowToken) WindowTestsBase.sDisplayContent.getWindowToken(mToken.asBinder()); + } + } + + public static class TestIApplicationToken implements IApplicationToken { + + private final Binder mBinder = new Binder(); + @Override + public IBinder asBinder() { + return mBinder; + } + } + + /** Used to track resize reports. */ + public static class TestWindowState extends WindowState { + boolean resizeReported; + + TestWindowState(WindowManagerService service, Session session, IWindow window, + WindowManager.LayoutParams attrs, WindowToken token) { + super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, + false /* ownerCanAddInternalSystemWindow */); + } + + @Override + void reportResized() { + super.reportResized(); + resizeReported = true; + } + + @Override + public boolean isGoneForLayoutLw() { + return false; + } + + @Override + void updateResizingWindowIfNeeded() { + // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive + // the system that it can actually update the window. + boolean hadSurface = mHasSurface; + mHasSurface = true; + + super.updateResizingWindowIfNeeded(); + + mHasSurface = hadSurface; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java index a9d930f5c893..eaf4ac4baf4f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -19,21 +19,16 @@ package com.android.server.wm; import static android.view.View.VISIBLE; import android.app.ActivityManager.TaskDescription; -import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; -import android.os.Binder; import android.view.Display; import android.view.DisplayInfo; -import android.view.IApplicationToken; import org.junit.Assert; import org.junit.After; import org.junit.Before; import org.mockito.MockitoAnnotations; -import android.app.ActivityManager.TaskSnapshot; import android.content.Context; -import android.os.IBinder; import android.support.test.InstrumentationRegistry; import android.view.IWindow; import android.view.WindowManager; @@ -41,10 +36,6 @@ import android.view.WindowManager; import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.AppOpsManager.OP_NONE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.content.res.Configuration.EMPTY; -import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; @@ -58,7 +49,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.mockito.Mockito.mock; import com.android.server.AttributeCache; @@ -78,8 +68,7 @@ class WindowTestsBase { // make sure we don't collide with any existing display. If we run into no other display, the // added display should be treated as default. This cannot be the default display private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1; - static int sNextStackId = FIRST_DYNAMIC_STACK_ID; - private static int sNextTaskId = 0; + private static int sNextStackId = FIRST_DYNAMIC_STACK_ID; private static boolean sOneTimeSetupDone = false; static DisplayContent sDisplayContent; @@ -184,14 +173,14 @@ class WindowTestsBase { private static WindowToken createWindowToken(DisplayContent dc, int stackId, int type) { if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { - return new TestWindowToken(type, dc); + return new WindowTestUtils.TestWindowToken(type, dc); } final TaskStack stack = stackId == INVALID_STACK_ID ? createTaskStackOnDisplay(dc) : createStackControllerOnStackOnDisplay(stackId, dc).mContainer; final Task task = createTaskInStack(stack, 0 /* userId */); - final TestAppWindowToken token = new TestAppWindowToken(dc); + final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc); task.addChild(token, 0); return token; } @@ -209,7 +198,7 @@ class WindowTestsBase { } WindowState createAppWindow(Task task, int type, String name) { - final AppWindowToken token = new TestAppWindowToken(sDisplayContent); + final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent); task.addChild(token, 0); return createWindow(null, type, token, name); } @@ -260,10 +249,7 @@ class WindowTestsBase { /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ static Task createTaskInStack(TaskStack stack, int userId) { - final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, 0, false, - false, new TaskDescription(), null); - stack.addTask(newTask, POSITION_TOP); - return newTask; + return WindowTestUtils.createTaskInStack(sWm, stack, userId); } /** Creates a {@link DisplayContent} and adds it to the system. */ @@ -274,227 +260,10 @@ class WindowTestsBase { return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm)); } - /* Used so we can gain access to some protected members of the {@link WindowToken} class */ - static class TestWindowToken extends WindowToken { - int adj = 0; - - TestWindowToken(int type, DisplayContent dc) { - this(type, dc, false /* persistOnEmpty */); - } - - TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { - super(sWm, mock(IBinder.class), type, persistOnEmpty, dc, - false /* ownerCanManageAppTokens */); - } - - int getWindowsCount() { - return mChildren.size(); - } - - boolean hasWindow(WindowState w) { - return mChildren.contains(w); - } - - @Override - int getAnimLayerAdjustment() { - return adj; - } - } - - /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ - static class TestAppWindowToken extends AppWindowToken { - - TestAppWindowToken(DisplayContent dc) { - super(sWm, null, false, dc, true /* fillsParent */, null /* overrideConfig */, - null /* bounds */); - } - - TestAppWindowToken(WindowManagerService service, IApplicationToken token, - boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, - boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, - int rotationAnimationHint, int configChanges, boolean launchTaskBehind, - boolean alwaysFocusable, AppWindowContainerController controller, - Configuration overrideConfig, Rect bounds) { - super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, - showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, - launchTaskBehind, alwaysFocusable, controller, overrideConfig, bounds); - } - - int getWindowsCount() { - return mChildren.size(); - } - - boolean hasWindow(WindowState w) { - return mChildren.contains(w); - } - - WindowState getFirstChild() { - return mChildren.getFirst(); - } - - WindowState getLastChild() { - return mChildren.getLast(); - } - - int positionInParent() { - return getParent().mChildren.indexOf(this); - } - } - - /* Used so we can gain access to some protected members of the {@link Task} class */ - class TestTask extends Task { - - boolean mShouldDeferRemoval = false; - boolean mOnDisplayChangedCalled = false; - private boolean mUseLocalIsAnimating = false; - private boolean mIsAnimating = false; - - TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, - Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, - boolean homeTask, TaskWindowContainerController controller) { - super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode, - supportsPictureInPicture, homeTask, new TaskDescription(), controller); - } - - boolean shouldDeferRemoval() { - return mShouldDeferRemoval; - } - - int positionInParent() { - return getParent().mChildren.indexOf(this); - } - - @Override - void onDisplayChanged(DisplayContent dc) { - super.onDisplayChanged(dc); - mOnDisplayChangedCalled = true; - } - - @Override - boolean isAnimating() { - return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating(); - } - - void setLocalIsAnimating(boolean isAnimating) { - mUseLocalIsAnimating = true; - mIsAnimating = isAnimating; - } - } - - /** - * Used so we can gain access to some protected members of {@link TaskWindowContainerController} - * class. - */ - class TestTaskWindowContainerController extends TaskWindowContainerController { - - TestTaskWindowContainerController() { - this(createStackControllerOnDisplay(sDisplayContent)); - } - - TestTaskWindowContainerController(StackWindowController stackController) { - super(sNextTaskId++, new TaskWindowContainerListener() { - @Override - public void onSnapshotChanged(TaskSnapshot snapshot) { - - } - - @Override - public void requestResize(Rect bounds, int resizeMode) { - - } - }, stackController, 0 /* userId */, null /* bounds */, - EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, - false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/, - true /* showForAllUsers */, new TaskDescription(), sWm); - } - - @Override - TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds, - Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, - boolean homeTask, TaskDescription taskDescription) { - return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode, - supportsPictureInPicture, homeTask, this); - } - } - - class TestAppWindowContainerController extends AppWindowContainerController { - - final IApplicationToken mToken; - - TestAppWindowContainerController(TestTaskWindowContainerController taskController) { - this(taskController, new TestIApplicationToken()); - } - - TestAppWindowContainerController(TestTaskWindowContainerController taskController, - IApplicationToken token) { - super(taskController, token, null /* listener */, 0 /* index */, - SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */, - true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */, - false /* launchTaskBehind */, false /* alwaysFocusable */, - 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */, - 0 /* inputDispatchingTimeoutNanos */, sWm, null /* overrideConfig */, - null /* bounds */); - mToken = token; - } - - @Override - AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, - boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, - boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, - int rotationAnimationHint, int configChanges, boolean launchTaskBehind, - boolean alwaysFocusable, AppWindowContainerController controller, - Configuration overrideConfig, Rect bounds) { - return new TestAppWindowToken(service, token, voiceInteraction, dc, - inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, - orientation, - rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, - controller, overrideConfig, bounds); - } - - AppWindowToken getAppWindowToken() { - return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder()); - } + /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ + WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs, + WindowToken token) { + return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token); } - class TestIApplicationToken implements IApplicationToken { - - private final Binder mBinder = new Binder(); - @Override - public IBinder asBinder() { - return mBinder; - } - } - - /** Used to track resize reports. */ - class TestWindowState extends WindowState { - boolean resizeReported; - - TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) { - super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0, - false /* ownerCanAddInternalSystemWindow */); - } - - @Override - void reportResized() { - super.reportResized(); - resizeReported = true; - } - - @Override - public boolean isGoneForLayoutLw() { - return false; - } - - @Override - void updateResizingWindowIfNeeded() { - // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive - // the system that it can actually update the window. - boolean hadSurface = mHasSurface; - mHasSurface = true; - - super.updateResizingWindowIfNeeded(); - - mHasSurface = hadSurface; - } - } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java index babb6d9db31f..4f7ad41050f1 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java @@ -46,7 +46,8 @@ public class WindowTokenTests extends WindowTestsBase { @Test public void testAddWindow() throws Exception { - final TestWindowToken token = new TestWindowToken(0, sDisplayContent); + final WindowTestUtils.TestWindowToken token = + new WindowTestUtils.TestWindowToken(0, sDisplayContent); assertEquals(0, token.getWindowsCount()); @@ -76,7 +77,7 @@ public class WindowTokenTests extends WindowTestsBase { @Test public void testChildRemoval() throws Exception { final DisplayContent dc = sDisplayContent; - final TestWindowToken token = new TestWindowToken(0, dc); + final WindowTestUtils.TestWindowToken token = new WindowTestUtils.TestWindowToken(0, dc); assertEquals(token, dc.getWindowToken(token.token)); @@ -95,7 +96,8 @@ public class WindowTokenTests extends WindowTestsBase { @Test public void testAdjustAnimLayer() throws Exception { - final TestWindowToken token = new TestWindowToken(0, sDisplayContent); + final WindowTestUtils.TestWindowToken token = + new WindowTestUtils.TestWindowToken(0, sDisplayContent); final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1"); final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11"); final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12"); @@ -135,8 +137,9 @@ public class WindowTokenTests extends WindowTestsBase { */ @Test public void testTokenRemovalProcess() throws Exception { - final TestWindowToken token = - new TestWindowToken(TYPE_TOAST, sDisplayContent, true /* persistOnEmpty */); + final WindowTestUtils.TestWindowToken token = + new WindowTestUtils.TestWindowToken(TYPE_TOAST, sDisplayContent, + true /* persistOnEmpty */); // Verify that the token is on the display assertNotNull(sDisplayContent.getWindowToken(token.token)); diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java index c34293347814..922f08da643f 100644 --- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java +++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java @@ -512,13 +512,6 @@ public class ShortcutManagerTestUtils { return actualShortcuts; } - public static List<ShortcutInfo> assertAllChooser(List<ShortcutInfo> actualShortcuts) { - for (ShortcutInfo s : actualShortcuts) { - assertTrue("ID " + s.getId(), s.isChooser()); - } - return actualShortcuts; - } - public static List<ShortcutInfo> assertAllPinned(List<ShortcutInfo> actualShortcuts) { for (ShortcutInfo s : actualShortcuts) { assertTrue("ID " + s.getId(), s.isPinned()); diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java index 7b8ebd44e629..01e36f57d1be 100644 --- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java @@ -1039,18 +1039,34 @@ class UsbProfileGroupSettingsManager { * Start the appropriate package when an device/accessory got attached. * * @param intent The intent to start the package - * @param matches The available resolutions of the intent + * @param rawMatches The available resolutions of the intent * @param defaultActivity The default activity for the device (if set) * @param device The device if a device was attached * @param accessory The accessory if a device was attached */ - private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches, + private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> rawMatches, @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device, @Nullable UsbAccessory accessory) { - int count = matches.size(); + final int numRawMatches = rawMatches.size(); + + // The raw matches contain the activities that can be started but also the intents to switch + // between the profiles + int numParentActivityMatches = 0; + int numNonParentActivityMatches = 0; + for (int i = 0; i < numRawMatches; i++) { + final ResolveInfo rawMatch = rawMatches.get(i); + if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { + if (UserHandle.getUserHandleForUid( + rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) { + numParentActivityMatches++; + } else { + numNonParentActivityMatches++; + } + } + } // don't show the resolver activity if there are no choices available - if (count == 0) { + if (numParentActivityMatches + numNonParentActivityMatches == 0) { if (accessory != null) { String uri = accessory.getUri(); if (uri != null && uri.length() > 0) { @@ -1073,6 +1089,21 @@ class UsbProfileGroupSettingsManager { return; } + // If only one profile has activity matches, we need to remove all switch intents + ArrayList<ResolveInfo> matches; + if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) { + matches = new ArrayList<>(numParentActivityMatches + numNonParentActivityMatches); + + for (int i = 0; i < numRawMatches; i++) { + ResolveInfo rawMatch = rawMatches.get(i); + if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { + matches.add(rawMatch); + } + } + } else { + matches = rawMatches; + } + if (defaultActivity != null) { UsbUserSettingsManager defaultRIUserSettings = mSettingsManager.getSettingsForUser( UserHandle.getUserId(defaultActivity.applicationInfo.uid)); @@ -1101,7 +1132,7 @@ class UsbProfileGroupSettingsManager { resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); UserHandle user; - if (count == 1) { + if (matches.size() == 1) { ResolveInfo rInfo = matches.get(0); // start UsbConfirmActivity if there is only one choice diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 201f3ad5dce7..81f660047c6b 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1178,6 +1178,7 @@ public class SubscriptionManager { public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) { if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + intent.putExtra(Intent.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); //FIXME this is using phoneId and slotIndex interchangeably //Eventually, this should be removed as it is not the slot id diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 061c0afa36aa..8357a2b535a4 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -877,19 +877,16 @@ public class TelephonyManager { /** * USSD return code success. - * @hide */ public static final int USSD_RETURN_SUCCESS = 100; /** * USSD return code for failure case. - * @hide */ public static final int USSD_RETURN_FAILURE = -1; /** * USSD return code for failure case. - * @hide */ public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; @@ -5113,16 +5110,32 @@ public class TelephonyManager { return new int[0]; } - public static abstract class OnReceiveUssdResponseCallback { + /* The caller of {@link #sendUssdRequest(String, UssdResponseCallback, Handler} provides + * once the network returns a USSD message or if there is failure. + * Either {@link #onReceiveUssdResponse(TelephonyManager, String, CharSequence} or + * {@link #onReceiveUssdResponseFailed(TelephonyManager, String, int} will be called. + */ + public static abstract class UssdResponseCallback { /** - ** Called when USSD has succeeded. + * Called when USSD has succeeded. The calling app can choose to either display the message + * or interpret the message. + * @param telephonyManager the TelephonyManager the callback is registered to. + * @param request the ussd code sent to the network. + * @param response the response from the network. **/ - public void onReceiveUssdResponse(String request, CharSequence response) {}; + public void onReceiveUssdResponse(final TelephonyManager telephonyManager, + String request, CharSequence response) {}; /** - ** Called when USSD has failed. + * Called when USSD has failed. + * @param telephonyManager the TelephonyManager the callback is registered to + * @param request the ussd code. + * @param failureCode failure code, should be either of + * {@link TelephonyManager#USSD_RETURN_FAILURE} or + * {@link TelephonyManager#USSD_ERROR_SERVICE_UNAVAIL}. **/ - public void onReceiveUssdResponseFailed(String request, int failureCode) {}; + public void onReceiveUssdResponseFailed(final TelephonyManager telephonyManager, + String request, int failureCode) {}; } /** @@ -5134,13 +5147,14 @@ public class TelephonyManager { * {@link android.Manifest.permission#CALL_PHONE} * @param ussdRequest the USSD command to be executed. * @param callback called by the framework to inform the caller of the result of executing the - * USSD request (see {@link OnReceiveUssdResponseCallback}). + * USSD request (see {@link UssdResponseCallback}). * @param handler the {@link Handler} to run the request on. */ @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String ussdRequest, - final OnReceiveUssdResponseCallback callback, Handler handler) { - checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null."); + final UssdResponseCallback callback, Handler handler) { + checkNotNull(callback, "UssdResponseCallback cannot be null."); + final TelephonyManager telephonyManager = this; ResultReceiver wrappedCallback = new ResultReceiver(handler) { @Override @@ -5150,10 +5164,11 @@ public class TelephonyManager { UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE); if (resultCode == USSD_RETURN_SUCCESS) { - callback.onReceiveUssdResponse(response.getUssdRequest(), + callback.onReceiveUssdResponse(telephonyManager, response.getUssdRequest(), response.getReturnMessage()); } else { - callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode); + callback.onReceiveUssdResponseFailed(telephonyManager, + response.getUssdRequest(), resultCode); } } }; @@ -5172,11 +5187,13 @@ public class TelephonyManager { } } - /* - * @return true, if the device is currently on a technology (e.g. UMTS or LTE) which can support - * voice and data simultaneously. This can change based on location or network condition. - */ - public boolean isConcurrentVoiceAndDataAllowed() { + /** + * Whether the device is currently on a technology (e.g. UMTS or LTE) which can support + * voice and data simultaneously. This can change based on location or network condition. + * + * @return {@code true} if simultaneous voice and data supported, and {@code false} otherwise. + */ + public boolean isConcurrentVoiceAndDataSupported() { try { ITelephony telephony = getITelephony(); return (telephony == null ? false : telephony.isConcurrentVoiceAndDataAllowed(mSubId)); diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 73ee25ad5bcf..b4c531e99a95 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -334,9 +334,11 @@ public class TelephonyIntents { * <ul> * <li><em>subscription</em> - A int, the current default subscription.</li> * </ul> + * @deprecated Use {@link Intent#ACTION_DEFAULT_SUBSCRIPTION_CHANGED} */ + @Deprecated public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED - = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED"; + = Intent.ACTION_DEFAULT_SUBSCRIPTION_CHANGED; /** * Broadcast Action: The default data subscription has changed. This has the following @@ -364,9 +366,11 @@ public class TelephonyIntents { * <ul> * <li><em>subscription</em> - A int, the current sms default subscription.</li> * </ul> + * @deprecated Use {@link Intent#ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED} */ + @Deprecated public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED - = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED"; + = Intent.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED; /* * Broadcast Action: An attempt to set phone radio type and access technology has changed. diff --git a/tests/WindowManagerStressTest/Android.mk b/tests/WindowManagerStressTest/Android.mk new file mode 100644 index 000000000000..e4cbe939e521 --- /dev/null +++ b/tests/WindowManagerStressTest/Android.mk @@ -0,0 +1,26 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := WindowManagerStressTest + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/WindowManagerStressTest/AndroidManifest.xml b/tests/WindowManagerStressTest/AndroidManifest.xml new file mode 100644 index 000000000000..17e0f15c29a9 --- /dev/null +++ b/tests/WindowManagerStressTest/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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="test.windowmanagerstresstest"> + + <application + android:allowBackup="false" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:supportsRtl="true" + android:theme="@style/AppTheme"> + <activity android:name=".MainActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/WindowManagerStressTest/res/layout/activity_main.xml b/tests/WindowManagerStressTest/res/layout/activity_main.xml new file mode 100644 index 000000000000..6cf82691155c --- /dev/null +++ b/tests/WindowManagerStressTest/res/layout/activity_main.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="@dimen/activity_vertical_margin" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + tools:context="test.amslam.MainActivity"> + + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/run" + android:text="@string/run" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/output" /> + +</LinearLayout> diff --git a/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000000..cde69bcccec6 --- /dev/null +++ b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png diff --git a/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000000..c133a0cbd379 --- /dev/null +++ b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png diff --git a/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000000..bfa42f0e7b91 --- /dev/null +++ b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png diff --git a/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000000..324e72cdd748 --- /dev/null +++ b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png diff --git a/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000000..aee44e138434 --- /dev/null +++ b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/tests/WindowManagerStressTest/res/values/colors.xml b/tests/WindowManagerStressTest/res/values/colors.xml new file mode 100644 index 000000000000..4270ca68a860 --- /dev/null +++ b/tests/WindowManagerStressTest/res/values/colors.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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> + <color name="colorPrimary">#3F51B5</color> + <color name="colorPrimaryDark">#303F9F</color> + <color name="colorAccent">#FF4081</color> +</resources> diff --git a/tests/WindowManagerStressTest/res/values/dimens.xml b/tests/WindowManagerStressTest/res/values/dimens.xml new file mode 100644 index 000000000000..ed4ccbcc700f --- /dev/null +++ b/tests/WindowManagerStressTest/res/values/dimens.xml @@ -0,0 +1,19 @@ +<!-- Copyright (C) 2016 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> + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> +</resources> diff --git a/tests/WindowManagerStressTest/res/values/strings.xml b/tests/WindowManagerStressTest/res/values/strings.xml new file mode 100644 index 000000000000..cef05dcb6584 --- /dev/null +++ b/tests/WindowManagerStressTest/res/values/strings.xml @@ -0,0 +1,19 @@ +<!-- + ~ Copyright (C) 2017 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> + <string name="app_name">WmSlam</string> + <string name="run">Run</string> +</resources> diff --git a/tests/WindowManagerStressTest/res/values/styles.xml b/tests/WindowManagerStressTest/res/values/styles.xml new file mode 100644 index 000000000000..0983b2535878 --- /dev/null +++ b/tests/WindowManagerStressTest/res/values/styles.xml @@ -0,0 +1,23 @@ +<!-- Copyright (C) 2016 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> + <!-- Base application theme. --> + <style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar"> + <!-- Customize your theme here. --> + <item name="android:colorPrimary">@color/colorPrimary</item> + <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="android:colorAccent">@color/colorAccent</item> + </style> +</resources> diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java new file mode 100644 index 000000000000..6b9bb31a75c7 --- /dev/null +++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2017 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 test.windowmanagerstresstest; + +import android.app.Activity; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Log; +import android.util.MergedConfiguration; +import android.view.Display; +import android.view.IWindowSession; +import android.view.Surface; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.view.WindowManagerGlobal; +import android.widget.TextView; + +import com.android.internal.view.BaseIWindow; + +import java.util.ArrayList; + +public class MainActivity extends Activity { + + private static final String TAG = "WmSlam"; + + private TextView mOutput; + private volatile boolean finished; + private final ArrayList<BaseIWindow> mWindows = new ArrayList<>(); + private final LayoutParams mLayoutParams = new LayoutParams(); + private final Rect mTmpRect = new Rect(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + mOutput = (TextView) findViewById(R.id.output); + + findViewById(R.id.run).setOnClickListener(view -> { + view.setEnabled(false); + mOutput.setText(""); + startBatch(); + }); + mLayoutParams.token = getActivityToken(); + } + + void startBatch() { + new Thread(() -> { + finished = false; + addWindows(); + startCpuRunnables(); + for (int i = 0; i < 5; i++) { + final long time = SystemClock.uptimeMillis(); + slamWm(); + log("Total: " + (SystemClock.uptimeMillis() - time) + " ms"); + } + removeWindows(); + finished = true; + }).start(); + } + + void startCpuRunnables() { + for (int i = 0; i < 10; i++) { + new Thread(mUseCpuRunnable).start(); + } + } + + private final Runnable mUseCpuRunnable = new Runnable() { + @Override + public void run() { + while (!finished) { + } + } + }; + + private void log(String text) { + mOutput.post(() -> mOutput.append(text + "\n")); + Log.d(TAG, text); + } + + private void slamWm() { + ArrayList<Thread> threads = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + for (BaseIWindow window : mWindows) { + Thread t = new Thread(() -> { + try { + WindowManagerGlobal.getWindowSession().relayout(window, + window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, mTmpRect, + mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, + new MergedConfiguration(), new Surface()); + } catch (RemoteException e) { + e.printStackTrace(); + } + }); + threads.add(t); + t.start(); + } + } + for (Thread t : threads) { + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + void addWindows() { + for (int i = 0; i < 50; i++) { + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); + layoutParams.token = getActivityToken(); + final BaseIWindow window = new BaseIWindow(); + final IWindowSession session = WindowManagerGlobal.getWindowSession(); + final Rect tmpRect = new Rect(); + try { + final int res = session.addToDisplayWithoutInputChannel(window, window.mSeq, layoutParams, + View.VISIBLE, Display.DEFAULT_DISPLAY, tmpRect, tmpRect); + } catch (RemoteException e) { + e.printStackTrace(); + } + mWindows.add(window); + } + } + + void removeWindows() { + for (BaseIWindow window : mWindows) { + try { + WindowManagerGlobal.getWindowSession().remove(window); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 04443a53527c..c562cb95ee31 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -80,6 +80,7 @@ import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.net.NetworkPinner; +import com.android.server.net.NetworkPolicyManagerInternal; import java.net.InetAddress; import java.util.ArrayList; @@ -713,6 +714,9 @@ public class ConnectivityServiceTest extends AndroidTestCase { } mServiceContext = new MockContext(getContext()); + LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); + LocalServices.addService( + NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); mService = new WrappedConnectivityService(mServiceContext, mock(INetworkManagementService.class), mock(INetworkStatsService.class), diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java index 7fe464abbf32..a21fe68e9003 100644 --- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java @@ -26,6 +26,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.AssetManager; import android.content.res.BridgeAssetManager; +import android.graphics.fonts.FontVariationAxis; import android.text.FontConfig; import java.awt.Font; @@ -250,7 +251,7 @@ public class FontFamily_Delegate { // ---- delegate methods ---- @LayoutlibDelegate /*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex, - FontConfig.Axis[] axes, int weight, int italic) { + FontVariationAxis[] axes, int weight, int italic) { if (thisFontFamily.mBuilderPtr == 0) { assert false : "Unable to call addFont after freezing."; return false; diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java index 80e3bada8ca3..c7818a3a9974 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -23,6 +23,7 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import android.annotation.NonNull; import android.graphics.FontFamily_Delegate.FontVariant; +import android.graphics.fonts.FontVariationAxis; import android.text.FontConfig; import java.awt.Font; @@ -163,7 +164,7 @@ public final class Typeface_Delegate { @LayoutlibDelegate /*package*/ static synchronized long nativeCreateFromTypefaceWithVariation(long native_instance, - List<FontConfig.Axis> axes) { + List<FontVariationAxis> axes) { long newInstance = nativeCreateFromTypeface(native_instance, 0); if (newInstance != 0) { |