diff options
232 files changed, 4024 insertions, 1900 deletions
diff --git a/Android.bp b/Android.bp index cb7f7a2317d3..ca1c614e6c02 100644 --- a/Android.bp +++ b/Android.bp @@ -1084,107 +1084,95 @@ framework_docs_args = "-android -manifest $(location core/res/AndroidManifest.xm "-federate SupportLib https://developer.android.com " + "-federationapi SupportLib $(location current/support-api.txt) " -doc_defaults { - name: "api-stubs-default", +framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " + + "-overview $(location core/java/overview.html) " + + // Federate Support Library references against local API file. + "-federate SupportLib https://developer.android.com " + + "-federationapi SupportLib $(location current/support-api.txt) " + +framework_docs_only_libs = [ + "conscrypt", + "bouncycastle", + "voip-common", + "android.test.mock", + "android-support-annotations", + "android-support-compat", + "android-support-core-ui", + "android-support-core-utils", + "android-support-customtabs", + "android-support-design", + "android-support-dynamic-animation", + "android-support-exifinterface", + "android-support-fragment", + "android-support-media-compat", + "android-support-percent", + "android-support-recommendation", + "android-support-transition", + "android-support-tv-provider", + "android-support-v7-cardview", + "android-support-v7-gridlayout", + "android-support-v7-mediarouter", + "android-support-v7-palette", + "android-support-v7-preference", + "android-support-v13", + "android-support-v14-preference", + "android-support-v17-leanback", + "android-support-v17-preference-leanback", + "android-support-wear", + "android-support-vectordrawable", + "android-support-animatedvectordrawable", + "android-support-v7-appcompat", + "android-support-v7-recyclerview", + "android-support-emoji", + "android-support-emoji-appcompat", + "android-support-emoji-bundled", + "android-support-v8-renderscript", + "android-support-multidex", + "android-support-multidex-instrumentation", +] + +metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " + + "--hide-package com.android.okhttp " + + "--hide-package com.android.org.conscrypt --hide-package com.android.server " + + "--hide RequiresPermission " + + "--hide MissingPermission --hide BroadcastBehavior " + + "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + + "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo" + +stubs_defaults { + name: "framework-doc-stubs-default", srcs: [ + "test-base/src/**/*.java", ":opt-telephony-srcs", ":opt-net-voip-srcs", ":openjdk_javadoc_files", ":non_openjdk_javadoc_files", ":android_icu4j_src_files_for_docs", + "test-mock/src/**/*.java", + "test-runner/src/**/*.java", ], srcs_lib: "framework", srcs_lib_whitelist_dirs: frameworks_base_subdirs, srcs_lib_whitelist_pkgs: packages_to_document, - libs: [ - "core-oj", - "core-libart", - "conscrypt", - "bouncycastle", - "okhttp", - "ext", - "framework", - "voip-common", - "android.test.mock.impl", - ], + libs: framework_docs_only_libs, local_sourcepaths: frameworks_base_subdirs, - html_dirs: [ - "docs/html", - ], - knowntags: [ - "docs/knowntags.txt", - ":known-oj-tags", + create_doc_stubs: true, + annotations_enabled: true, + api_levels_annotations_enabled: true, + api_levels_annotations_dirs: [ + "sdk-dir", + "api-versions-jars-dir", ], - custom_template: "droiddoc-templates-sdk", - hdf: [ - "dac true", - "sdk.codename O", - "sdk.preview.version 1", - "sdk.version 7.0", - "sdk.rel.id 1", - "sdk.preview 0", + previous_api: ":last-released-public-api", + merge_annotations_dirs: [ + "metalava-manual", + "ojluni-annotated-stubs", ], - resourcesdir: "docs/html/reference/images", - resourcesoutdir: "reference/android/images", - installable: false, } doc_defaults { name: "framework-docs-default", - srcs: [ - "test-base/src/**/*.java", - ":opt-telephony-srcs", - ":opt-net-voip-srcs", - ":openjdk_javadoc_files", - ":non_openjdk_javadoc_files", - ":android_icu4j_src_files_for_docs", - "test-mock/src/**/*.java", - "test-runner/src/**/*.java", - ], - srcs_lib: "framework", - srcs_lib_whitelist_dirs: frameworks_base_subdirs, - srcs_lib_whitelist_pkgs: packages_to_document, - libs: [ - "conscrypt", - "bouncycastle", - "voip-common", - "android.test.mock", - "android-support-annotations", - "android-support-compat", - "android-support-core-ui", - "android-support-core-utils", - "android-support-customtabs", - "android-support-design", - "android-support-dynamic-animation", - "android-support-exifinterface", - "android-support-fragment", - "android-support-media-compat", - "android-support-percent", - "android-support-recommendation", - "android-support-transition", - "android-support-tv-provider", - "android-support-v7-cardview", - "android-support-v7-gridlayout", - "android-support-v7-mediarouter", - "android-support-v7-palette", - "android-support-v7-preference", - "android-support-v13", - "android-support-v14-preference", - "android-support-v17-leanback", - "android-support-v17-preference-leanback", - "android-support-wear", - "android-support-vectordrawable", - "android-support-animatedvectordrawable", - "android-support-v7-appcompat", - "android-support-v7-recyclerview", - "android-support-emoji", - "android-support-emoji-appcompat", - "android-support-emoji-bundled", - "android-support-v8-renderscript", - "android-support-multidex", - "android-support-multidex-instrumentation", - ], - local_sourcepaths: frameworks_base_subdirs, + libs: framework_docs_only_libs, html_dirs: [ "docs/html", ], @@ -1205,22 +1193,12 @@ doc_defaults { ], arg_files: [ "core/res/AndroidManifest.xml", - ":api-version-xml", "core/java/overview.html", ":current-support-api", - "api/current.txt", ], create_stubs: false, } -metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " + - "--hide-package com.android.okhttp " + - "--hide-package com.android.org.conscrypt --hide-package com.android.server " + - "--hide RequiresPermission " + - "--hide MissingPermission --hide BroadcastBehavior " + - "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + - "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo" - stubs_defaults { name: "metalava-api-stubs-default", srcs: [ @@ -1254,21 +1232,45 @@ stubs_defaults { ], } +droidstubs { + name: "framework-doc-stubs", + defaults: ["framework-doc-stubs-default"], + arg_files: [ + "core/res/AndroidManifest.xml", + ], + args: metalava_framework_docs_args, +} + +droidstubs { + name: "framework-doc-system-stubs", + defaults: ["framework-doc-stubs-default"], + arg_files: [ + "core/res/AndroidManifest.xml", + ], + args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi ", +} + droiddoc { name: "doc-comment-check-docs", defaults: ["framework-docs-default"], - args: framework_docs_args + " -referenceonly -parsecomments", + srcs: [ + ":framework-doc-stubs", + ], + args: framework_docs_only_args + " -referenceonly -parsecomments", installable: false, } droiddoc { name: "offline-sdk-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], hdf: [ "android.whichdoc offline", ], proofread_file: "offline-sdk-docs-proofrerad.txt", - args: framework_docs_args + " -offlinemode -title \"Android SDK\"", + args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"", write_sdk_values: true, static_doc_index_redirect: "docs/docs-preview-index.html", } @@ -1276,11 +1278,14 @@ droiddoc { droiddoc { name: "offline-sdk-referenceonly-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], hdf: [ "android.whichdoc offline", ], proofread_file: "offline-sdk-referenceonly-docs-proofrerad.txt", - args: framework_docs_args + " -offlinemode -title \"Android SDK\" -referenceonly", + args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly", write_sdk_values: true, static_doc_index_redirect: "docs/docs-documentation-redirect.html", static_doc_properties: "docs/source.properties", @@ -1289,13 +1294,15 @@ droiddoc { droiddoc { name: "offline-system-sdk-referenceonly-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-system-stubs", + ], hdf: [ "android.whichdoc offline", ], proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt", - args: framework_docs_args + " -hide 101 -hide 104 -hide 108" + - " -showAnnotation android.annotation.SystemApi " + - " -offlinemode -title \"Android System SDK\" -referenceonly", + args: framework_docs_only_args + " -hide 101 -hide 104 -hide 108" + + " -offlinemode -title \"Android System SDK\" -referenceonly", write_sdk_values: true, static_doc_index_redirect: "docs/docs-documentation-redirect.html", static_doc_properties: "docs/source.properties", @@ -1304,12 +1311,15 @@ droiddoc { droiddoc { name: "online-sdk-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], hdf: [ "android.whichdoc online", "android.hasSamples true", ], proofread_file: "online-sdk-docs-proofrerad.txt", - args: framework_docs_args + + args: framework_docs_only_args + " -toroot / -samplegroup Admin " + " -samplegroup Background " + " -samplegroup Connectivity " + @@ -1330,14 +1340,16 @@ droiddoc { droiddoc { name: "online-system-api-sdk-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-system-stubs", + ], hdf: [ "android.whichdoc online", "android.hasSamples true", ], proofread_file: "online-system-api-sdk-docs-proofrerad.txt", - args: framework_docs_args + + args: framework_docs_only_args + " -referenceonly " + - " -showAnnotation android.annotation.SystemApi " + " -title \"Android SDK - Including system APIs.\" " + " -hide 101 " + " -hide 104 " + @@ -1363,12 +1375,15 @@ droiddoc { droiddoc { name: "ds-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], hdf: [ "android.whichdoc online", "android.hasSamples true", ], proofread_file: "ds-docs-proofrerad.txt", - args: framework_docs_args + + args: framework_docs_only_args + " -toroot / -samplegroup Admin " + " -samplegroup Background " + " -samplegroup Connectivity " + @@ -1389,11 +1404,14 @@ droiddoc { droiddoc { name: "ds-static-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], hdf: [ "android.whichdoc online", ], proofread_file: "ds-static-docs-proofrerad.txt", - args: framework_docs_args + + args: framework_docs_only_args + " -staticonly " + " -toroot / " + " -devsite " + @@ -1403,11 +1421,14 @@ droiddoc { droiddoc { name: "ds-ref-navtree-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], hdf: [ "android.whichdoc online", ], proofread_file: "ds-ref-navtree-docs-proofrerad.txt", - args: framework_docs_args + + args: framework_docs_only_args + " -toroot / " + " -atLinksNavtree " + " -navtreeonly ", @@ -1416,12 +1437,15 @@ droiddoc { droiddoc { name: "online-sdk-dev-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], hdf: [ "android.whichdoc online", "android.hasSamples true", ], proofread_file: "online-sdk-dev-docs-proofrerad.txt", - args: framework_docs_args + + args: framework_docs_only_args + " -toroot / -samplegroup Admin " + " -samplegroup Background " + " -samplegroup Connectivity " + @@ -1442,13 +1466,16 @@ droiddoc { droiddoc { name: "hidden-docs", defaults: ["framework-docs-default"], + srcs: [ + ":framework-doc-stubs", + ], proofread_file: "hidden-docs-proofrerad.txt", - args: framework_docs_args + + args: framework_docs_only_args + " -referenceonly " + " -title \"Android SDK - Including hidden APIs.\"", } -droiddoc { +droidstubs { name: "hwbinder-stubs-docs", srcs: [ "core/java/android/os/HidlSupport.java", @@ -1466,10 +1493,15 @@ droiddoc { "core/java/android/os/RemoteException.java", "core/java/android/util/AndroidException.java", ], - custom_template: "droiddoc-templates-sdk", installable: false, no_framework_libs: true, - args: "-showAnnotation android.annotation.SystemApi -nodocs -stubsourceonly", + annotations_enabled: true, + previous_api: ":last-released-public-api", + merge_annotations_dirs: [ + "metalava-manual", + "ojluni-annotated-stubs", + ], + args: " --show-annotation android.annotation.SystemApi", } java_library_static { @@ -1496,23 +1528,17 @@ droidstubs { } -droiddoc { +droidstubs { name: "hiddenapi-mappings", - defaults: ["api-stubs-default"], + defaults: ["metalava-api-stubs-default"], arg_files: [ "core/res/AndroidManifest.xml", - ":api-version-xml", - "core/java/overview.html", - ":current-support-api", - "api/current.txt", ], dex_mapping_filename: "dex-mapping.txt", - args: framework_docs_args + - " -referenceonly" + - " -nodocs" + - " -showUnannotated" + - " -showAnnotation android.annotation.SystemApi" + - " -showAnnotation android.annotation.TestApi", + args: metalava_framework_docs_args + + " --show-unannotated " + + " --show-annotation android.annotation.SystemApi " + + " --show-annotation android.annotation.TestApi " } filegroup { diff --git a/api/current.txt b/api/current.txt index ea21c2dd10b1..c1a1c52bbbbd 100755 --- a/api/current.txt +++ b/api/current.txt @@ -2905,6 +2905,7 @@ package android.accessibilityservice { field public static final deprecated int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8 field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20 field public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 512; // 0x200 + field public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 1024; // 0x400 field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4 field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40 field public int eventTypes; @@ -36594,9 +36595,9 @@ package android.provider { field public static final java.lang.String IS_PRIVATE = "isprivate"; field public static final java.lang.String LATITUDE = "latitude"; field public static final java.lang.String LONGITUDE = "longitude"; - field public static final java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic"; + field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic"; field public static final java.lang.String ORIENTATION = "orientation"; - field public static final java.lang.String PICASA_ID = "picasa_id"; + field public static final deprecated java.lang.String PICASA_ID = "picasa_id"; } public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns { @@ -36699,7 +36700,7 @@ package android.provider { field public static final java.lang.String LANGUAGE = "language"; field public static final java.lang.String LATITUDE = "latitude"; field public static final java.lang.String LONGITUDE = "longitude"; - field public static final java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic"; + field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic"; field public static final java.lang.String RESOLUTION = "resolution"; field public static final java.lang.String TAGS = "tags"; } diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h index 302b4ef7ae34..86d956ff75d8 100644 --- a/cmds/incidentd/src/Section.h +++ b/cmds/incidentd/src/Section.h @@ -171,7 +171,7 @@ private: */ class TombstoneSection : public WorkerThreadSection { public: - TombstoneSection(int id, const char* type, int64_t timeoutMs = 30000 /* 30 seconds */); + TombstoneSection(int id, const char* type, int64_t timeoutMs = 120000 /* 2 minutes */); virtual ~TombstoneSection(); virtual status_t BlockingCall(int pipeWriteFd) const; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2c07431ee38a..6ab4dd915178 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -132,6 +132,7 @@ message Atom { KeyValuePairsAtom key_value_pairs_atom = 83; VibratorStateChanged vibrator_state_changed = 84; DeferredJobStatsReported deferred_job_stats_reported = 85; + ThermalThrottlingStateChanged thermal_throttling = 86; } // Pulled events will start at field 10000. @@ -229,6 +230,26 @@ message KeyValuePairsAtom { */ /** + * Logs when the Thermal service HAL notifies the throttling start/stop events. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java + */ +message ThermalThrottlingStateChanged { + optional android.os.TemperatureTypeEnum sensor_type = 1; + + enum State { + UNKNOWN = 0; + START = 1; + STOP = 2; + } + + optional State state = 2; + + optional float temperature = 3; +} + +/** * Logs when the screen state changes. * * Logged from: @@ -2175,8 +2196,8 @@ message Temperature { /** * Pulls the statistics of calls to Binder. * - * Binder stats are cumulative from boot unless somebody reset the data using - * > adb shell dumpsys binder_calls_stats --reset + * Binder stats will be reset every time the data is pulled. It means it can only be pulled by one + * config on the device. * * Next tag: 14 */ diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index dbc13dc36ea7..f6ba0b6017be 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -168,7 +168,7 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, // temperature - {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}, + {android::util::TEMPERATURE, {{}, {}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}}, // binder_calls {android::util::BINDER_CALLS, {{4, 5, 6, 8, 12}, diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 5d37c5fdbaff..8c347fc7e169 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -2222,13 +2222,6 @@ Lcom/android/org/conscrypt/AbstractConscryptSocket;->setSoWriteTimeout(I)V Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setUseSessionTickets(Z)V -Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostname()Ljava/lang/String; -Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostnameOrIP()Ljava/lang/String; -Lcom/android/org/conscrypt/ConscryptSocketBase;->getSoWriteTimeout()I -Lcom/android/org/conscrypt/ConscryptSocketBase;->setHandshakeTimeout(I)V -Lcom/android/org/conscrypt/ConscryptSocketBase;->setHostname(Ljava/lang/String;)V -Lcom/android/org/conscrypt/ConscryptSocketBase;->setSoWriteTimeout(I)V -Lcom/android/org/conscrypt/ConscryptSocketBase;->socket:Ljava/net/Socket; Lcom/android/org/conscrypt/OpenSSLKey;-><init>(J)V Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey; Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY; diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 9a061b0eb79c..f2ad2683f4e0 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; import android.graphics.Region; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -446,7 +447,7 @@ public abstract class AccessibilityService extends Service { @UnsupportedAppUsage private AccessibilityServiceInfo mInfo; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private IBinder mWindowToken; private WindowManager mWindowManager; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 759443dcf476..aa0275a6b635 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -314,6 +314,12 @@ public class AccessibilityServiceInfo implements Parcelable { */ public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 0x00000200; + /** + * This flag requests that accessibility shortcut warning dialog has spoken feedback when + * dialog is shown. + */ + public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400; + /** {@hide} */ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; @@ -414,6 +420,7 @@ public class AccessibilityServiceInfo implements Parcelable { * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON + * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK */ public int flags; @@ -1050,6 +1057,8 @@ public class AccessibilityServiceInfo implements Parcelable { return "FLAG_REQUEST_ACCESSIBILITY_BUTTON"; case FLAG_REQUEST_FINGERPRINT_GESTURES: return "FLAG_REQUEST_FINGERPRINT_GESTURES"; + case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK: + return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK"; default: return null; } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 7b8664658422..5499d59fe0b3 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -847,7 +847,7 @@ public class Activity extends ContextThemeWrapper /*package*/ ActionBar mActionBar = null; private boolean mEnableDefaultActionBarUp; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private VoiceInteractor mVoiceInteractor; @UnsupportedAppUsage @@ -3523,7 +3523,7 @@ public class Activity extends ContextThemeWrapper * {@link android.view.Window#FEATURE_OPTIONS_PANEL} panel, * so that subclasses of Activity don't need to deal with feature codes. */ - public boolean onCreatePanelMenu(int featureId, Menu menu) { + public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) { if (featureId == Window.FEATURE_OPTIONS_PANEL) { boolean show = onCreateOptionsMenu(menu); show |= mFragments.dispatchCreateOptionsMenu(menu, getMenuInflater()); @@ -3541,8 +3541,8 @@ public class Activity extends ContextThemeWrapper * panel, so that subclasses of * Activity don't need to deal with feature codes. */ - public boolean onPreparePanel(int featureId, View view, Menu menu) { - if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) { + public boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { boolean goforit = onPrepareOptionsMenu(menu); goforit |= mFragments.dispatchPrepareOptionsMenu(menu); return goforit; @@ -3555,7 +3555,8 @@ public class Activity extends ContextThemeWrapper * * @return The default implementation returns true. */ - public boolean onMenuOpened(int featureId, Menu menu) { + @Override + public boolean onMenuOpened(int featureId, @NonNull Menu menu) { if (featureId == Window.FEATURE_ACTION_BAR) { initWindowDecorActionBar(); if (mActionBar != null) { @@ -3576,7 +3577,7 @@ public class Activity extends ContextThemeWrapper * panel, so that subclasses of * Activity don't need to deal with feature codes. */ - public boolean onMenuItemSelected(int featureId, MenuItem item) { + public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) { CharSequence titleCondensed = item.getTitleCondensed(); switch (featureId) { @@ -3626,7 +3627,7 @@ public class Activity extends ContextThemeWrapper * For context menus ({@link Window#FEATURE_CONTEXT_MENU}), the * {@link #onContextMenuClosed(Menu)} will be called. */ - public void onPanelClosed(int featureId, Menu menu) { + public void onPanelClosed(int featureId, @NonNull Menu menu) { switch (featureId) { case Window.FEATURE_OPTIONS_PANEL: mFragments.dispatchOptionsMenuClosed(menu); @@ -3734,7 +3735,7 @@ public class Activity extends ContextThemeWrapper * * @see #onCreateOptionsMenu */ - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(@NonNull MenuItem item) { if (mParent != null) { return mParent.onOptionsItemSelected(item); } @@ -3958,7 +3959,7 @@ public class Activity extends ContextThemeWrapper * @return boolean Return false to allow normal context menu processing to * proceed, true to consume it here. */ - public boolean onContextItemSelected(MenuItem item) { + public boolean onContextItemSelected(@NonNull MenuItem item) { if (mParent != null) { return mParent.onContextItemSelected(item); } @@ -3972,7 +3973,7 @@ public class Activity extends ContextThemeWrapper * * @param menu The context menu that is being closed. */ - public void onContextMenuClosed(Menu menu) { + public void onContextMenuClosed(@NonNull Menu menu) { if (mParent != null) { mParent.onContextMenuClosed(menu); } @@ -6385,11 +6386,13 @@ public class Activity extends ContextThemeWrapper * closed for you after you return. * @param args additional arguments to the dump request. */ - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + public void dump(@NonNull String prefix, @Nullable FileDescriptor fd, + @NonNull PrintWriter writer, @Nullable String[] args) { dumpInner(prefix, fd, writer, args); } - void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd, + @NonNull PrintWriter writer, @Nullable String[] args) { if (args != null && args.length > 0 && args[0].equals("--autofill")) { dumpAutofillManager(prefix, writer); return; @@ -7097,7 +7100,7 @@ public class Activity extends ContextThemeWrapper // ------------------ Internal API ------------------ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final void setParent(Activity parent) { mParent = parent; } @@ -7208,7 +7211,7 @@ public class Activity extends ContextThemeWrapper mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions()); } - final void performNewIntent(Intent intent) { + final void performNewIntent(@NonNull Intent intent) { mCanEnterPictureInPicture = true; onNewIntent(intent); } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 8354235544ff..e86a49d93cf9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1221,7 +1221,7 @@ public class ActivityManager { * @return The background color. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int getBackgroundColor() { return mColorBackground; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 0e884d67d011..31e9a2d5daaf 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -340,7 +340,7 @@ public final class ActivityThread extends ClientTransactionHandler { // An executor that performs multi-step transactions. private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final ResourcesManager mResourcesManager; private static final class ProviderKey { @@ -374,7 +374,7 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<IBinder, ProviderRefCount>(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<IBinder, ProviderClientRecord>(); @UnsupportedAppUsage @@ -394,7 +394,7 @@ public final class ActivityThread extends ClientTransactionHandler { final GcIdler mGcIdler = new GcIdler(); boolean mGcIdlerScheduled = false; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) static volatile Handler sMainThreadHandler; // set once in main() Bundle mCoreSettings = null; @@ -456,7 +456,7 @@ public final class ActivityThread extends ClientTransactionHandler { private int mLifecycleState = PRE_ON_CREATE; @VisibleForTesting - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public ActivityClientRecord() { this.isForward = false; init(); @@ -704,7 +704,7 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage boolean persistent; Configuration config; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) CompatibilityInfo compatInfo; String buildSerial; @@ -2088,7 +2088,7 @@ public final class ActivityThread extends ClientTransactionHandler { return mH; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo, int flags) { return getPackageInfo(packageName, compatInfo, flags, UserHandle.myUserId()); @@ -2177,7 +2177,7 @@ public final class ActivityThread extends ClientTransactionHandler { return getPackageInfo(ai, compatInfo, null, false, true, false); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) { synchronized (mResourcesManager) { WeakReference<LoadedApk> ref; @@ -2850,7 +2850,7 @@ public final class ActivityThread extends ClientTransactionHandler { return aInfo; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final Activity startActivityNow(Activity parent, String id, Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state, Activity.NonConfigurationInstances lastNonConfigurationInstances) { diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index dbc8c5d1727b..cf40e067e5b1 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -397,7 +397,7 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener The {@link DialogInterface.OnClickListener} to use. * @deprecated Use * {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)} - * with {@link DialogInterface#BUTTON_POSITIVE} + * with {@link DialogInterface#BUTTON_NEUTRAL} */ @Deprecated public void setButton3(CharSequence text, final OnClickListener listener) { diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java index 10989902fea8..2a13c7198b3f 100644 --- a/core/java/android/app/ContentProviderHolder.java +++ b/core/java/android/app/ContentProviderHolder.java @@ -20,6 +20,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.ContentProviderNative; import android.content.IContentProvider; import android.content.pm.ProviderInfo; +import android.os.Build; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -35,7 +36,7 @@ public class ContentProviderHolder implements Parcelable { @UnsupportedAppUsage public IContentProvider provider; public IBinder connection; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean noReleaseNeeded; @UnsupportedAppUsage diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index bbaaee8eed44..77f639535b15 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -164,7 +164,7 @@ class ContextImpl extends Context { * Map from preference name to generated path. */ @GuardedBy("ContextImpl.class") - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private ArrayMap<String, File> mSharedPrefsPaths; @UnsupportedAppUsage @@ -183,7 +183,7 @@ class ContextImpl extends Context { @UnsupportedAppUsage private final String mBasePackageName; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final String mOpPackageName; private final @NonNull ResourcesManager mResourcesManager; @@ -191,7 +191,7 @@ class ContextImpl extends Context { private @NonNull Resources mResources; private @Nullable Display mDisplay; // may be null if default display - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int mFlags; @UnsupportedAppUsage diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index b7bac52178b0..6bcfb2e8fe9e 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -34,6 +34,7 @@ import android.content.res.Configuration; import android.content.res.ResourceId; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -133,7 +134,7 @@ public class Dialog implements DialogInterface, Window.Callback, private final Handler mHandler = new Handler(); private static final int DISMISS = 0x43; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private static final int CANCEL = 0x44; private static final int SHOW = 0x45; @@ -936,8 +937,8 @@ public class Dialog implements DialogInterface, Window.Callback, * @see Activity#onPreparePanel(int, View, Menu) */ @Override - public boolean onPreparePanel(int featureId, View view, Menu menu) { - if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) { + public boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { return onPrepareOptionsMenu(menu) && menu.hasVisibleItems(); } return true; @@ -947,7 +948,7 @@ public class Dialog implements DialogInterface, Window.Callback, * @see Activity#onMenuOpened(int, Menu) */ @Override - public boolean onMenuOpened(int featureId, Menu menu) { + public boolean onMenuOpened(int featureId, @NonNull Menu menu) { if (featureId == Window.FEATURE_ACTION_BAR) { mActionBar.dispatchMenuVisibilityChanged(true); } @@ -958,7 +959,7 @@ public class Dialog implements DialogInterface, Window.Callback, * @see Activity#onMenuItemSelected(int, MenuItem) */ @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { + public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) { return false; } @@ -966,7 +967,7 @@ public class Dialog implements DialogInterface, Window.Callback, * @see Activity#onPanelClosed(int, Menu) */ @Override - public void onPanelClosed(int featureId, Menu menu) { + public void onPanelClosed(int featureId, @NonNull Menu menu) { if (featureId == Window.FEATURE_ACTION_BAR) { mActionBar.dispatchMenuVisibilityChanged(false); } diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 35999a223938..1622c06b0a34 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -879,7 +879,7 @@ public class DownloadManager { * @return this object * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public Query orderBy(String column, int direction) { if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) { throw new IllegalArgumentException("Invalid direction: " + direction); @@ -1011,7 +1011,7 @@ public class DownloadManager { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void setAccessFilename(boolean accessFilename) { mAccessFilename = accessFilename; } diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 9f4157f007f1..49917b40521d 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -264,7 +264,7 @@ import java.lang.reflect.InvocationTargetException; */ @Deprecated public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private static final ArrayMap<String, Class<?>> sClassMap = new ArrayMap<String, Class<?>>(); diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 3085fe58c8e6..b720df8afc8f 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -29,6 +29,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -415,7 +416,7 @@ public class KeyguardManager { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean isDeviceLocked(int userId) { try { return mTrustManager.isDeviceLocked(userId); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index ddd944186705..b827d01314ce 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -111,7 +111,7 @@ public final class LoadedApk { private String mDataDir; @UnsupportedAppUsage private String mLibDir; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private File mDataDirFile; private File mDeviceProtectedDataDirFile; private File mCredentialProtectedDataDirFile; @@ -141,7 +141,7 @@ public final class LoadedApk { = new ArrayMap<>(); private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers = new ArrayMap<>(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices = new ArrayMap<>(); private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices @@ -1358,7 +1358,7 @@ public final class LoadedApk { final IIntentReceiver.Stub mIIntentReceiver; @UnsupportedAppUsage final BroadcastReceiver mReceiver; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final Context mContext; final Handler mActivityThread; final Instrumentation mInstrumentation; @@ -1605,7 +1605,7 @@ public final class LoadedApk { private final ServiceDispatcher.InnerConnection mIServiceConnection; @UnsupportedAppUsage private final ServiceConnection mConnection; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final Context mContext; private final Handler mActivityThread; private final ServiceConnectionLeaked mLocation; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 491af6094d96..217225e90f78 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1417,7 +1417,7 @@ public class Notification implements Parcelable public static final int SEMANTIC_ACTION_CALL = 10; private final Bundle mExtras; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Icon mIcon; private final RemoteInput[] mRemoteInputs; private boolean mAllowGeneratedReplies = true; diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index dbb6c3d0ee07..c0903b65737c 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -29,6 +29,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManagerGlobal; +import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -193,7 +194,7 @@ public final class UiAutomation { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public UiAutomation(Looper looper, IUiAutomationConnection connection) { if (looper == null) { throw new IllegalArgumentException("Looper cannot be null!"); @@ -210,7 +211,7 @@ public final class UiAutomation { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void connect() { connect(0); } @@ -282,7 +283,7 @@ public final class UiAutomation { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void disconnect() { synchronized (mLock) { if (mIsConnecting) { diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 2a263d6de2d4..bebe79e41e5b 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1288,7 +1288,7 @@ public class WallpaperManager { * requires permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, @SetWallpaperFlags int which, int userId) throws IOException { diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index 9baa16f2b72b..556ffa24368f 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -36,6 +36,7 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.Uri; import android.os.BaseBundle; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -311,7 +312,7 @@ public class JobInfo implements Parcelable { private final long initialBackoffMillis; private final int backoffPolicy; private final int priority; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int flags; /** diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 0994332bcdc7..dbb00eb5c288 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -25,6 +25,7 @@ import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.content.Context; import android.content.pm.ParceledListSlice; +import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; @@ -235,7 +236,7 @@ public final class UsageStatsManager { @UnsupportedAppUsage private static final UsageEvents sEmptyResults = new UsageEvents(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final Context mContext; @UnsupportedAppUsage private final IUsageStatsManager mService; diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index d21f76d435e6..466b9cee10a0 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -571,7 +572,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH) - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int getPriority(BluetoothDevice device) { if (VDBG) log("getPriority(" + device + ")"); try { diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 78248efdd048..29d5a1c583a1 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -17,6 +17,7 @@ package android.bluetooth; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Handler; import android.os.ParcelUuid; import android.os.RemoteException; @@ -52,7 +53,7 @@ public final class BluetoothGatt implements BluetoothProfile { private BluetoothDevice mDevice; @UnsupportedAppUsage private boolean mAutoConnect; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mAuthRetryState; private int mConnState; private final Object mStateLock = new Object(); diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 9777b5cc6cdc..3c3a01b191e6 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -21,6 +21,7 @@ import android.Manifest; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import java.util.List; @@ -86,7 +87,7 @@ public interface BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) int PAN = 5; /** diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index b55fe7618b94..8691ed43ac81 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -21,6 +21,7 @@ import android.app.ActivityManager; import android.app.ActivityThread; import android.app.IActivityManager; import android.app.QueuedWork; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -71,22 +72,22 @@ public abstract class BroadcastReceiver { /** @hide */ public static final int TYPE_UNREGISTERED = 2; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final int mType; @UnsupportedAppUsage final boolean mOrderedHint; @UnsupportedAppUsage final boolean mInitialStickyHint; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final IBinder mToken; @UnsupportedAppUsage final int mSendingUser; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final int mFlags; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) int mResultCode; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) String mResultData; @UnsupportedAppUsage Bundle mResultExtras; @@ -96,7 +97,7 @@ public abstract class BroadcastReceiver { boolean mFinished; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type, boolean ordered, boolean sticky, IBinder token, int userId, int flags) { mResultCode = resultCode; diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 2b7ea66d2054..089cf1098ffc 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -25,6 +25,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.net.Uri; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.StrictMode; @@ -198,7 +199,7 @@ public class ClipData implements Parcelable { final CharSequence mText; final String mHtmlText; final Intent mIntent; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) Uri mUri; /** @hide */ diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index f5339efb8d60..bd1e6a462805 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -37,6 +37,7 @@ import android.database.SQLException; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; @@ -163,7 +164,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * in the test, which is available via {@link #getPathPermissions()}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public ContentProvider( Context context, String readPermission, diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index 04be572ad97a..d315f4945ffe 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -24,6 +24,7 @@ import android.database.CrossProcessCursorWrapper; import android.database.Cursor; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; import android.os.DeadObjectException; @@ -73,7 +74,7 @@ public class ContentProviderClient implements AutoCloseable { private final ContentResolver mContentResolver; @UnsupportedAppUsage private final IContentProvider mContentProvider; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final String mPackageName; private final boolean mStable; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 80e79a305f97..2ae3ae6f1f64 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -327,6 +327,15 @@ public abstract class Context { public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080; /** + * Flag for {@link #bindService}: If binding from something better than perceptible, + * still set the adjust below perceptible. This would be used for bound services that can + * afford to be evicted when under extreme memory pressure, but should be restarted as soon + * as possible. + * @hide + */ + public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100; + + /** * @hide Flag for {@link #bindService}: allows binding to a service provided * by an instant app. Note that the caller may not have access to the instant * app providing the service which is a violation of the instant app sandbox. @@ -3407,7 +3416,7 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a - * {@link android.app.NotificationManager} for controlling keyguard. + * {@link android.app.KeyguardManager} for controlling keyguard. * * @see #getSystemService(String) * @see android.app.KeyguardManager @@ -3431,7 +3440,7 @@ public abstract class Context { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static final String COUNTRY_DETECTOR = "country_detector"; /** diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index d814e676886e..044ed61470ea 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -21,6 +21,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.ICancellationSignal; @@ -80,7 +81,7 @@ public interface IContentProvider extends IInterface { Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException; /* IPC constants */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) static final String descriptor = "android.content.IContentProvider"; @UnsupportedAppUsage diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 212e13262433..0dd618657004 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.net.Uri; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.PatternMatcher; @@ -655,7 +656,7 @@ public class IntentFilter implements Parcelable { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final boolean isVerified() { if ((mVerifyState & STATE_NEED_VERIFY_CHECKED) == STATE_NEED_VERIFY_CHECKED) { return ((mVerifyState & STATE_NEED_VERIFY) == STATE_NEED_VERIFY); diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java index 33395ec37d9d..bbdab048207b 100644 --- a/core/java/android/content/RestrictionsManager.java +++ b/core/java/android/content/RestrictionsManager.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; import android.os.RemoteException; @@ -403,7 +404,7 @@ public class RestrictionsManager { private static final String TAG_RESTRICTION = "restriction"; private final Context mContext; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final IRestrictionsManager mService; /** diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java index fd12d7acc8d7..c18b2823ed47 100644 --- a/core/java/android/content/SyncRequest.java +++ b/core/java/android/content/SyncRequest.java @@ -18,6 +18,7 @@ package android.content; import android.accounts.Account; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -33,10 +34,10 @@ public class SyncRequest implements Parcelable { @UnsupportedAppUsage private final Account mAccountToSync; /** Authority string that corresponds to a ContentProvider. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final String mAuthority; /** Bundle containing user info as well as sync settings. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final Bundle mExtras; /** Don't allow this sync request on metered networks. */ private final boolean mDisallowMetered; diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 46877ca9fe5c..44e652f10094 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -42,6 +42,7 @@ import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -136,7 +137,7 @@ public class LauncherApps { "android.content.pm.extra.PIN_ITEM_REQUEST"; private final Context mContext; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final ILauncherApps mService; @UnsupportedAppUsage private final PackageManager mPm; diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 316ace16f0a4..8fab7bb0ad4e 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -32,6 +32,7 @@ import android.content.pm.PackageManager.DeleteFlags; import android.content.pm.PackageManager.InstallReason; import android.graphics.Bitmap; import android.net.Uri; +import android.os.Build; import android.os.FileBridge; import android.os.Handler; import android.os.Looper; @@ -960,6 +961,10 @@ public class PackageInstaller { * If the installer is the device owner or the affiliated profile owner, there will be no * user intervention. * + * @param statusReceiver Called when the state of the session changes. Intents + * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the + * individual status codes on how to handle them. + * * @throws SecurityException if streams opened through * {@link #openWrite(String, long, long)} are still open. * @@ -986,7 +991,9 @@ public class PackageInstaller { * that new properties are added to the session with a new API revision. In this case the * callers need to be updated. * - * @param statusReceiver Callbacks called when the state of the session changes. + * @param statusReceiver Called when the state of the session changes. Intents + * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the + * individual status codes on how to handle them. * * @hide */ @@ -1091,7 +1098,7 @@ public class PackageInstaller { public static final int UID_UNKNOWN = -1; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int mode = MODE_INVALID; /** {@hide} */ @UnsupportedAppUsage @@ -1104,13 +1111,13 @@ public class PackageInstaller { @UnsupportedAppUsage public long sizeBytes = -1; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public String appPackageName; /** {@hide} */ @UnsupportedAppUsage public Bitmap appIcon; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public String appLabel; /** {@hide} */ public long appIconLastModified = -1; @@ -1435,40 +1442,40 @@ public class PackageInstaller { public static class SessionInfo implements Parcelable { /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int sessionId; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public String installerPackageName; /** {@hide} */ @UnsupportedAppUsage public String resolvedBaseCodePath; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public float progress; /** {@hide} */ @UnsupportedAppUsage public boolean sealed; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean active; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int mode; /** {@hide} */ public @InstallReason int installReason; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public long sizeBytes; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public String appPackageName; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public Bitmap appIcon; /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public CharSequence appLabel; /** {@hide} */ diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 20e1454e6276..b5b4432bbdb2 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -136,24 +136,6 @@ public abstract class PackageManagerInternal { public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider); /** - * Sets the SMS packages provider. - * @param provider The packages provider. - */ - public abstract void setSmsAppPackagesProvider(PackagesProvider provider); - - /** - * Sets the dialer packages provider. - * @param provider The packages provider. - */ - public abstract void setDialerAppPackagesProvider(PackagesProvider provider); - - /** - * Sets the sim call manager packages provider. - * @param provider The packages provider. - */ - public abstract void setSimCallManagerPackagesProvider(PackagesProvider provider); - - /** * Sets the Use Open Wifi packages provider. * @param provider The packages provider. */ @@ -166,26 +148,28 @@ public abstract class PackageManagerInternal { public abstract void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider); /** - * Requests granting of the default permissions to the current default SMS app. - * @param packageName The default SMS package name. - * @param userId The user for which to grant the permissions. + * Called when the package for the default dialer changed + * + * @param packageName the new dialer package + * @param userId user for which the change was made */ - public abstract void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId); + public void onDefaultDialerAppChanged(String packageName, int userId) {} /** - * Requests granting of the default permissions to the current default dialer app. - * @param packageName The default dialer package name. - * @param userId The user for which to grant the permissions. + * Called when the package for the default SMS handler changed + * + * @param packageName the new sms package + * @param userId user for which the change was made */ - public abstract void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId); + public void onDefaultSmsAppChanged(String packageName, int userId) {} /** - * Requests granting of the default permissions to the current default sim call manager. - * @param packageName The default sim call manager package name. - * @param userId The user for which to grant the permissions. + * Called when the package for the default sim call manager changed + * + * @param packageName the new sms package + * @param userId user for which the change was made */ - public abstract void grantDefaultPermissionsToDefaultSimCallManager(String packageName, - int userId); + public void onDefaultSimCallManagerAppChanged(String packageName, int userId) {} /** * Requests granting of the default permissions to the current default Use Open Wifi app. @@ -446,8 +430,8 @@ public abstract class PackageManagerInternal { * * @param packageName The package to check for * @param uid the uid in which the package is running - * @return {@link USER_TRUSTED} if the user has trusted the package, {@link USER_BLOCKED} - * if user has blocked requests from the package, {@link USER_DEFAULT} if the user response + * @return {@link #USER_TRUSTED} if the user has trusted the package, {@link #USER_BLOCKED} + * if user has blocked requests from the package, {@link #USER_DEFAULT} if the user response * is not yet available */ int getPackageTrustedToInstallApps(String packageName, int uid); @@ -561,7 +545,7 @@ public abstract class PackageManagerInternal { /** * Returns a list without a change observer. * - * {@see #getPackageList(PackageListObserver)} + * @see #getPackageList(PackageListObserver) */ public @NonNull PackageList getPackageList() { return getPackageList(null); @@ -590,7 +574,16 @@ public abstract class PackageManagerInternal { /** * Returns a package object for the disabled system package name. */ - public abstract @Nullable PackageParser.Package getDisabledPackage(@NonNull String packageName); + public abstract @Nullable PackageParser.Package getDisabledSystemPackage( + @NonNull String packageName); + + /** + * Returns the package name for the disabled system package. + * + * This is equivalent to + * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName} + */ + public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName); /** * Returns whether or not the component is the resolver activity. @@ -619,7 +612,7 @@ public abstract class PackageManagerInternal { * Access may be limited based upon whether the calling or target applications * are instant applications. * - * @see #canAccessInstantApps(int) + * @see #canAccessInstantApps */ public abstract boolean filterAppAccess( @Nullable PackageParser.Package pkg, int callingUid, int userId); @@ -635,6 +628,9 @@ public abstract class PackageManagerInternal { public abstract void updatePermissionFlagsTEMP(@NonNull String permName, @NonNull String packageName, int flagMask, int flagValues, int userId); + /** Returns whether the given package was signed by the platform */ + public abstract boolean isPlatformSigned(String pkg); + /** * Returns true if it's still safe to restore data backed up from this app's version * that was signed with restoringFromSigHash. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 6d493627785f..03a3d1f438ff 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1902,7 +1902,7 @@ public class PackageParser { * @throws XmlPullParserException * @throws IOException */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { final String splitName; diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java index 2eef16584c9d..dccc52494f59 100644 --- a/core/java/android/content/pm/ParceledListSlice.java +++ b/core/java/android/content/pm/ParceledListSlice.java @@ -17,6 +17,7 @@ package android.content.pm; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -72,7 +73,7 @@ public class ParceledListSlice<T extends Parcelable> extends BaseParceledListSli } @SuppressWarnings("unchecked") - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static final Parcelable.ClassLoaderCreator<ParceledListSlice> CREATOR = new Parcelable.ClassLoaderCreator<ParceledListSlice>() { public ParceledListSlice createFromParcel(Parcel in) { diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 546c21331dbd..ec2e2fd474a2 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -30,6 +30,7 @@ import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.graphics.Bitmap; import android.graphics.drawable.Icon; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -1243,7 +1244,7 @@ public final class ShortcutInfo implements Parcelable { * @hide */ @Nullable - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public Icon getIcon() { return mIcon; } diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index 60ac1f08ba66..2d590033259f 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.graphics.drawable.AdaptiveIconDrawable; +import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.RemoteException; import android.os.ServiceManager; @@ -55,7 +56,7 @@ public class ShortcutManager { private static final String TAG = "ShortcutManager"; private final Context mContext; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final IShortcutService mService; /** diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index c6c2aa57f533..8bcaa4526fa7 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -19,6 +19,7 @@ package android.database; import android.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.UserHandle; import android.util.Log; @@ -79,7 +80,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { private final DataSetObservable mDataSetObservable = new DataSetObservable(); private final ContentObservable mContentObservable = new ContentObservable(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Bundle mExtras = Bundle.EMPTY; /* -------------------------------------------------------- */ diff --git a/core/java/android/database/sqlite/SQLiteCustomFunction.java b/core/java/android/database/sqlite/SQLiteCustomFunction.java index ec204581aef5..41b78d3a7745 100644 --- a/core/java/android/database/sqlite/SQLiteCustomFunction.java +++ b/core/java/android/database/sqlite/SQLiteCustomFunction.java @@ -17,6 +17,7 @@ package android.database.sqlite; import android.annotation.UnsupportedAppUsage; +import android.os.Build; /** * Describes a custom SQL function. @@ -24,7 +25,7 @@ import android.annotation.UnsupportedAppUsage; * @hide */ public final class SQLiteCustomFunction { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final String name; @UnsupportedAppUsage public final int numArgs; diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java index b705ebb77d9b..4fce2d7fe0df 100644 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java @@ -34,6 +34,7 @@ import libcore.util.EmptyArray; import java.util.Arrays; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -50,6 +51,8 @@ public class SQLiteQueryBuilder { Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?"); private Map<String, String> mProjectionMap = null; + private List<Pattern> mProjectionGreylist = null; + @UnsupportedAppUsage private String mTables = ""; @UnsupportedAppUsage @@ -164,6 +167,17 @@ public class SQLiteQueryBuilder { } /** + * Sets a projection greylist of columns that will be allowed through, even + * when {@link #setStrict(boolean)} is enabled. This provides a way for + * abusive custom columns like {@code COUNT(*)} to continue working. + * + * @hide + */ + public void setProjectionGreylist(List<Pattern> projectionGreylist) { + mProjectionGreylist = projectionGreylist; + } + + /** * Sets the cursor factory to be used for the query. You can use * one factory for all queries on a database but it is normally * easier to specify the factory when doing this query. @@ -809,6 +823,24 @@ public class SQLiteQueryBuilder { continue; } + // If greylist is configured, we might be willing to let + // this custom column bypass our strict checks. + if (mProjectionGreylist != null) { + boolean match = false; + for (Pattern p : mProjectionGreylist) { + if (p.matcher(userColumn).matches()) { + match = true; + break; + } + } + + if (match) { + Log.w(TAG, "Allowing abusive custom column: " + userColumn); + projection[i] = userColumn; + continue; + } + } + throw new IllegalArgumentException("Invalid column " + projectionIn[i]); } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 8e96f56e8cd3..ac863b2a45af 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -31,6 +31,7 @@ import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.media.AudioAttributes; import android.media.IAudioService; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -165,7 +166,7 @@ public class Camera { private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400; private static final int CAMERA_MSG_FOCUS_MOVE = 0x800; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private long mNativeContext; // accessed by native methods private EventHandler mEventHandler; private ShutterCallback mShutterCallback; @@ -721,7 +722,7 @@ public class Camera { /** * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public native final void setPreviewSurface(Surface surface) throws IOException; /** diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java index c17aabb9c31d..d2c0e7be5900 100644 --- a/core/java/android/hardware/HardwareBuffer.java +++ b/core/java/android/hardware/HardwareBuffer.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -184,7 +185,7 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable { * Private use only. See {@link #create(int, int, int, int, long)}. May also be * called from JNI using an already allocated native <code>HardwareBuffer</code>. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private HardwareBuffer(long nativeObject) { mNativeObject = nativeObject; diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 6ca5f0ca0c18..bfb7c58c2dc9 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -25,6 +25,7 @@ import android.app.IInputForwarder; import android.content.Context; import android.media.AudioAttributes; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -65,7 +66,7 @@ public final class InputManager { private static InputManager sInstance; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final IInputManager mIm; // Guarded by mInputDevicesLock diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index ae0855a684ed..41119416e419 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -32,6 +32,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.hardware.usb.gadget.V1_0.GadgetFunction; +import android.os.Build; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; @@ -385,7 +386,7 @@ public class UsbManager { /** * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public UsbManager(Context context, IUsbManager service) { mContext = context; mService = service; diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java index ec5f05067120..51d33b2f1d4a 100644 --- a/core/java/android/inputmethodservice/Keyboard.java +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -25,6 +25,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; +import android.os.Build; import android.text.TextUtils; import android.util.Log; import android.util.TypedValue; @@ -627,7 +628,7 @@ public class Keyboard { rows.add(row); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final void resize(int newWidth, int newHeight) { int numRows = rows.size(); for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) { diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index fd1e5f23382b..12b6f9e1b370 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -21,6 +21,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; @@ -904,7 +905,7 @@ public final class NetworkCapabilities implements Parcelable { * specifier. See {@link #setNetworkSpecifier}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public NetworkSpecifier getNetworkSpecifier() { return mNetworkSpecifier; } diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index c545ee205df8..97fb3fb772a5 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.Slog; @@ -34,7 +35,7 @@ public class NetworkState implements Parcelable { public final NetworkInfo networkInfo; public final LinkProperties linkProperties; public final NetworkCapabilities networkCapabilities; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final Network network; public final String subscriberId; public final String networkId; diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 31494d99738b..abc1cac02c7e 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.SystemProperties; import android.util.Log; @@ -87,7 +88,7 @@ import javax.net.ssl.X509TrustManager; * requires root access. */ public class SSLCertificateSocketFactory extends SSLSocketFactory { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private static final String TAG = "SSLCertificateSocketFactory"; @UnsupportedAppUsage @@ -384,7 +385,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * @throws IllegalArgumentException if the socket was not created by this factory. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public byte[] getAlpnSelectedProtocol(Socket socket) { return castToOpenSSLSocket(socket).getAlpnSelectedProtocol(); } @@ -410,7 +411,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void setChannelIdPrivateKey(PrivateKey privateKey) { mChannelIdPrivateKey = privateKey; } diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java index 71199c9c6257..030066eb80a4 100644 --- a/core/java/android/nfc/NfcManager.java +++ b/core/java/android/nfc/NfcManager.java @@ -19,6 +19,7 @@ package android.nfc; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; import android.content.Context; +import android.os.Build; /** * High level manager used to obtain an instance of an {@link NfcAdapter}. @@ -45,7 +46,7 @@ public final class NfcManager { /** * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public NfcManager(Context context) { NfcAdapter adapter; context = context.getApplicationContext(); diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index f303674ce055..71eda19e165b 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -20,6 +20,7 @@ import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; +import android.os.Build; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -65,7 +66,7 @@ public class SystemHealthManager { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static SystemHealthManager from(Context context) { return (SystemHealthManager)context.getSystemService(Context.SYSTEM_HEALTH_SERVICE); } diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index deff693a5cae..5bef7ee0e619 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -22,6 +22,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Environment; import android.os.Parcel; import android.os.Parcelable; @@ -249,7 +250,7 @@ public final class StorageVolume implements Parcelable { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public UserHandle getOwner() { return mOwner; } diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 98b69a828c28..238765702a1d 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -1167,7 +1168,7 @@ public class Preference implements Comparable<Preference> { * @return True if the Preference handled the key. Returns false by default. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean onKey(View v, int keyCode, KeyEvent event) { return false; } diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java index c76c8d3632f6..dfee1af1c463 100644 --- a/core/java/android/preference/PreferenceManager.java +++ b/core/java/android/preference/PreferenceManager.java @@ -30,6 +30,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.XmlResourceParser; +import android.os.Build; import android.os.Bundle; import android.util.Log; @@ -68,7 +69,7 @@ public class PreferenceManager { * Fragment that owns this instance. */ @Nullable - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private PreferenceFragment mFragment; /** @@ -201,7 +202,7 @@ public class PreferenceManager { /** * Sets the owning preference fragment */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) void setFragment(PreferenceFragment fragment) { mFragment = fragment; } diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 189b7b491dc5..82459b13a4eb 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -717,7 +717,11 @@ public final class MediaStore { /** * The picasa id of the image * <P>Type: TEXT</P> + * + * @deprecated this value was only relevant for images hosted on + * Picasa, which are no longer supported. */ + @Deprecated public static final String PICASA_ID = "picasa_id"; /** @@ -755,7 +759,12 @@ public final class MediaStore { /** * The mini thumb id. * <P>Type: INTEGER</P> + * + * @deprecated all thumbnails should be obtained via + * {@link Images.Thumbnails#getThumbnail}, as this + * value is no longer supported. */ + @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; /** @@ -1947,7 +1956,12 @@ public final class MediaStore { /** * The mini thumb id. * <P>Type: INTEGER</P> + * + * @deprecated all thumbnails should be obtained via + * {@link Images.Thumbnails#getThumbnail}, as this + * value is no longer supported. */ + @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 026195e64a97..4c7f0f3d823d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -363,6 +363,21 @@ public final class Settings { "android.settings.MANAGE_UNKNOWN_APP_SOURCES"; /** + * Activity Action: Show the "Open by Default" page in a particular application's details page. + * <p> + * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + * <p> + * Input: The Intent's data URI specifies the application package name + * to be shown, with the "package" scheme. That is "package:com.my.app". + * <p> + * Output: Nothing. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_APP_OPEN_BY_DEFAULT_SETTINGS = + "com.android.settings.APP_OPEN_BY_DEFAULT_SETTINGS"; + + /** * Activity Action: Show trusted credentials settings, opening to the user tab, * to allow management of installed credentials. * <p> @@ -809,21 +824,6 @@ public final class Settings { "android.settings.APPLICATION_DETAILS_SETTINGS"; /** - * Activity Action: Show the "Open by Default" page in a particular application's details page. - * <p> - * In some cases, a matching Activity may not exist, so ensure you safeguard against this. - * <p> - * Input: The Intent's data URI specifies the application package name - * to be shown, with the "package" scheme. That is "package:com.my.app". - * <p> - * Output: Nothing. - * @hide - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_APPLICATION_DETAILS_SETTINGS_OPEN_BY_DEFAULT_PAGE = - "android.settings.APPLICATION_DETAILS_SETTINGS_OPEN_BY_DEFAULT_PAGE"; - - /** * Activity Action: Show list of applications that have been running * foreground services (to the user "running in the background"). * <p> diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java index b1ae7a5b5d33..fdbb1c2dcab6 100644 --- a/core/java/android/service/autofill/CustomDescription.java +++ b/core/java/android/service/autofill/CustomDescription.java @@ -314,7 +314,8 @@ public final class CustomDescription implements Parcelable { * is called multiple times passing the same {@code id}, only the last call will be used. * * @param id resource id of the child view. - * @param action action to be performed. + * @param action action to be performed. Must be an an implementation provided by the + * Android System. * * @return this builder * diff --git a/core/java/android/service/autofill/OnClickAction.java b/core/java/android/service/autofill/OnClickAction.java index 7439b003c070..8597a886e8bc 100644 --- a/core/java/android/service/autofill/OnClickAction.java +++ b/core/java/android/service/autofill/OnClickAction.java @@ -21,6 +21,9 @@ package android.service.autofill; * * <p>Typically used to switch the visibility of other views in a * {@link CustomDescription custom save UI}. + * + * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only + * implementations provided by the Android System can be used in other Autofill APIs. */ public interface OnClickAction { } diff --git a/core/java/android/service/autofill/Sanitizer.java b/core/java/android/service/autofill/Sanitizer.java index 38757ac7408b..8a1310de6e32 100644 --- a/core/java/android/service/autofill/Sanitizer.java +++ b/core/java/android/service/autofill/Sanitizer.java @@ -21,6 +21,9 @@ package android.service.autofill; * <p>Typically used to avoid displaying the save UI for values that are autofilled but reformatted * by the app—for example, if the autofill service sends a credit card number * value as "004815162342108" and the app automatically changes it to "0048 1516 2342 108". + * + * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only + * implementations provided by the Android System can be used in other Autofill APIs. */ public interface Sanitizer { } diff --git a/core/java/android/service/autofill/Transformation.java b/core/java/android/service/autofill/Transformation.java index aa8bc9b9500f..de43955e2dc1 100644 --- a/core/java/android/service/autofill/Transformation.java +++ b/core/java/android/service/autofill/Transformation.java @@ -20,6 +20,9 @@ package android.service.autofill; * template} at runtime, using the values of fields contained in the screen. * * <p>Typically used by {@link CustomDescription} to provide a customized autofill save UI. + * + * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only + * implementations provided by the Android System can be used in other Autofill APIs. */ public interface Transformation { } diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 15b2aaebd1c0..38de79456bee 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -27,6 +27,7 @@ import android.app.Service; import android.content.Intent; import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; @@ -626,7 +627,7 @@ public class DreamService extends Service implements Window.Callback { * @see #startDozing * @hide For use by system UI components only. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean canDoze() { return mCanDoze; } @@ -694,7 +695,7 @@ public class DreamService extends Service implements Window.Callback { * @see #startDozing * @hide For use by system UI components only. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void stopDozing() { if (mDozing) { mDozing = false; @@ -716,7 +717,7 @@ public class DreamService extends Service implements Window.Callback { * @see #setDozing(boolean) * @hide For use by system UI components only. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean isDozing() { return mDozing; } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 3319c9ecb605..d7fe15d0e925 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -280,7 +280,7 @@ public abstract class NotificationListenerService extends Service { private final Object mLock = new Object(); - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Handler mHandler; /** @hide */ diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index f2fa45d59c1e..e819c963ae45 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -1551,7 +1551,9 @@ public class ZenModeConfig implements Parcelable { if (component != null) { component.writeToProto(proto, ZenRuleProto.COMPONENT); } - // TODO: write zenPolicy to proto (b/115370281) + if (zenPolicy != null) { + zenPolicy.writeToProto(proto, ZenRuleProto.ZEN_POLICY); + } proto.end(token); } diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java index 88825f08967e..1ccf529d3009 100644 --- a/core/java/android/service/notification/ZenPolicy.java +++ b/core/java/android/service/notification/ZenPolicy.java @@ -21,6 +21,7 @@ import android.app.Notification; import android.app.NotificationChannel; import android.os.Parcel; import android.os.Parcelable; +import android.util.proto.ProtoOutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -852,6 +853,34 @@ public final class ZenPolicy implements Parcelable { } /** + * @hide + */ + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + + proto.write(ZenPolicyProto.REMINDERS, getPriorityCategoryReminders()); + proto.write(ZenPolicyProto.EVENTS, getPriorityCategoryEvents()); + proto.write(ZenPolicyProto.MESSAGES, getPriorityCategoryMessages()); + proto.write(ZenPolicyProto.CALLS, getPriorityCategoryCalls()); + proto.write(ZenPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers()); + proto.write(ZenPolicyProto.ALARMS, getPriorityCategoryAlarms()); + proto.write(ZenPolicyProto.MEDIA, getPriorityCategoryMedia()); + proto.write(ZenPolicyProto.SYSTEM, getPriorityCategorySystem()); + + proto.write(ZenPolicyProto.FULL_SCREEN_INTENT, getVisualEffectFullScreenIntent()); + proto.write(ZenPolicyProto.LIGHTS, getVisualEffectLights()); + proto.write(ZenPolicyProto.PEEK, getVisualEffectPeek()); + proto.write(ZenPolicyProto.STATUS_BAR, getVisualEffectStatusBar()); + proto.write(ZenPolicyProto.BADGE, getVisualEffectBadge()); + proto.write(ZenPolicyProto.AMBIENT, getVisualEffectAmbient()); + proto.write(ZenPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList()); + + proto.write(ZenPolicyProto.PRIORITY_MESSAGES, getPriorityMessageSenders()); + proto.write(ZenPolicyProto.PRIORITY_CALLS, getPriorityCallSenders()); + proto.end(token); + } + + /** * Makes deep copy of this ZenPolicy. * @hide */ diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index c46c831b2f9d..c928da103557 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.graphics.Paint; import android.graphics.Rect; +import android.os.Build; import android.text.style.ReplacementSpan; import android.text.style.UpdateLayout; import android.text.style.WrapTogetherSpan; @@ -354,7 +355,7 @@ public class DynamicLayout extends Layout { * @deprecated Use {@link Builder} instead. */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public DynamicLayout(@NonNull CharSequence base, @NonNull CharSequence display, @NonNull TextPaint paint, @IntRange(from = 0) int width, diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 5adb1cad4ef2..e1ffef01feae 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.graphics.Paint; +import android.os.Build; import android.text.style.LeadingMarginSpan; import android.text.style.LeadingMarginSpan.LeadingMarginSpan2; import android.text.style.LineHeightSpan; @@ -1293,7 +1294,7 @@ public class StaticLayout extends Layout { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int getHeight(boolean cap) { if (cap && mLineCount > mMaximumVisibleLineCount && mMaxLineHeight == -1 && Log.isLoggable(TAG, Log.WARN)) { diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index bf2d600456bc..ad7a851926a1 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -22,6 +22,7 @@ import android.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; +import android.os.Build; import android.text.Layout.Directions; import android.text.Layout.TabStops; import android.text.style.CharacterStyle; @@ -61,7 +62,7 @@ public class TextLine { private TabStops mTabs; private char[] mChars; private boolean mCharsValid; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Spanned mSpanned; private PrecomputedText mComputed; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 0476cf8961a5..ff6e86ebff61 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -45,6 +45,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_dynamic_homepage", "false"); DEFAULT_FLAGS.put("settings_mobile_network_v2", "false"); DEFAULT_FLAGS.put("settings_data_usage_v2", "false"); + DEFAULT_FLAGS.put("settings_seamless_transfer", "false"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true"); } diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index ce16ffc82090..a8727760095b 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -22,6 +22,7 @@ import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.hardware.display.DisplayManagerGlobal; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -153,7 +154,7 @@ public final class Choreographer { public String toString() { return "FRAME_CALLBACK_TOKEN"; } }; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final Object mLock = new Object(); private final Looper mLooper; diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 8641d7f3302d..c38fcf36a65c 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -21,6 +21,7 @@ import static android.view.Display.INVALID_DISPLAY; import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.method.MetaKeyKeyListener; @@ -1256,7 +1257,7 @@ public class KeyEvent extends InputEvent implements Parcelable { @UnsupportedAppUsage private int mDeviceId; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mSource; private int mDisplayId; @UnsupportedAppUsage @@ -1658,7 +1659,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * @hide */ @Override - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final void recycle() { super.recycle(); mCharacters = null; diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index dc097a155d4d..cf11fd04efdf 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -31,6 +31,7 @@ import android.graphics.RectF; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -146,7 +147,7 @@ public final class PointerIcon implements Parcelable { private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>(); private static boolean sUseLargeIcons = false; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int mType; private int mSystemIconResourceId; @UnsupportedAppUsage @@ -319,7 +320,7 @@ public final class PointerIcon implements Parcelable { * @throws IllegalArgumentException if context is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public PointerIcon load(@NonNull Context context) { if (context == null) { throw new IllegalArgumentException("context must not be null"); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 9bc53ed5a851..c29fbbb2125f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4582,7 +4582,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Object that handles automatic animation of view properties. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private ViewPropertyAnimator mAnimator = null; /** @@ -6876,7 +6876,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param requestCode The request code to use. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void startActivityForResult(Intent intent, int requestCode) { mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); @@ -18406,7 +18406,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * communicate with the window manager. * @return the session object to communicate with the window manager */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) /*package*/ IWindowSession getWindowSession() { return mAttachInfo != null ? mAttachInfo.mSession : null; } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index f436962147eb..a7ec6df00017 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -422,7 +422,7 @@ public abstract class Window { * @return boolean You must return true for the panel to be displayed; * if you return false it will not be shown. */ - public boolean onCreatePanelMenu(int featureId, Menu menu); + boolean onCreatePanelMenu(int featureId, @NonNull Menu menu); /** * Prepare a panel to be displayed. This is called right before the @@ -438,7 +438,7 @@ public abstract class Window { * * @see #onCreatePanelView */ - public boolean onPreparePanel(int featureId, View view, Menu menu); + boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu); /** * Called when a panel's menu is opened by the user. This may also be @@ -450,7 +450,7 @@ public abstract class Window { * @return Return true to allow the menu to open, or false to prevent * the menu from opening. */ - public boolean onMenuOpened(int featureId, Menu menu); + boolean onMenuOpened(int featureId, @NonNull Menu menu); /** * Called when a panel's menu item has been selected by the user. @@ -462,7 +462,7 @@ public abstract class Window { * false to perform the normal menu handling (calling its * Runnable or sending a Message to its target Handler). */ - public boolean onMenuItemSelected(int featureId, MenuItem item); + boolean onMenuItemSelected(int featureId, @NonNull MenuItem item); /** * This is called whenever the current window attributes change. @@ -512,7 +512,7 @@ public abstract class Window { * @param menu If onCreatePanelView() returned null, this is the Menu * being displayed in the panel. */ - public void onPanelClosed(int featureId, Menu menu); + void onPanelClosed(int featureId, @NonNull Menu menu); /** * Called when the user signals the desire to start a search. diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index d810067c38de..4ca9a141fd23 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -23,6 +23,7 @@ import android.content.ComponentCallbacks2; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; +import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -213,7 +214,7 @@ public final class WindowManagerGlobal { } } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static IWindowSession peekWindowSession() { synchronized (WindowManagerGlobal.class) { return sWindowSession; diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 3eca8541d1fe..dccf9d40a605 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -18,6 +18,7 @@ package android.view.accessibility; import android.annotation.IntDef; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -761,7 +762,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par private CharSequence mPackageName; private long mEventTime; int mMovementGranularity; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) int mAction; int mContentChangeTypes; int mWindowChangeTypes; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index c51c5e2173e2..508509a83f03 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -336,7 +336,7 @@ public final class InputMethodManager { /** * The InputConnection that was last retrieved from the served view. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) ControlledInputConnectionWrapper mServedInputConnectionWrapper; /** * The completions that were last provided by the served view. diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java index a7d7a8d67f64..14c879e78551 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtype.java +++ b/core/java/android/view/inputmethod/InputMethodSubtype.java @@ -28,7 +28,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; -import com.android.internal.inputmethod.InputMethodUtils; +import com.android.internal.inputmethod.SubtypeLocaleUtils; import java.util.ArrayList; import java.util.Arrays; @@ -384,7 +384,7 @@ public final class InputMethodSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag); } else { - mCachedLocaleObj = InputMethodUtils.constructLocaleFromString(mSubtypeLocale); + mCachedLocaleObj = SubtypeLocaleUtils.constructLocaleFromString(mSubtypeLocale); } return mCachedLocaleObj; } diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java index 026610ecb6f9..d904d4672db9 100644 --- a/core/java/android/view/textservice/SpellCheckerSubtype.java +++ b/core/java/android/view/textservice/SpellCheckerSubtype.java @@ -25,7 +25,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; -import com.android.internal.inputmethod.InputMethodUtils; +import com.android.internal.inputmethod.SubtypeLocaleUtils; import java.util.ArrayList; import java.util.Arrays; @@ -228,7 +228,7 @@ public final class SpellCheckerSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { return Locale.forLanguageTag(mSubtypeLanguageTag); } - return InputMethodUtils.constructLocaleFromString(mSubtypeLocale); + return SubtypeLocaleUtils.constructLocaleFromString(mSubtypeLocale); } /** diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java index 1d3a617a6bec..7839a00eff69 100644 --- a/core/java/android/webkit/SafeBrowsingResponse.java +++ b/core/java/android/webkit/SafeBrowsingResponse.java @@ -36,14 +36,14 @@ public abstract class SafeBrowsingResponse { public abstract void showInterstitial(boolean allowReporting); /** - * Act as if the user clicked "visit this unsafe site." + * Act as if the user clicked the "visit this unsafe site" button. * * @param report {@code true} to enable Safe Browsing reporting. */ public abstract void proceed(boolean report); /** - * Act as if the user clicked "back to safety." + * Act as if the user clicked the "back to safety" button. * * @param report {@code true} to enable Safe Browsing reporting. */ diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 71d13a9acdca..cbd624eec7d6 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -24,6 +24,7 @@ import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Build; import android.text.Editable; import android.text.Selection; import android.text.TextUtils; @@ -533,7 +534,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * * @hide Pending API council approval */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void setDropDownAnimationStyle(int animationStyle) { mPopup.setAnimationStyle(animationStyle); } diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 5b5950dce1f4..10e1dfb30a5a 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -36,6 +36,7 @@ import android.database.Cursor; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -1292,7 +1293,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { mSearchSrcTextView.dismissDropDown(); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private void onCloseClicked() { CharSequence text = mSearchSrcTextView.getText(); if (TextUtils.isEmpty(text)) { @@ -1590,7 +1591,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { /** * Sets the text in the query box, without updating the suggestions. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private void setQuery(CharSequence query) { mSearchSrcTextView.setText(query, true); // Move the cursor to the end diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 3fbc819123c3..10cf70215747 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.PixelFormat; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -443,7 +444,7 @@ public class Toast { * schedule handleShow into the right thread */ @Override - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void show(IBinder windowToken) { if (localLOGV) Log.v(TAG, "SHOW: " + this); mHandler.obtainMessage(SHOW, windowToken).sendToTarget(); diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 1bbd7e89ef21..adb7f2f89320 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -29,6 +29,7 @@ import android.app.ActionBar; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.Layout; @@ -137,7 +138,7 @@ public class Toolbar extends ViewGroup { @UnsupportedAppUsage private TextView mTitleTextView; private TextView mSubtitleTextView; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private ImageButton mNavButtonView; private ImageView mLogoView; diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index 14881eb60721..8b45d997627a 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -38,6 +38,7 @@ import android.media.SubtitleTrack.RenderingWidget; import android.media.TtmlRenderer; import android.media.WebVttRenderer; import android.net.Uri; +import android.os.Build; import android.os.Looper; import android.util.AttributeSet; import android.util.Log; @@ -85,7 +86,7 @@ public class VideoView extends SurfaceView // all possible internal states private static final int STATE_ERROR = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private static final int STATE_IDLE = 0; private static final int STATE_PREPARING = 1; private static final int STATE_PREPARED = 2; diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index 90712fdbde4f..e83e79b2029e 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -16,6 +16,10 @@ package com.android.internal.accessibility; +import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; + +import static com.android.internal.util.ArrayUtils.convertToLongArray; + import android.accessibilityservice.AccessibilityServiceInfo; import android.app.ActivityManager; import android.app.ActivityThread; @@ -34,23 +38,23 @@ import android.os.Handler; import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; +import android.speech.tts.TextToSpeech; +import android.speech.tts.Voice; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; - import android.widget.Toast; + import com.android.internal.R; +import com.android.internal.util.function.pooled.PooledLambda; import java.util.Collections; +import java.util.Locale; import java.util.Map; -import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; - -import static com.android.internal.util.ArrayUtils.convertToLongArray; - /** * Class to help manage the accessibility shortcut */ @@ -70,6 +74,7 @@ public class AccessibilityShortcutController { private static Map<ComponentName, ToggleableFrameworkFeatureInfo> sFrameworkShortcutFeaturesMap; private final Context mContext; + private final Handler mHandler; private AlertDialog mAlertDialog; private boolean mIsShortcutEnabled; private boolean mEnabledOnLockScreen; @@ -123,6 +128,7 @@ public class AccessibilityShortcutController { public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) { mContext = context; + mHandler = handler; mUserId = initialUserId; // Keep track of state of shortcut settings @@ -189,22 +195,6 @@ public class AccessibilityShortcutController { final int userId = ActivityManager.getCurrentUser(); final int dialogAlreadyShown = Settings.Secure.getIntForUser( cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId); - // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they - // have less ways of providing feedback like vibration. - final int audioAttributesUsage = hasFeatureLeanback() - ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY - : AudioAttributes.USAGE_NOTIFICATION_EVENT; - - // Play a notification tone - final Ringtone tone = - RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI); - if (tone != null) { - tone.setAudioAttributes(new AudioAttributes.Builder() - .setUsage(audioAttributesUsage) - .build()); - tone.play(); - } - // Play a notification vibration Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); if ((vibrator != null) && vibrator.hasVibrator()) { @@ -223,6 +213,9 @@ public class AccessibilityShortcutController { if (mAlertDialog == null) { return; } + if (!performTtsPrompt(mAlertDialog)) { + playNotificationTone(); + } Window w = mAlertDialog.getWindow(); WindowManager.LayoutParams attr = w.getAttributes(); attr.type = TYPE_KEYGUARD_DIALOG; @@ -231,6 +224,7 @@ public class AccessibilityShortcutController { Settings.Secure.putIntForUser( cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1, userId); } else { + playNotificationTone(); if (mAlertDialog != null) { mAlertDialog.dismiss(); mAlertDialog = null; @@ -344,6 +338,102 @@ public class AccessibilityShortcutController { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); } + private void playNotificationTone() { + // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they + // have less ways of providing feedback like vibration. + final int audioAttributesUsage = hasFeatureLeanback() + ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY + : AudioAttributes.USAGE_NOTIFICATION_EVENT; + + // Play a notification tone + final Ringtone tone = mFrameworkObjectProvider.getRingtone(mContext, + Settings.System.DEFAULT_NOTIFICATION_URI); + if (tone != null) { + tone.setAudioAttributes(new AudioAttributes.Builder() + .setUsage(audioAttributesUsage) + .build()); + tone.play(); + } + } + + private boolean performTtsPrompt(AlertDialog alertDialog) { + final AccessibilityServiceInfo serviceInfo = getInfoForTargetService(); + if (serviceInfo == null) { + return false; + } + if ((serviceInfo.flags & AccessibilityServiceInfo + .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK) == 0) { + return false; + } + final TtsPrompt tts = new TtsPrompt(); + alertDialog.setOnDismissListener(dialog -> tts.dismiss()); + return true; + } + + /** + * Class to wrap TextToSpeech for shortcut dialog spoken feedback. + */ + private class TtsPrompt implements TextToSpeech.OnInitListener { + private final CharSequence mText; + private boolean mDismiss; + private TextToSpeech mTts; + + TtsPrompt() { + mText = mContext.getString(R.string.accessibility_shortcut_spoken_feedback); + mTts = mFrameworkObjectProvider.getTextToSpeech(mContext, this); + } + + /** + * Releases the resources used by the TextToSpeech, when dialog dismiss. + */ + public void dismiss() { + mDismiss = true; + mHandler.sendMessage(PooledLambda.obtainMessage(TextToSpeech::shutdown, mTts)); + } + + @Override + public void onInit(int status) { + if (status != TextToSpeech.SUCCESS) { + Slog.d(TAG, "Tts init fail, status=" + Integer.toString(status)); + playNotificationTone(); + return; + } + mHandler.sendMessage(PooledLambda.obtainMessage(TtsPrompt::play, this)); + } + + private void play() { + if (mDismiss) { + return; + } + int status = TextToSpeech.ERROR; + if (setLanguage(Locale.getDefault())) { + status = mTts.speak(mText, TextToSpeech.QUEUE_FLUSH, null, null); + } + if (status != TextToSpeech.SUCCESS) { + Slog.d(TAG, "Tts play fail"); + playNotificationTone(); + } + } + + /** + * @return false if tts language is not available + */ + private boolean setLanguage(final Locale locale) { + int status = mTts.isLanguageAvailable(locale); + if (status == TextToSpeech.LANG_MISSING_DATA + || status == TextToSpeech.LANG_NOT_SUPPORTED) { + return false; + } + mTts.setLanguage(locale); + Voice voice = mTts.getVoice(); + if (voice == null || (voice.getFeatures() != null && voice.getFeatures() + .contains(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED))) { + return false; + } + return true; + } + } + /** * Immutable class to hold info about framework features that can be controlled by shortcut */ @@ -406,5 +496,23 @@ public class AccessibilityShortcutController { public Context getSystemUiContext() { return ActivityThread.currentActivityThread().getSystemUiContext(); } + + /** + * @param ctx A context for TextToSpeech + * @param listener TextToSpeech initialization callback + * @return TextToSpeech instance + */ + public TextToSpeech getTextToSpeech(Context ctx, TextToSpeech.OnInitListener listener) { + return new TextToSpeech(ctx, listener); + } + + /** + * @param ctx context for ringtone + * @param uri ringtone uri + * @return Ringtone instance + */ + public Ringtone getRingtone(Context ctx, Uri uri) { + return RingtoneManager.getRingtone(ctx, uri); + } } } diff --git a/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java b/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java new file mode 100644 index 000000000000..9ea4fa2d0ee4 --- /dev/null +++ b/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.inputmethod; + +import android.annotation.Nullable; +import android.text.TextUtils; + +import java.util.Locale; + +/** + * A utility class to handle {@link Locale} related logic for + * {@link android.view.inputmethod.InputMethodSubtype} and + * {@link android.view.textservice.SpellCheckerSubtype}. + */ +public class SubtypeLocaleUtils { + /** + * Maintains deprecated logic about how subtype locales specified in XML resources have been + * parsed. + * + * <p>This logic is kept basically for compatibility purpose. Consider relying on languageTag + * attribute instead.</p> + * + * @param localeStr string representation that is specified in the locale attribute + * @return {@link Locale} object parsed from {@code localeStr}. {@code null} for unexpected + * format + * + * @attr ref android.R.styleable#InputMethod_Subtype_imeSubtypeLocale + * @attr ref android.R.styleable#InputMethod_Subtype_languageTag + * @attr ref android.R.styleable#SpellChecker_Subtype_languageTag + * @attr ref android.R.styleable#SpellChecker_Subtype_subtypeLocale + */ + @Nullable + public static Locale constructLocaleFromString(String localeStr) { + if (TextUtils.isEmpty(localeStr)) { + return null; + } + // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. + String[] localeParams = localeStr.split("_", 3); + if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { + // Convert a locale whose language is "tl" to one whose language is "fil". + // For example, "tl_PH" will get converted to "fil_PH". + // Versions of Android earlier than Lollipop did not support three letter language + // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). + // On Lollipop and above, the current three letter version must be used. + localeParams[0] = "fil"; + } + // The length of localeStr is guaranteed to always return a 1 <= value <= 3 + // because localeStr is not empty. + if (localeParams.length == 1) { + return new Locale(localeParams[0]); + } else if (localeParams.length == 2) { + return new Locale(localeParams[0], localeParams[1]); + } else if (localeParams.length == 3) { + return new Locale(localeParams[0], localeParams[1], localeParams[2]); + } + return null; + } +} diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java index 6f9c87ab8f5a..ececba13c760 100644 --- a/core/java/com/android/internal/view/IInputConnectionWrapper.java +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -19,6 +19,7 @@ package com.android.internal.view; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -68,7 +69,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { @GuardedBy("mLock") @Nullable - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private InputConnection mInputConnection; private Looper mMainLooper; diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index 0b37d5794741..4773e168fffa 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -840,7 +840,11 @@ public class PointerLocationView extends View implements InputDeviceListener, scale *= 10; } value = (float) (Math.rint(value * scale) / scale); - + + // Corner case: (int)-0.1 will become zero, so the negative sign gets lost + if ((int) value == 0 && value < 0) { + append("-"); + } append((int) value); if (precision != 0) { diff --git a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java index 65be161bc0f6..b2e8b5e7af05 100644 --- a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java +++ b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java @@ -37,6 +37,7 @@ import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; @@ -181,7 +182,7 @@ public class SSLSocketFactory implements LayeredSocketFactory { private final javax.net.ssl.SSLSocketFactory socketfactory; @UnsupportedAppUsage private final HostNameResolver nameResolver; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; public SSLSocketFactory( @@ -251,7 +252,7 @@ public class SSLSocketFactory implements LayeredSocketFactory { * This constructor is used exclusively to instantiate the factory for * {@link #getSocketFactory getSocketFactory}. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private SSLSocketFactory() { super(); this.sslcontext = null; diff --git a/core/jni/Android.bp b/core/jni/Android.bp index bb8ee14e1902..762b43079c31 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -230,7 +230,6 @@ cc_library_shared { static_libs: [ "libgif", "libseccomp_policy", - "libselinux", "libgrallocusage", "libscrypt_static", ], diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index ccbd02764d7e..8836c2e4241f 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -200,6 +200,7 @@ message ZenRuleProto { optional string condition_id = 8; optional ConditionProto condition = 9; optional android.content.ComponentNameProto component = 10; + optional ZenPolicyProto zenPolicy = 11; } // A dump from com.android.server.notification.ZenModeHelper. @@ -212,3 +213,47 @@ message ZenModeProto { repeated android.content.ComponentNameProto suppressors = 4; optional android.app.PolicyProto policy = 5; } + +// An android.service.notification.ZenPolicy object +message ZenPolicyProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + enum State { + STATE_UNSET = 0; + STATE_ALLOW = 1; + STATE_DISALLOW = 2; + } + + // Notifications and sounds allowed/disallowed when DND is active + optional State reminders = 1; + optional State events = 2; + optional State messages = 3; + optional State calls = 4; + optional State repeat_callers = 5; + optional State alarms = 6; + optional State media = 7; + optional State system = 8; + + // Visual effects allowed/disallowed for intercepted notifications when DND is active + optional State full_screen_intent = 9; + optional State lights = 10; + optional State peek = 11; + optional State status_bar = 12; + optional State badge= 13; + optional State ambient = 14; + optional State notification_list = 15; + + enum Sender { + SENDER_UNSET = 0; + // Any sender is prioritized. + SENDER_ANY = 1; + // Saved contacts are prioritized. + SENDER_CONTACTS = 2; + // Only starred contacts are prioritized. + SENDER_STARRED = 3; + // No calls/messages are prioritized. + SENDER_NONE = 4; + } + optional Sender priority_calls = 16; + optional Sender priority_messages = 17; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9ab55d62839b..814973d783c2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3756,6 +3756,10 @@ <permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" android:protectionLevel="signature" /> + <!-- Allows the system to control the BiometricDialog (SystemUI). Reserved for the system. @hide --> + <permission android:name="android.permission.MANAGE_BIOMETRIC_DIALOG" + android:protectionLevel="signature" /> + <!-- Allows an app to reset face authentication attempt counter. Reserved for the system. @hide --> <permission android:name="android.permission.RESET_FACE_LOCKOUT" android:protectionLevel="signature" /> @@ -4112,7 +4116,7 @@ <!-- Allows an application to directly open the "Open by default" page inside a package's Details screen. @hide <p>Not for use by third-party applications. --> - <permission android:name="android.permission.OPEN_APPLICATION_DETAILS_OPEN_BY_DEFAULT_PAGE" + <permission android:name="android.permission.OPEN_APP_OPEN_BY_DEFAULT_SETTINGS" android:protectionLevel="signature" /> <!-- Allows hidden API checks to be disabled when starting a process. diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 2de2b9eef5b8..65b88076abf0 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3606,6 +3606,8 @@ <flag name="flagRequestAccessibilityButton" value="0x00000100" /> <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FINGERPRINT_GESTURES}. --> <flag name="flagRequestFingerprintGestures" value="0x00000200" /> + <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. --> + <flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" /> </attr> <!-- Component name of an activity that allows the user to modify the settings for this service. This setting cannot be changed at runtime. --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 365e4a47ce23..1a5b7b6cb06a 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4334,6 +4334,9 @@ <string name="accessibility_shortcut_disabling_service">Accessibility Shortcut turned <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> off</string> + <!-- Text spoken when accessibility shortcut warning dialog is shown. [CHAR LIMIT=none] --> + <string name="accessibility_shortcut_spoken_feedback">Use Accessibility Shortcut again to start the current accessibility feature</string> + <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. --> <string name="accessibility_button_prompt_text">Choose a feature to use when you tap the Accessibility button:</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7b6e064c9cf9..7b8eceda9370 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3083,6 +3083,7 @@ <java-symbol type="string" name="color_inversion_feature_name" /> <java-symbol type="string" name="color_correction_feature_name" /> <java-symbol type="string" name="config_defaultAccessibilityService" /> + <java-symbol type="string" name="accessibility_shortcut_spoken_feedback" /> <!-- Accessibility Button --> <java-symbol type="layout" name="accessibility_button_chooser" /> diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java index 1c4039b85441..3ce258969822 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java @@ -44,7 +44,7 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.StandardCopyOption; -import java.util.HashSet; +import java.util.ArrayList; import java.util.Locale; @SmallTest @@ -112,7 +112,7 @@ public class TypefaceSystemFallbackTest { private static void buildSystemFallback(String xml, ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) { - final HashSet<Font> availableFonts = new HashSet<>(); + final ArrayList<Font> availableFonts = new ArrayList<>(); try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) { fos.write(xml.getBytes(Charset.forName("UTF-8"))); } catch (IOException e) { @@ -127,7 +127,7 @@ public class TypefaceSystemFallbackTest { public void testBuildSystemFallback() { final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - final HashSet<Font> availableFonts = new HashSet<>(); + final ArrayList<Font> availableFonts = new ArrayList<>(); final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML, SYSTEM_FONT_DIR, fallbackMap, availableFonts); diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java index 355be619ea91..898e78c651e6 100644 --- a/core/tests/coretests/src/android/text/FontFallbackSetup.java +++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java @@ -33,7 +33,7 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.StandardCopyOption; -import java.util.HashSet; +import java.util.ArrayList; public class FontFallbackSetup implements AutoCloseable { private final String[] mTestFontFiles; @@ -76,7 +76,7 @@ public class FontFallbackSetup implements AutoCloseable { } final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - final HashSet<Font> availableFonts = new HashSet<>(); + final ArrayList<Font> availableFonts = new ArrayList<>(); final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml, mTestFontsDir, fallbackMap, availableFonts); Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases); diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java index f3e10e033caf..a302657c7ede 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java @@ -16,6 +16,31 @@ package com.android.internal.accessibility; +import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN; +import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED; +import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN; +import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.junit.Assert.fail; +import static org.mockito.AdditionalMatchers.aryEq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + import android.accessibilityservice.AccessibilityServiceInfo; import android.app.AlertDialog; import android.content.ComponentName; @@ -25,11 +50,14 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; +import android.media.Ringtone; import android.os.Handler; +import android.os.Message; import android.os.Vibrator; import android.provider.Settings; +import android.speech.tts.TextToSpeech; +import android.speech.tts.Voice; import android.support.test.runner.AndroidJUnit4; - import android.test.mock.MockContentResolver; import android.text.TextUtils; import android.view.Window; @@ -37,9 +65,10 @@ import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManager; import android.widget.Toast; + import com.android.internal.R; -import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider; +import com.android.internal.util.test.FakeSettingsProvider; import org.junit.After; import org.junit.Before; @@ -48,31 +77,12 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; import java.lang.reflect.Field; import java.util.Collections; import java.util.Map; -import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN; -import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED; -import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN; -import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; - -import static org.junit.Assert.fail; -import static org.mockito.AdditionalMatchers.aryEq; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; @RunWith(AndroidJUnit4.class) public class AccessibilityShortcutControllerTest { @@ -102,6 +112,9 @@ public class AccessibilityShortcutControllerTest { private @Mock Vibrator mVibrator; private @Mock ApplicationInfo mApplicationInfo; private @Mock PackageManager mPackageManager; + private @Mock TextToSpeech mTextToSpeech; + private @Mock Voice mVoice; + private @Mock Ringtone mRingtone; private MockContentResolver mContentResolver; private WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(); @@ -137,6 +150,9 @@ public class AccessibilityShortcutControllerTest { when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt())) .thenReturn(mToast); when(mFrameworkObjectProvider.getSystemUiContext()).thenReturn(mContext); + when(mFrameworkObjectProvider.getTextToSpeech(eq(mContext), any())) + .thenReturn(mTextToSpeech); + when(mFrameworkObjectProvider.getRingtone(eq(mContext), any())).thenReturn(mRingtone); when(mResources.getString(anyInt())).thenReturn("Howdy %s"); when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT); @@ -172,6 +188,8 @@ public class AccessibilityShortcutControllerTest { throw new RuntimeException("Unable to set mWindowAttributes", e); } when(mAlertDialog.getWindow()).thenReturn(window); + + when(mTextToSpeech.getVoice()).thenReturn(mVoice); } @After @@ -308,8 +326,10 @@ public class AccessibilityShortcutControllerTest { mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0)); verify(mResources).getString(R.string.accessibility_shortcut_toogle_warning); verify(mAlertDialog).show(); - verify(mAccessibilityManagerService).getInstalledAccessibilityServiceList(anyInt()); + verify(mAccessibilityManagerService, atLeastOnce()).getInstalledAccessibilityServiceList( + anyInt()); verify(mAccessibilityManagerService, times(0)).performAccessibilityShortcut(); + verify(mFrameworkObjectProvider, times(0)).getTextToSpeech(any(), any()); } @Test @@ -434,6 +454,49 @@ public class AccessibilityShortcutControllerTest { verify(mAccessibilityManagerService).performAccessibilityShortcut(); } + @Test + public void testOnAccessibilityShortcut_showsWarningDialog_shouldTtsSpokenPrompt() { + configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); + configureValidShortcutService(); + configureTtsSpokenPromptEnabled(); + configureHandlerCallbackInvocation(); + AccessibilityShortcutController accessibilityShortcutController = getController(); + Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0); + accessibilityShortcutController.performAccessibilityShortcut(); + + verify(mAlertDialog).show(); + ArgumentCaptor<TextToSpeech.OnInitListener> onInitCap = ArgumentCaptor.forClass( + TextToSpeech.OnInitListener.class); + verify(mFrameworkObjectProvider).getTextToSpeech(any(), onInitCap.capture()); + onInitCap.getValue().onInit(TextToSpeech.SUCCESS); + verify(mTextToSpeech).speak(any(), eq(TextToSpeech.QUEUE_FLUSH), any(), any()); + ArgumentCaptor<DialogInterface.OnDismissListener> onDismissCap = ArgumentCaptor.forClass( + DialogInterface.OnDismissListener.class); + verify(mAlertDialog).setOnDismissListener(onDismissCap.capture()); + onDismissCap.getValue().onDismiss(mAlertDialog); + verify(mTextToSpeech).shutdown(); + verify(mRingtone, times(0)).play(); + } + + @Test + public void testOnAccessibilityShortcut_showsWarningDialog_ttsInitFail_noSpokenPrompt() { + configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); + configureValidShortcutService(); + configureTtsSpokenPromptEnabled(); + configureHandlerCallbackInvocation(); + AccessibilityShortcutController accessibilityShortcutController = getController(); + Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0); + accessibilityShortcutController.performAccessibilityShortcut(); + + verify(mAlertDialog).show(); + ArgumentCaptor<TextToSpeech.OnInitListener> onInitCap = ArgumentCaptor.forClass( + TextToSpeech.OnInitListener.class); + verify(mFrameworkObjectProvider).getTextToSpeech(any(), onInitCap.capture()); + onInitCap.getValue().onInit(TextToSpeech.ERROR); + verify(mTextToSpeech, times(0)).speak(any(), anyInt(), any(), any()); + verify(mRingtone).play(); + } + private void configureNoShortcutService() { Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ""); } @@ -481,6 +544,19 @@ public class AccessibilityShortcutControllerTest { mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, lockscreen ? 1 : 0); } + private void configureTtsSpokenPromptEnabled() { + mServiceInfo.flags |= AccessibilityServiceInfo + .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK; + } + + private void configureHandlerCallbackInvocation() { + doAnswer((InvocationOnMock invocation) -> { + Message m = (Message) invocation.getArguments()[0]; + m.getCallback().run(); + return true; + }).when(mHandler).sendMessageAtTime(any(), anyLong()); + } + private AccessibilityShortcutController getController() { AccessibilityShortcutController accessibilityShortcutController = new AccessibilityShortcutController(mContext, mHandler, 0); diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java new file mode 100644 index 000000000000..8179328c32c4 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.inputmethod; + +import static org.junit.Assert.assertEquals; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Locale; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class SubtypeLocaleUtilsTest { + private static final Locale LOCALE_EN = new Locale("en"); + private static final Locale LOCALE_EN_US = new Locale("en", "US"); + private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); + private static final Locale LOCALE_EN_IN = new Locale("en", "IN"); + private static final Locale LOCALE_FIL = new Locale("fil"); + private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH"); + private static final Locale LOCALE_JA = new Locale("ja"); + private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); + private static final Locale LOCALE_TH = new Locale("ht"); + private static final Locale LOCALE_TH_TH = new Locale("ht", "TH"); + private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH"); + + @Test + public void testConstructLocaleFromString() throws Exception { + assertEquals(new Locale("en"), SubtypeLocaleUtils.constructLocaleFromString("en")); + assertEquals(new Locale("en", "US"), SubtypeLocaleUtils.constructLocaleFromString("en_US")); + assertEquals(new Locale("en", "US", "POSIX"), + SubtypeLocaleUtils.constructLocaleFromString("en_US_POSIX")); + + // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not + // support three letter language codes, and used "tl" (Tagalog) as the language string for + // "fil" (Filipino). + assertEquals(new Locale("fil"), SubtypeLocaleUtils.constructLocaleFromString("tl")); + assertEquals(new Locale("fil", "PH"), + SubtypeLocaleUtils.constructLocaleFromString("tl_PH")); + assertEquals(new Locale("fil", "PH", "POSIX"), + SubtypeLocaleUtils.constructLocaleFromString("tl_PH_POSIX")); + + // So far rejecting an invalid/unexpected locale string is out of the scope of this method. + assertEquals(new Locale("a"), SubtypeLocaleUtils.constructLocaleFromString("a")); + assertEquals(new Locale("a b c"), SubtypeLocaleUtils.constructLocaleFromString("a b c")); + assertEquals(new Locale("en-US"), SubtypeLocaleUtils.constructLocaleFromString("en-US")); + } +} diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 616a8d64b5b6..114c2285c008 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -281,6 +281,7 @@ applications that come with the platform <permission name="android.permission.MANAGE_FINGERPRINT"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.READ_SEARCH_INDEXABLES"/> + <permission name="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA"/> </privapp-permissions> <privapp-permissions package="com.android.sharedstoragebackup"> diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java index 9b5027d71ad6..43282d39ed47 100644 --- a/graphics/java/android/graphics/BitmapRegionDecoder.java +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -17,6 +17,7 @@ package android.graphics; import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; +import android.os.Build; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -166,7 +167,7 @@ public final class BitmapRegionDecoder { This can be called from JNI code. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private BitmapRegionDecoder(long decoder) { mNativeBitmapRegionDecoder = decoder; mRecycled = false; diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index ef58c8f2bd16..36c1c2133c2c 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -126,7 +126,7 @@ public class Canvas extends BaseCanvas { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public Canvas(long nativeCanvas) { if (nativeCanvas == 0) { throw new IllegalStateException(); diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java index 8162544273f4..6f030ffac2df 100644 --- a/graphics/java/android/graphics/Movie.java +++ b/graphics/java/android/graphics/Movie.java @@ -18,6 +18,7 @@ package android.graphics; import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; +import android.os.Build; import java.io.FileInputStream; import java.io.InputStream; @@ -30,7 +31,7 @@ public class Movie { @UnsupportedAppUsage private long mNativeMovie; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Movie(long nativeMovie) { if (nativeMovie == 0) { throw new RuntimeException("native movie creation failed"); diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 5aa09cef0c4e..492c236c014e 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -30,6 +30,7 @@ import android.content.res.AssetManager; import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; import android.net.Uri; +import android.os.Build; import android.provider.FontRequest; import android.provider.FontsContract; import android.text.FontConfig; @@ -1076,7 +1077,7 @@ public class Typeface { } // don't allow clients to call this directly - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Typeface(long ni) { if (ni == 0) { throw new RuntimeException("native typeface cannot be made"); diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java index 00380c5d0d95..11a46c4ba9b9 100644 --- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java @@ -24,6 +24,7 @@ import android.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; +import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.util.LongSparseLongArray; @@ -67,7 +68,7 @@ public class AnimatedStateListDrawable extends StateListDrawable { private static final String ELEMENT_TRANSITION = "transition"; private static final String ELEMENT_ITEM = "item"; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private AnimatedStateListState mState; /** The currently running transition, if any. */ diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index a33777314116..7efe5220873e 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -34,6 +34,7 @@ import android.graphics.BitmapFactory; import android.graphics.PorterDuff; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.Parcel; @@ -101,7 +102,7 @@ public final class Icon implements Parcelable { private static final int VERSION_STREAM_SERIALIZER = 1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int mType; private ColorStateList mTintList; @@ -118,7 +119,7 @@ public final class Icon implements Parcelable { // TYPE_RESOURCE: package name // TYPE_URI: uri string - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private String mString1; // TYPE_RESOURCE: resId @@ -174,7 +175,7 @@ public final class Icon implements Parcelable { * valid compressed bitmap data is found. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int getDataOffset() { if (mType != TYPE_DATA) { throw new IllegalStateException("called getDataOffset() on " + this); @@ -189,7 +190,7 @@ public final class Icon implements Parcelable { * bitmap data. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public byte[] getDataBytes() { if (mType != TYPE_DATA) { throw new IllegalStateException("called getDataBytes() on " + this); @@ -203,7 +204,7 @@ public final class Icon implements Parcelable { * @return The {@link android.content.res.Resources} for this {@link #TYPE_RESOURCE} Icon. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public Resources getResources() { if (mType != TYPE_RESOURCE) { throw new IllegalStateException("called getResources() on " + this); diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index 8aa48456ebff..1458c66a2c54 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -119,7 +119,7 @@ public final class Font { private @Nullable ByteBuffer mBuffer; private @Nullable File mFile; - private @NonNull LocaleList mLocaleList = LocaleList.getEmptyLocaleList(); + private @NonNull String mLocaleList = ""; private @IntRange(from = -1, to = 1000) int mWeight = NOT_SPECIFIED; private @IntRange(from = -1, to = 1) int mItalic = NOT_SPECIFIED; private @IntRange(from = 0) int mTtcIndex = 0; @@ -150,7 +150,7 @@ public final class Font { * @hide */ public Builder(@NonNull ByteBuffer buffer, @NonNull File path, - @NonNull LocaleList localeList) { + @NonNull String localeList) { this(buffer); mFile = path; mLocaleList = localeList; @@ -457,7 +457,7 @@ public final class Font { private final boolean mItalic; private final @IntRange(from = 0) int mTtcIndex; private final @Nullable FontVariationAxis[] mAxes; - private final @NonNull LocaleList mLocaleList; + private final @NonNull String mLocaleList; /** * Use Builder instead @@ -465,7 +465,7 @@ public final class Font { private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file, @IntRange(from = 0, to = 1000) int weight, boolean italic, @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] axes, - @NonNull LocaleList localeList) { + @NonNull String localeList) { mBuffer = buffer; mFile = file; mWeight = weight; @@ -546,7 +546,7 @@ public final class Font { * @return a locale list */ public @NonNull LocaleList getLocaleList() { - return mLocaleList; + return LocaleList.forLanguageTags(mLocaleList); } /** @hide */ @@ -580,7 +580,7 @@ public final class Font { + ", italic=" + mItalic + ", ttcIndex=" + mTtcIndex + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes) - + ", localeList=" + mLocaleList.toLanguageTags() + + ", localeList=" + mLocaleList + ", buffer=" + mBuffer + "}"; } diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java index 242cbb81b83c..bcee559d8291 100644 --- a/graphics/java/android/graphics/fonts/FontVariationAxis.java +++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java @@ -19,6 +19,7 @@ package android.graphics.fonts; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.text.TextUtils; import java.util.ArrayList; @@ -29,7 +30,7 @@ import java.util.regex.Pattern; * Class that holds information about single font variation axis. */ public final class FontVariationAxis { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final int mTag; private final String mTagString; @UnsupportedAppUsage diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 1c957b8880b9..f4a2199a6688 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -19,7 +19,6 @@ package android.graphics.fonts; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.FontListParser; -import android.os.LocaleList; import android.text.FontConfig; import android.util.ArrayMap; import android.util.Log; @@ -54,7 +53,7 @@ public class SystemFonts { private static final Map<String, FontFamily[]> sSystemFallbackMap; private static final FontConfig.Alias[] sAliases; - private static final Set<Font> sAvailableFonts; + private static final List<Font> sAvailableFonts; /** * Returns all available font files in the system. @@ -63,7 +62,9 @@ public class SystemFonts { * @return an array of system fonts */ public static @NonNull Set<Font> getAvailableFonts() { - return sAvailableFonts; + HashSet<Font> set = new HashSet<>(); + set.addAll(sAvailableFonts); + return set; } /** @@ -114,7 +115,7 @@ public class SystemFonts { @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap, @NonNull Map<String, ByteBuffer> cache, @NonNull String fontDir, - @NonNull HashSet<Font> availableFonts) { + @NonNull ArrayList<Font> availableFonts) { final String languageTags = xmlFamily.getLanguages(); final int variant = xmlFamily.getVariant(); @@ -170,13 +171,12 @@ public class SystemFonts { @FontConfig.Family.Variant int variant, @NonNull Map<String, ByteBuffer> cache, @NonNull String fontDir, - @NonNull HashSet<Font> availableFonts) { + @NonNull ArrayList<Font> availableFonts) { if (fonts.size() == 0) { return null; } FontFamily.Builder b = null; - final LocaleList localeList = LocaleList.forLanguageTags(languageTags); for (int i = 0; i < fonts.size(); i++) { final FontConfig.Font fontConfig = fonts.get(i); final String fullPath = fontDir + fontConfig.getFontName(); @@ -194,7 +194,7 @@ public class SystemFonts { final Font font; try { - font = new Font.Builder(buffer, new File(fullPath), localeList) + font = new Font.Builder(buffer, new File(fullPath), languageTags) .setWeight(fontConfig.getWeight()) .setItalic(fontConfig.isItalic()) .setTtcIndex(fontConfig.getTtcIndex()) @@ -228,7 +228,7 @@ public class SystemFonts { public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath, @NonNull String fontDir, @NonNull ArrayMap<String, FontFamily[]> fallbackMap, - @NonNull HashSet<Font> availableFonts) { + @NonNull ArrayList<Font> availableFonts) { try { final FileInputStream fontsIn = new FileInputStream(xmlPath); final FontConfig fontConfig = FontListParser.parse(fontsIn); @@ -284,11 +284,11 @@ public class SystemFonts { static { final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>(); - final HashSet<Font> availableFonts = new HashSet<>(); + final ArrayList<Font> availableFonts = new ArrayList<>(); sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", systemFallbackMap, availableFonts); sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap); - sAvailableFonts = Collections.unmodifiableSet(availableFonts); + sAvailableFonts = Collections.unmodifiableList(availableFonts); } } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 04bbe248263f..b01136361101 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -247,7 +247,7 @@ cc_library { // Enables fine-grained GLES error checking // If enabled, every GLES call is wrapped & error checked // Has moderate overhead - "hwui_enable_opengl_validation", + //"hwui_enable_opengl_validation", ], } diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index a43f58cd1e56..b5b87d516ff7 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -66,12 +66,16 @@ void DeviceInfo::initialize(int maxTextureSize) { sDeviceInfo = new DeviceInfo(); sDeviceInfo->mDisplayInfo = DeviceInfo::queryDisplayInfo(); sDeviceInfo->mMaxTextureSize = maxTextureSize; + sDeviceInfo->queryCompositionPreference(&sDeviceInfo->mTargetDataSpace, + &sDeviceInfo->mTargetPixelFormat); }); } void DeviceInfo::load() { mDisplayInfo = queryDisplayInfo(); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + sDeviceInfo->queryCompositionPreference(&sDeviceInfo->mTargetDataSpace, + &sDeviceInfo->mTargetPixelFormat); } DisplayInfo DeviceInfo::queryDisplayInfo() { @@ -86,5 +90,17 @@ DisplayInfo DeviceInfo::queryDisplayInfo() { return displayInfo; } +void DeviceInfo::queryCompositionPreference(ui::Dataspace* dataSpace, + ui::PixelFormat* pixelFormat) { + if (Properties::isolatedProcess) { + *dataSpace = ui::Dataspace::V0_SRGB; + *pixelFormat = ui::PixelFormat::RGBA_8888; + } + + status_t status = + SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat); + LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h index 297b2664414b..416af179eb21 100644 --- a/libs/hwui/DeviceInfo.h +++ b/libs/hwui/DeviceInfo.h @@ -17,6 +17,7 @@ #define DEVICEINFO_H #include <ui/DisplayInfo.h> +#include <ui/GraphicTypes.h> #include "Extensions.h" #include "utils/Macros.h" @@ -39,6 +40,8 @@ public: static void initialize(int maxTextureSize); int maxTextureSize() const { return mMaxTextureSize; } + ui::Dataspace getTargetDataSpace() const { return mTargetDataSpace; } + ui::PixelFormat getTargetPixelFormat() const { return mTargetPixelFormat; } const DisplayInfo& displayInfo() const { return mDisplayInfo; } const Extensions& extensions() const { return mExtensions; } @@ -50,6 +53,9 @@ public: static DisplayInfo queryDisplayInfo(); private: + static void queryCompositionPreference(ui::Dataspace* dataSpace, + ui::PixelFormat* pixelFormat); + DeviceInfo() {} ~DeviceInfo() {} @@ -58,6 +64,9 @@ private: int mMaxTextureSize; DisplayInfo mDisplayInfo; Extensions mExtensions; + // TODO(lpy) Replace below with android_ prefix types. + ui::Dataspace mTargetDataSpace; + ui::PixelFormat mTargetPixelFormat; }; } /* namespace uirenderer */ diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h index b14b80cc598a..6857999500f0 100644 --- a/libs/hwui/LayerUpdateQueue.h +++ b/libs/hwui/LayerUpdateQueue.h @@ -19,6 +19,7 @@ #include <utils/StrongPointer.h> #include "Rect.h" +#include "RenderNode.h" #include "utils/Macros.h" #include <unordered_map> diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index d58b59e83380..3b1ebd690465 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -27,6 +27,8 @@ #include "utils/GLUtils.h" #include "utils/TraceUtils.h" +#include <GLES3/gl3.h> + #include <GrBackendSurface.h> #include <SkBlendMode.h> #include <SkImageInfo.h> @@ -62,21 +64,23 @@ Frame SkiaOpenGLPipeline::getFrame() { bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, - bool opaque, bool wideColorGamut, const LightInfo& lightInfo, + bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) { mEglManager.damageFrame(frame, dirty); - SkColorType colorType; + SkColorType colorType = getSurfaceColorType(); // setup surface for fbo0 GrGLFramebufferInfo fboInfo; fboInfo.fFBOID = 0; - if (wideColorGamut) { + if (colorType == kRGBA_F16_SkColorType) { fboInfo.fFormat = GL_RGBA16F; - colorType = kRGBA_F16_SkColorType; - } else { + } else if (colorType == kN32_SkColorType) { + // Note: The default preference of pixel format is RGBA_8888, when other + // pixel format is available, we should branch out and do more check. fboInfo.fFormat = GL_RGBA8; - colorType = kN32_SkColorType; + } else { + LOG_ALWAYS_FATAL("Unsupported color type."); } GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo); @@ -89,8 +93,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con nullptr, &props)); SkiaPipeline::updateLighting(lightGeometry, lightInfo); - renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds, - surface); + renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); layerUpdateQueue->clear(); // Draw visual debugging features @@ -147,8 +150,7 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, if (surface) { mRenderThread.requireGlContext(); - const bool wideColorGamut = colorMode == ColorMode::WideColorGamut; - mEglSurface = mEglManager.createSurface(surface, wideColorGamut); + mEglSurface = mEglManager.createSurface(surface, colorMode); } if (mEglSurface != EGL_NO_SURFACE) { @@ -168,6 +170,14 @@ bool SkiaOpenGLPipeline::isContextReady() { return CC_LIKELY(mEglManager.hasEglContext()); } +SkColorType SkiaOpenGLPipeline::getSurfaceColorType() const { + return mEglManager.getSurfaceColorType(); +} + +sk_sp<SkColorSpace> SkiaOpenGLPipeline::getSurfaceColorSpace() { + return mEglManager.getSurfaceColorSpace(); +} + void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; if (thread.eglManager().hasEglContext()) { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 808685ad4460..fbdf3139dabd 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -34,8 +34,7 @@ public: renderthread::Frame getFrame() override; bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty, const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, - const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const LightInfo& lightInfo, + const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode> >& renderNodes, FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, @@ -46,6 +45,8 @@ public: void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; + SkColorType getSurfaceColorType() const override; + sk_sp<SkColorSpace> getSurfaceColorSpace() override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 988981d65775..7f8abb8afa97 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -83,16 +83,15 @@ void SkiaPipeline::onPrepareTree() { void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, - bool wideColorGamut, const LightInfo& lightInfo) { + const LightInfo& lightInfo) { updateLighting(lightGeometry, lightInfo); ATRACE_NAME("draw layers"); renderVectorDrawableCache(); - renderLayersImpl(*layerUpdateQueue, opaque, wideColorGamut); + renderLayersImpl(*layerUpdateQueue, opaque); layerUpdateQueue->clear(); } -void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, - bool wideColorGamut) { +void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) { sk_sp<GrContext> cachedContext; // Render all layers that need to be updated, in order. @@ -161,7 +160,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, } bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, - bool wideColorGamut, ErrorHandler* errorHandler) { + ErrorHandler* errorHandler) { // compute the size of the surface (i.e. texture) to be allocated for this layer const int surfaceWidth = ceilf(node->getWidth() / float(LAYER_SIZE)) * LAYER_SIZE; const int surfaceHeight = ceilf(node->getHeight() / float(LAYER_SIZE)) * LAYER_SIZE; @@ -169,12 +168,8 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator SkSurface* layer = node->getLayerSurface(); if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) { SkImageInfo info; - if (wideColorGamut) { - info = SkImageInfo::Make(surfaceWidth, surfaceHeight, kRGBA_F16_SkColorType, - kPremul_SkAlphaType); - } else { - info = SkImageInfo::MakeN32Premul(surfaceWidth, surfaceHeight); - } + info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(), + kPremul_SkAlphaType); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), @@ -321,19 +316,18 @@ void SkiaPipeline::endCapture(SkSurface* surface) { void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip, const std::vector<sp<RenderNode>>& nodes, bool opaque, - bool wideColorGamut, const Rect& contentDrawBounds, - sk_sp<SkSurface> surface) { + const Rect& contentDrawBounds, sk_sp<SkSurface> surface) { renderVectorDrawableCache(); // draw all layers up front - renderLayersImpl(layers, opaque, wideColorGamut); + renderLayersImpl(layers, opaque); // initialize the canvas for the current frame, that might be a recording canvas if SKP // capture is enabled. std::unique_ptr<SkPictureRecorder> recorder; SkCanvas* canvas = tryCapture(surface.get()); - renderFrameImpl(layers, clip, nodes, opaque, wideColorGamut, contentDrawBounds, canvas); + renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas); endCapture(surface.get()); @@ -354,13 +348,12 @@ static Rect nodeBounds(RenderNode& node) { void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip, const std::vector<sp<RenderNode>>& nodes, bool opaque, - bool wideColorGamut, const Rect& contentDrawBounds, - SkCanvas* canvas) { + const Rect& contentDrawBounds, SkCanvas* canvas) { SkAutoCanvasRestore saver(canvas, true); canvas->androidFramework_setDeviceClipRestriction(clip.roundOut()); // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293 - if (!opaque || wideColorGamut) { + if (!opaque || getSurfaceColorType() == kRGBA_F16_SkColorType) { canvas->clear(SK_ColorTRANSPARENT); } @@ -493,7 +486,7 @@ void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& // each time a pixel would have been drawn. // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero // initialized. - renderFrameImpl(layers, clip, nodes, true, false, contentDrawBounds, &overdrawCanvas); + renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas); sk_sp<SkImage> counts = offscreen->makeImageSnapshot(); // Draw overdraw colors to the canvas. The color filter will convert counts to colors. diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 8c9c80381b84..b78dea1a5c87 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -42,15 +42,14 @@ public: void unpinImages() override; void onPrepareTree() override; - void renderLayers(const LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const LightInfo& lightInfo) override; + void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, + bool opaque, const LightInfo& lightInfo) override; bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, - bool wideColorGamut, ErrorHandler* errorHandler) override; + ErrorHandler* errorHandler) override; void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip, - const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut, + const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect& contentDrawBounds, sk_sp<SkSurface> surface); std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; } @@ -59,7 +58,7 @@ public: static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap); - void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, bool wideColorGamut); + void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque); static float getLightRadius() { if (CC_UNLIKELY(Properties::overrideLightRadius > 0)) { @@ -112,7 +111,7 @@ protected: private: void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip, - const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut, + const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect& contentDrawBounds, SkCanvas* canvas); /** diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 611a34c069d4..5cbe33debbce 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -63,8 +63,7 @@ Frame SkiaVulkanPipeline::getFrame() { bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, - bool opaque, bool wideColorGamut, - const LightInfo& lightInfo, + bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) { sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface(); @@ -72,8 +71,7 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, con return false; } SkiaPipeline::updateLighting(lightGeometry, lightInfo); - renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds, - backBuffer); + renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer); layerUpdateQueue->clear(); // Draw visual debugging features @@ -139,6 +137,14 @@ bool SkiaVulkanPipeline::isContextReady() { return CC_LIKELY(mVkManager.hasVkContext()); } +SkColorType SkiaVulkanPipeline::getSurfaceColorType() const { + return mVkManager.getSurfaceColorType(); +} + +sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() { + return mVkManager.getSurfaceColorSpace(); +} + void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { // TODO: we currently don't support OpenGL WebView's DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 900b054e35bd..6e723a8373e1 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -32,8 +32,7 @@ public: renderthread::Frame getFrame() override; bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty, const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, - const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const LightInfo& lightInfo, + const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode> >& renderNodes, FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, @@ -44,6 +43,8 @@ public: void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; + SkColorType getSurfaceColorType() const override; + sk_sp<SkColorSpace> getSurfaceColorSpace() override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 727cef3035f5..ea6a851419c0 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -151,7 +151,8 @@ void CanvasContext::setSurface(sp<Surface>&& surface) { mNativeSurface = std::move(surface); - ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb; + // TODO(b/111436479) Introduce a way for app to specify DisplayColorGamut mode. + ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Legacy; bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); mFrameNumber = -1; @@ -416,7 +417,7 @@ void CanvasContext::draw() { SkRect windowDirty = computeDirtyRect(frame, &dirty); bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, - mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, + mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler())); int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1; @@ -555,8 +556,7 @@ void CanvasContext::buildLayer(RenderNode* node) { // purposes when the frame is actually drawn node->setPropertyFieldsDirty(RenderNode::GENERIC); - mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mWideColorGamut, - mLightInfo); + mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo); node->incStrong(nullptr); mPrefetchedLayers.insert(node); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 02ee72f05f04..8448788eb9a6 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -75,8 +75,7 @@ public: */ bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator, ErrorHandler* errorHandler) { - return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, mWideColorGamut, - errorHandler); + return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, errorHandler); } /** diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 5f8d7ad3373a..675df4118876 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -20,6 +20,7 @@ #include <log/log.h> #include <private/gui/SyncFeatures.h> #include <utils/Trace.h> +#include "utils/Color.h" #include "utils/StringUtils.h" #include "DeviceInfo.h" @@ -27,6 +28,7 @@ #include "Properties.h" #include <EGL/eglext.h> +#include <GLES/gl.h> #include <string> #include <vector> @@ -75,6 +77,7 @@ static struct { bool pixelFormatFloat = false; bool glColorSpace = false; bool scRGB = false; + bool displayP3 = false; bool contextPriority = false; bool surfacelessContext = false; } EglExtensions; @@ -125,6 +128,17 @@ void EglManager::initialize() { createPBufferSurface(); makeCurrent(mPBufferSurface, nullptr, /* force */ true); DeviceInfo::initialize(); + + mSurfaceColorGamut = DataSpaceToColorGamut( + static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace())); + + LOG_ALWAYS_FATAL_IF(mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut && + !EglExtensions.displayP3, "EGL doesn't support Display P3."); + + mSurfaceColorType = PixelFormatToColorType( + static_cast<android_pixel_format>(DeviceInfo::get()->getTargetPixelFormat())); + mSurfaceColorSpace = DataSpaceToColorSpace( + static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace())); } void EglManager::initExtensions() { @@ -148,6 +162,7 @@ void EglManager::initExtensions() { #else EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb"); #endif + EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3"); EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority"); EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context"); } @@ -160,6 +175,10 @@ void EglManager::loadConfigs() { ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior)); EGLint swapBehavior = (mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; + + // Note: The default pixel format is RGBA_8888, when other formats are + // available, we should check the target pixel format and configure the + // attributes list properly. EGLint attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, @@ -255,11 +274,12 @@ void EglManager::createPBufferSurface() { } } -EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) { +EGLSurface EglManager::createSurface(EGLNativeWindowType window, ColorMode colorMode) { LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized"); - wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB && - EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext; + bool wideColorGamut = colorMode == ColorMode::WideColorGamut && EglExtensions.glColorSpace && + EglExtensions.scRGB && EglExtensions.pixelFormatFloat && + EglExtensions.noConfigContext; // The color space we want to use depends on whether linear blending is turned // on and whether the app has requested wide color gamut rendering. When wide @@ -269,9 +289,9 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG // When wide gamut rendering is off: // - Blending is done by default in gamma space, which requires using a // linear EGL color space (the GPU uses the color values as is) - // - If linear blending is on, we must use the sRGB EGL color space (the - // GPU will perform sRGB to linear and linear to SRGB conversions before - // and after blending) + // - If linear blending is on, we must use the non-linear EGL color space + // (the GPU will perform sRGB to linear and linear to SRGB conversions + // before and after blending) // // When wide gamut rendering is on we cannot rely on the GPU performing // linear blending for us. We use two different color spaces to tag the @@ -279,7 +299,7 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG // - Gamma blending (default) requires the use of the scRGB-nl color space // - Linear blending requires the use of the scRGB color space - // Not all Android targets support the EGL_GL_COLOR_SPACE_KHR extension + // Not all Android targets support the EGL_GL_COLORSPACE_KHR extension // We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value. // According to section 3.4.1 of the EGL specification, the attributes // list is considered empty if the first entry is EGL_NONE @@ -291,13 +311,21 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG if (wideColorGamut) { attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT; } else { - attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; + if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) { + attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT; + } else { + attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; + } } #else if (wideColorGamut) { attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT; } else { - attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; + if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) { + attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT; + } else { + attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; + } } #endif } diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index 507673adf26e..e97228cd0a39 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -18,11 +18,13 @@ #include <EGL/egl.h> #include <EGL/eglext.h> +#include <SkImageInfo.h> #include <SkRect.h> #include <cutils/compiler.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <utils/StrongPointer.h> +#include "IRenderPipeline.h" namespace android { namespace uirenderer { @@ -45,7 +47,7 @@ public: bool hasEglContext(); - EGLSurface createSurface(EGLNativeWindowType window, bool wideColorGamut); + EGLSurface createSurface(EGLNativeWindowType window, ColorMode colorMode); void destroySurface(EGLSurface surface); void destroy(); @@ -76,6 +78,9 @@ public: // Depending on installed extensions, the result is either Android native fence or EGL fence. status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence); + SkColorType getSurfaceColorType() const { return mSurfaceColorType; } + sk_sp<SkColorSpace> getSurfaceColorSpace() { return mSurfaceColorSpace; } + private: void initExtensions(); @@ -89,8 +94,10 @@ private: EGLConfig mEglConfigWideGamut; EGLContext mEglContext; EGLSurface mPBufferSurface; - EGLSurface mCurrentSurface; + SkColorSpace::Gamut mSurfaceColorGamut; + SkColorType mSurfaceColorType; + sk_sp<SkColorSpace> mSurfaceColorSpace; enum class SwapBehavior { Discard, diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index b7b7853e6ed7..0297c9c141ff 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -16,11 +16,12 @@ #pragma once +#include "DamageAccumulator.h" #include "FrameInfoVisualizer.h" #include "LayerUpdateQueue.h" +#include "Lighting.h" #include "SwapBehavior.h" #include "hwui/Bitmap.h" -#include "thread/TaskManager.h" #include <SkRect.h> #include <utils/RefBase.h> @@ -35,13 +36,25 @@ namespace uirenderer { class DeferredLayerUpdater; class ErrorHandler; +class TaskManager; namespace renderthread { enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded }; enum class ColorMode { - Srgb, + // Legacy means HWUI will produce buffer with whatever platform prefers + // HWUI to produce, however, HWUI doesn't accurately convert color from + // source color space to destination color space, instead HWUI will take + // the pixel value directly and interpret it destination color space. + Legacy, + // DisplayColorGamut means HWUI will produce buffer with whatever platform + // prefers HWUI to produce and accurately convert color from source color + // space to destination color space. + DisplayColorGamut, + // WideColorGamut means HWUI would support rendering scRGB non-linear into + // a signed buffer with enough range to support the wide color gamut of the + // display. WideColorGamut, // Hdr }; @@ -55,7 +68,7 @@ public: virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, - bool opaque, bool wideColorGamut, const LightInfo& lightInfo, + bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) = 0; virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, @@ -67,15 +80,17 @@ public: virtual bool isContextReady() = 0; virtual void onDestroyHardwareResources() = 0; virtual void renderLayers(const LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, + LayerUpdateQueue* layerUpdateQueue, bool opaque, const LightInfo& lightInfo) = 0; virtual TaskManager* getTaskManager() = 0; virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, - bool wideColorGamut, ErrorHandler* errorHandler) = 0; + ErrorHandler* errorHandler) = 0; virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0; virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0; virtual void unpinImages() = 0; virtual void onPrepareTree() = 0; + virtual SkColorType getSurfaceColorType() const = 0; + virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0; virtual ~IRenderPipeline() {} }; diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index ebc11a50685e..7a539ae42605 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -118,6 +118,10 @@ public: // Creates a fence that is signaled, when all the pending Vulkan commands are flushed. status_t createReleaseFence(sp<Fence>& nativeFence); + // TODO(b/115636873): Handle composition preference. + SkColorType getSurfaceColorType() const { return SkColorType::kN32_SkColorType; } + sk_sp<SkColorSpace> getSurfaceColorSpace() { return SkColorSpace::MakeSRGB(); } + private: friend class RenderThread; diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 48bc8e4df155..2926ef3a2d95 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -537,7 +537,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) { layerUpdateQueue.enqueueLayerWithDamage(child.get(), android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT)); auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); - pipeline->renderLayersImpl(layerUpdateQueue, true, false); + pipeline->renderLayersImpl(layerUpdateQueue, true); EXPECT_EQ(1, drawCounter); // assert index 0 is drawn on the layer RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true); diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index a9124d90f9a5..5e5d13485942 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -50,7 +50,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) { auto surface = SkSurface::MakeRasterN32Premul(1, 1); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); } @@ -83,7 +83,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) { ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); } @@ -105,11 +105,11 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) { auto surface = SkSurface::MakeRasterN32Premul(2, 2); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); @@ -129,7 +129,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) { auto surface = SkSurface::MakeRasterN32Premul(2, 2); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE); @@ -171,7 +171,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) { lightGeometry.center = {0.0f, 0.0f, 0.0f}; LightInfo lightInfo; auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); - pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo); + pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo); ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED); ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE); @@ -202,37 +202,37 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) { ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); // Single draw, should be white. - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE); // 1 Overdraw, should be blue blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff); // 2 Overdraw, should be green blended onto white renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0); // 3 Overdraw, should be pink blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0); // 4 Overdraw, should be red blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); // 5 Overdraw, should be red blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds, + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); } @@ -318,7 +318,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) { SkRect dirty = SkRect::MakeWH(800, 600); auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); sk_sp<DeferLayer<DeferTestCanvas>> surface(new DeferLayer<DeferTestCanvas>()); - pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false, contentDrawBounds, surface); + pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface); EXPECT_EQ(4, surface->canvas()->mDrawCounter); } @@ -348,7 +348,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) { SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40); auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>()); - pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false, + pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface); EXPECT_EQ(1, surface->canvas()->mDrawCounter); } @@ -378,7 +378,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) { SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40); auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>()); - pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false, + pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface); EXPECT_EQ(1, surface->canvas()->mDrawCounter); } diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index a3e785957526..d35fe4f01aa0 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -57,6 +57,45 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) { return false; } +SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) { + switch (pixelFormat) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + return SkColorType::kN32_SkColorType; + case HAL_PIXEL_FORMAT_RGBA_FP16: + return SkColorType::kRGBA_F16_SkColorType; + case HAL_PIXEL_FORMAT_RGBA_1010102: + return SkColorType::kRGBA_1010102_SkColorType; + default: + ALOGW("Unsupported pixel format: %d, return kN32 by default", pixelFormat); + return SkColorType::kN32_SkColorType; + } +} + +SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) { + switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) { + case HAL_DATASPACE_STANDARD_BT709: + return SkColorSpace::kSRGB_Gamut; + case HAL_DATASPACE_STANDARD_BT2020: + return SkColorSpace::kRec2020_Gamut; + case HAL_DATASPACE_STANDARD_DCI_P3: + return SkColorSpace::kDCIP3_D65_Gamut; + case HAL_DATASPACE_STANDARD_ADOBE_RGB: + return SkColorSpace::kAdobeRGB_Gamut; + case HAL_DATASPACE_STANDARD_UNSPECIFIED: + case HAL_DATASPACE_STANDARD_BT601_625: + case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED: + case HAL_DATASPACE_STANDARD_BT601_525: + case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED: + case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE: + case HAL_DATASPACE_STANDARD_BT470M: + case HAL_DATASPACE_STANDARD_FILM: + default: + ALOGW("Unsupported Gamut: %d, return SRGB gamut by default", dataSpace); + return SkColorSpace::kSRGB_Gamut; + } +} + sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { SkColorSpace::Gamut gamut; diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index 3c13a548fe76..ff0e755934f2 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -21,6 +21,7 @@ #include <SkColor.h> #include <SkColorSpace.h> +#include <SkImageInfo.h> namespace android { namespace uirenderer { @@ -113,6 +114,10 @@ static constexpr float EOCF(float srgb) { // returns true for sRGB, gamma 2.2 and Display P3 for instance bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); +SkColorType PixelFormatToColorType(android_pixel_format pixelFormat); + +SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace); + sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace); struct Lab { diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java index 119d1e0071e5..ae139499eeb2 100644 --- a/location/java/android/location/CountryDetector.java +++ b/location/java/android/location/CountryDetector.java @@ -21,6 +21,7 @@ import java.util.HashMap; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; import android.content.Context; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; @@ -88,7 +89,7 @@ public class CountryDetector { * create an instance of this class is using the factory * Context.getSystemService. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public CountryDetector(ICountryDetector service) { mService = service; mListeners = new HashMap<CountryListener, ListenerTransport>(); diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 5ad73653a615..f1325ce9bae9 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -375,11 +376,11 @@ public final class AudioAttributes implements Parcelable { @UnsupportedAppUsage private int mUsage = USAGE_UNKNOWN; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mContentType = CONTENT_TYPE_UNKNOWN; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mFlags = 0x0; private HashSet<String> mTags; @UnsupportedAppUsage diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index aaf7dd793060..62e58cab0772 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -1656,7 +1656,7 @@ public class AudioTrack extends PlayerBase * @param timestamp a reference to a non-null AudioTimestamp instance allocated * and owned by caller. * @return true if a timestamp is available, or false if no timestamp is available. - * If a timestamp if available, + * If a timestamp is available, * the AudioTimestamp instance is filled in with a position in frame units, together * with the estimated time when that frame was presented or is committed to * be presented. diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index d45acdfa627e..d1d605fc8399 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -24,6 +24,7 @@ import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.media.MediaCodecInfo.CodecCapabilities; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -3580,7 +3581,7 @@ final public class MediaCodec { native_init(); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private long mNativeContext; /** @hide */ diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index ef312d125694..995ebb2897c5 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -19,6 +19,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.util.Log; import android.util.Pair; import android.util.Range; @@ -1589,7 +1590,7 @@ public final class MediaCodecInfo { private VideoCapabilities() { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static VideoCapabilities create( MediaFormat info, CodecCapabilities parent) { VideoCapabilities caps = new VideoCapabilities(); diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 43bee852f94b..ffeff4d93d15 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -34,6 +34,7 @@ import android.hardware.display.DisplayManager; import android.hardware.display.WifiDisplay; import android.hardware.display.WifiDisplayStatus; import android.media.session.MediaSession; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Process; @@ -2064,7 +2065,7 @@ public class MediaRouter { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean isDefault() { return this == sStatic.mDefaultAudioVideo; } diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java index 716e0cbf9fb4..f704acde7cf7 100644 --- a/media/java/android/media/MiniThumbFile.java +++ b/media/java/android/media/MiniThumbFile.java @@ -18,9 +18,12 @@ package android.media; import android.annotation.UnsupportedAppUsage; import android.net.Uri; +import android.os.Build; import android.os.Environment; import android.util.Log; +import dalvik.system.VMRuntime; + import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; @@ -42,7 +45,10 @@ import java.util.Hashtable; * * @hide This file is shared between MediaStore and MediaProvider and should remained internal use * only. + * @deprecated thumbnails are now maintained in separate files, and this file + * format is no longer used. */ +@Deprecated public class MiniThumbFile { private static final String TAG = "MiniThumbFile"; private static final int MINI_THUMB_DATA_FILE_VERSION = 4; @@ -69,6 +75,9 @@ public class MiniThumbFile { } public static synchronized MiniThumbFile instance(Uri uri) { + if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) { + throw new UnsupportedOperationException(); + } String type = uri.getPathSegments().get(1); MiniThumbFile file = sThumbFiles.get(type); // Log.v(TAG, "get minithumbfile for type: "+type); diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java index 6594dd79f981..3fe1a32265dc 100644 --- a/media/java/android/media/PlaybackParams.java +++ b/media/java/android/media/PlaybackParams.java @@ -19,6 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -94,7 +95,7 @@ public final class PlaybackParams implements Parcelable { private static final int SET_AUDIO_FALLBACK_MODE = 1 << 2; @UnsupportedAppUsage private static final int SET_AUDIO_STRETCH_MODE = 1 << 3; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mSet = 0; // params @@ -104,7 +105,7 @@ public final class PlaybackParams implements Parcelable { private int mAudioStretchMode = AUDIO_STRETCH_MODE_DEFAULT; @UnsupportedAppUsage private float mPitch = 1.0f; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private float mSpeed = 1.0f; public PlaybackParams() { diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 1a456f69458d..97468423219a 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -21,6 +21,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -872,7 +873,7 @@ public class AudioEffect { * In case of failure, the returned value is negative and implementation specific. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int command(int cmdCode, byte[] command, byte[] reply) throws IllegalStateException { checkState("command()"); diff --git a/native/android/Android.bp b/native/android/Android.bp index 43847cc4ab06..24d003b7c2b1 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { "sharedmem.cpp", "storage_manager.cpp", "surface_texture.cpp", + "system_fonts.cpp", "trace.cpp", ], @@ -65,6 +66,7 @@ cc_library_shared { "libandroid_runtime", "libnetd_client", "libhwui", + "libxml2", ], static_libs: [ diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index ac5ded60bf6b..9f48bc97e94c 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -212,6 +212,18 @@ LIBANDROID { ASurfaceTexture_getTransformMatrix; # introduced=28 ASurfaceTexture_release; # introduced=28 ASurfaceTexture_updateTexImage; # introduced=28 + ASystemFontIterator_open; # introduced=29 + ASystemFontIterator_close; # introduced=29 + ASystemFontIterator_next; # introduced=29 + ASystemFont_close; # introduced=29 + ASystemFont_getFontFilePath; # introduced=29 + ASystemFont_getWeight; # introduced=29 + ASystemFont_isItalic; # introduced=29 + ASystemFont_getLocale; # introduced=29 + ASystemFont_getCollectionIndex; # introduced=29 + ASystemFont_getAxisCount; # introduced=29 + ASystemFont_getAxisTag; # introduced=29 + ASystemFont_getAxisValue; # introduced=29 ATrace_beginSection; # introduced=23 ATrace_endSection; # introduced=23 ATrace_isEnabled; # introduced=23 diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp new file mode 100644 index 000000000000..b95adad78f89 --- /dev/null +++ b/native/android/system_fonts.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <jni.h> + +#include <android/system_fonts.h> + +#include <memory> +#include <string> +#include <vector> + +#include <errno.h> +#include <fcntl.h> +#include <libxml/tree.h> +#include <log/log.h> +#include <sys/stat.h> +#include <unistd.h> + +struct XmlCharDeleter { + void operator()(xmlChar* b) { xmlFree(b); } +}; + +struct XmlDocDeleter { + void operator()(xmlDoc* d) { xmlFreeDoc(d); } +}; + +using XmlCharUniquePtr = std::unique_ptr<xmlChar, XmlCharDeleter>; +using XmlDocUniquePtr = std::unique_ptr<xmlDoc, XmlDocDeleter>; + +struct ASystemFontIterator { + XmlDocUniquePtr mXmlDoc; + xmlNode* mFontNode; +}; + +struct ASystemFont { + std::string mFilePath; + std::unique_ptr<std::string> mLocale; + uint16_t mWeight; + bool mItalic; + uint32_t mCollectionIndex; + std::vector<std::pair<uint32_t, float>> mAxes; +}; + +namespace { + +std::string xmlTrim(const std::string& in) { + if (in.empty()) { + return in; + } + const char XML_SPACES[] = "\u0020\u000D\u000A\u0009"; + const size_t start = in.find_first_not_of(XML_SPACES); // inclusive + if (start == std::string::npos) { + return ""; + } + const size_t end = in.find_last_not_of(XML_SPACES); // inclusive + if (end == std::string::npos) { + return ""; + } + return in.substr(start, end - start + 1 /* +1 since end is inclusive */); +} + +const xmlChar* FAMILY_TAG = BAD_CAST("family"); +const xmlChar* FONT_TAG = BAD_CAST("font"); + +xmlNode* firstElement(xmlNode* node, const xmlChar* tag) { + for (xmlNode* child = node->children; child; child = child->next) { + if (xmlStrEqual(child->name, tag)) { + return child; + } + } + return nullptr; +} + +xmlNode* nextSibling(xmlNode* node, const xmlChar* tag) { + while ((node = node->next) != nullptr) { + if (xmlStrEqual(node->name, tag)) { + return node; + } + } + return nullptr; +} + +void copyFont(ASystemFontIterator* ite, ASystemFont* out) { + const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang"); + XmlCharUniquePtr filePathStr( + xmlNodeListGetString(ite->mXmlDoc.get(), ite->mFontNode->xmlChildrenNode, 1)); + out->mFilePath = "/system/fonts/" + xmlTrim( + std::string(filePathStr.get(), filePathStr.get() + xmlStrlen(filePathStr.get()))); + + const xmlChar* WEIGHT_ATTR_NAME = BAD_CAST("weight"); + XmlCharUniquePtr weightStr(xmlGetProp(ite->mFontNode, WEIGHT_ATTR_NAME)); + out->mWeight = weightStr ? + strtol(reinterpret_cast<const char*>(weightStr.get()), nullptr, 10) : 400; + + const xmlChar* STYLE_ATTR_NAME = BAD_CAST("style"); + const xmlChar* ITALIC_ATTR_VALUE = BAD_CAST("italic"); + XmlCharUniquePtr styleStr(xmlGetProp(ite->mFontNode, STYLE_ATTR_NAME)); + out->mItalic = styleStr ? xmlStrEqual(styleStr.get(), ITALIC_ATTR_VALUE) : false; + + const xmlChar* INDEX_ATTR_NAME = BAD_CAST("index"); + XmlCharUniquePtr indexStr(xmlGetProp(ite->mFontNode, INDEX_ATTR_NAME)); + out->mCollectionIndex = indexStr ? + strtol(reinterpret_cast<const char*>(indexStr.get()), nullptr, 10) : 0; + + XmlCharUniquePtr localeStr(xmlGetProp(ite->mXmlDoc->parent, LOCALE_ATTR_NAME)); + out->mLocale.reset( + localeStr ? new std::string(reinterpret_cast<const char*>(localeStr.get())) : nullptr); + + const xmlChar* TAG_ATTR_NAME = BAD_CAST("tag"); + const xmlChar* STYLEVALUE_ATTR_NAME = BAD_CAST("stylevalue"); + const xmlChar* AXIS_TAG = BAD_CAST("axis"); + out->mAxes.clear(); + for (xmlNode* axis = firstElement(ite->mFontNode, AXIS_TAG); axis; + axis = nextSibling(axis, AXIS_TAG)) { + XmlCharUniquePtr tagStr(xmlGetProp(axis, TAG_ATTR_NAME)); + if (!tagStr || xmlStrlen(tagStr.get()) != 4) { + continue; // Tag value must be 4 char string + } + + XmlCharUniquePtr styleValueStr(xmlGetProp(axis, STYLEVALUE_ATTR_NAME)); + if (!styleValueStr) { + continue; + } + + uint32_t tag = + static_cast<uint32_t>(tagStr.get()[0] << 24) | + static_cast<uint32_t>(tagStr.get()[1] << 16) | + static_cast<uint32_t>(tagStr.get()[2] << 8) | + static_cast<uint32_t>(tagStr.get()[3]); + float styleValue = strtod(reinterpret_cast<const char*>(styleValueStr.get()), nullptr); + out->mAxes.push_back(std::make_pair(tag, styleValue)); + } +} + +bool isFontFileAvailable(const std::string& filePath) { + std::string fullPath = filePath; + struct stat st = {}; + if (stat(fullPath.c_str(), &st) != 0) { + return false; + } + return S_ISREG(st.st_mode); +} + +xmlNode* findFirstFontNode(xmlDoc* doc) { + xmlNode* familySet = xmlDocGetRootElement(doc); + if (familySet == nullptr) { + return nullptr; + } + xmlNode* family = firstElement(familySet, FAMILY_TAG); + if (family == nullptr) { + return nullptr; + } + + xmlNode* font = firstElement(family, FONT_TAG); + while (font == nullptr) { + family = nextSibling(family, FAMILY_TAG); + if (family == nullptr) { + return nullptr; + } + font = firstElement(family, FONT_TAG); + } + return font; +} + +} // namespace + +ASystemFontIterator* ASystemFontIterator_open() { + std::unique_ptr<ASystemFontIterator> ite(new ASystemFontIterator()); + ite->mXmlDoc.reset(xmlReadFile("/system/etc/fonts.xml", nullptr, 0)); + return ite.release(); +} + +void ASystemFontIterator_close(ASystemFontIterator* ite) { + delete ite; +} + +ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) { + LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument"); + if (ite->mFontNode == nullptr) { + if (ite->mXmlDoc == nullptr) { + return nullptr; // Already at the end. + } else { + // First time to query font. + ite->mFontNode = findFirstFontNode(ite->mXmlDoc.get()); + if (ite->mFontNode == nullptr) { + ite->mXmlDoc.reset(); + return nullptr; // No font node found. + } + std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>(); + copyFont(ite, font.get()); + return font.release(); + } + } else { + xmlNode* nextNode = nextSibling(ite->mFontNode, FONT_TAG); + while (nextNode == nullptr) { + xmlNode* family = nextSibling(ite->mFontNode->parent, FAMILY_TAG); + if (family == nullptr) { + break; + } + nextNode = firstElement(family, FONT_TAG); + } + ite->mFontNode = nextNode; + if (nextNode == nullptr) { + ite->mXmlDoc.reset(); + return nullptr; + } + + std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>(); + copyFont(ite, font.get()); + if (!isFontFileAvailable(font->mFilePath)) { + // fonts.xml intentionally contains missing font configuration. Skip it. + return ASystemFontIterator_next(ite); + } + return font.release(); + } +} + +void ASystemFont_close(ASystemFont* font) { + delete font; +} + +const char* ASystemFont_getFontFilePath(const ASystemFont* font) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument"); + return font->mFilePath.c_str(); +} + +uint16_t ASystemFont_getWeight(const ASystemFont* font) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument"); + return font->mWeight; +} + +bool ASystemFont_isItalic(const ASystemFont* font) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument"); + return font->mItalic; +} + +const char* ASystemFont_getLocale(const ASystemFont* font) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); + return font->mLocale ? nullptr : font->mLocale->c_str(); +} + +size_t ASystemFont_getCollectionIndex(const ASystemFont* font) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); + return font->mCollectionIndex; +} + +size_t ASystemFont_getAxisCount(const ASystemFont* font) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); + return font->mAxes.size(); +} + +uint32_t ASystemFont_getAxisTag(const ASystemFont* font, uint32_t axisIndex) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); + LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(), + "given axis index is out of bounds. (< %zd", font->mAxes.size()); + return font->mAxes[axisIndex].first; +} + +float ASystemFont_getAxisValue(const ASystemFont* font, uint32_t axisIndex) { + LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); + LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(), + "given axis index is out of bounds. (< %zd", font->mAxes.size()); + return font->mAxes[axisIndex].second; +} diff --git a/native/webview/loader/loader.cpp b/native/webview/loader/loader.cpp index fee2a259cb54..7f71f6312f00 100644 --- a/native/webview/loader/loader.cpp +++ b/native/webview/loader/loader.cpp @@ -26,6 +26,7 @@ #include <string.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> @@ -58,6 +59,7 @@ jboolean DoReserveAddressSpace(jlong size) { vsize, strerror(errno)); return JNI_FALSE; } + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, vsize, "libwebview reservation"); gReservedAddress = addr; gReservedSize = vsize; ALOGV("Reserved %zd bytes at %p", vsize, addr); diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java index 3bade25b712a..192a40c5e79a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java @@ -26,6 +26,12 @@ import android.view.View; import androidx.preference.DialogPreference; import androidx.preference.PreferenceDialogFragment; +/** + * Framework version is deprecated, use the compat version instead. + * + * @deprecated + */ +@Deprecated public class CustomDialogPreference extends DialogPreference { private CustomPreferenceDialogFragment mFragment; diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java index dfaff6108c89..3caa0bb9cf4b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java @@ -31,6 +31,12 @@ import androidx.annotation.CallSuper; import androidx.preference.EditTextPreference; import androidx.preference.EditTextPreferenceDialogFragment; +/** + * Framework version is deprecated, use the compat version instead. + * + * @deprecated + */ +@Deprecated public class CustomEditTextPreference extends EditTextPreference { private CustomPreferenceDialogFragment mFragment; diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java index 223c05546b7f..60d22a0d5803 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java @@ -34,8 +34,11 @@ import android.os.RemoteException; import com.android.settingslib.AppItem; /** - * Loader for historical chart data for both network and UID details. + * Framework loader is deprecated, use the compat version instead. + * + * @deprecated */ +@Deprecated public class ChartDataLoader extends AsyncTaskLoader<ChartData> { private static final String KEY_TEMPLATE = "template"; private static final String KEY_APP = "app"; diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java index 572bae1112da..649aeffd0d5f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java @@ -24,6 +24,12 @@ import android.net.NetworkTemplate; import android.os.Bundle; import android.os.RemoteException; +/** + * Framework loader is deprecated, use the compat version instead. + * + * @deprecated + */ +@Deprecated public class SummaryForAllUidLoader extends AsyncTaskLoader<NetworkStats> { private static final String KEY_TEMPLATE = "template"; private static final String KEY_START = "start"; diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java index 6597daa9acaf..b0e987ee2779 100644 --- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java @@ -32,8 +32,11 @@ import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.List; /** - * Manages IPC communication to SettingsIntelligence for suggestion related services. + * Framework mixin is deprecated, use the compat version instead. + * + * @deprecated */ +@Deprecated public class SuggestionControllerMixin implements SuggestionController.ServiceConnectionListener, androidx.lifecycle.LifecycleObserver, LoaderManager.LoaderCallbacks<List<Suggestion>> { @@ -65,7 +68,7 @@ public class SuggestionControllerMixin implements SuggestionController.ServiceCo mContext = context.getApplicationContext(); mHost = host; mSuggestionController = new SuggestionController(mContext, componentName, - this /* serviceConnectionListener */); + this /* serviceConnectionListener */); if (lifecycle != null) { lifecycle.addObserver(this); } diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java index 9c1af1edc778..8011424bb0d2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java @@ -24,6 +24,12 @@ import com.android.settingslib.utils.AsyncLoader; import java.util.List; +/** + * Framework loader is deprecated, use the compat version instead. + * + * @deprecated + */ +@Deprecated public class SuggestionLoader extends AsyncLoader<List<Suggestion>> { public static final int LOADER_ID_SUGGESTIONS = 42; diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java index 06770ac09558..64b9ffe7a735 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java @@ -29,7 +29,9 @@ import android.content.Context; * This loader is based on the MailAsyncTaskLoader from the AOSP EmailUnified repo. * * @param <T> the data type to be loaded. + * @deprecated Framework loader is deprecated, use the compat version instead. */ +@Deprecated public abstract class AsyncLoader<T> extends AsyncTaskLoader<T> { private T mResult; diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java index 2987c1597193..fcf236337703 100644 --- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java +++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java @@ -25,6 +25,12 @@ import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.SetPreferenceScreen; +/** + * Framework mixin is deprecated, use the compat version instead. + * + * @deprecated + */ +@Deprecated public class FooterPreferenceMixin implements LifecycleObserver, SetPreferenceScreen { private final PreferenceFragment mFragment; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 290a4f83a40a..63978ba60171 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2948,7 +2948,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 171; + private static final int SETTINGS_VERSION = 172; private final int mUserId; @@ -3900,6 +3900,37 @@ public class SettingsProvider extends ContentProvider { currentVersion = 171; } + if (currentVersion == 171) { + // Version 171: by default, add STREAM_VOICE_CALL to list of streams that can + // be muted. + final SettingsState systemSettings = getSystemSettingsLocked(userId); + final Setting currentSetting = systemSettings.getSettingLocked( + Settings.System.MUTE_STREAMS_AFFECTED); + if (!currentSetting.isNull()) { + try { + int currentSettingIntegerValue = Integer.parseInt( + currentSetting.getValue()); + if ((currentSettingIntegerValue + & (1 << AudioManager.STREAM_VOICE_CALL)) == 0) { + systemSettings.insertSettingLocked( + Settings.System.MUTE_STREAMS_AFFECTED, + Integer.toString( + currentSettingIntegerValue + | (1 << AudioManager.STREAM_VOICE_CALL)), + null, true, SettingsState.SYSTEM_PACKAGE_NAME); + } + } catch (NumberFormatException e) { + // remove the setting in case it is not a valid integer + Slog.w("Failed to parse integer value of MUTE_STREAMS_AFFECTED" + + "setting, removing setting", e); + systemSettings.deleteSettingLocked( + Settings.System.MUTE_STREAMS_AFFECTED); + } + + } + currentVersion = 172; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java index b6f51bc4d781..95569dc6d1b7 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java @@ -613,7 +613,7 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { final String name, final String value, final int userId) throws Exception { ContentResolver contentResolver = getContext().getContentResolver(); - final Uri settingUri = getBaseUriForType(type); + final Uri settingUri = getBaseUriForType(type).buildUpon().appendPath(name).build(); final AtomicBoolean success = new AtomicBoolean(); @@ -640,20 +640,22 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { final long startTimeMillis = SystemClock.uptimeMillis(); synchronized (mLock) { - if (success.get()) { - return; - } - final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; - if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) { - fail("Could not change setting for " - + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms"); - } - final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS - - elapsedTimeMillis; - try { - mLock.wait(remainingTimeMillis); - } catch (InterruptedException ie) { - /* ignore */ + while (true) { + if (success.get()) { + return; + } + final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; + if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) { + fail("Could not change setting for " + + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms"); + } + final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + - elapsedTimeMillis; + try { + mLock.wait(remainingTimeMillis); + } catch (InterruptedException ie) { + /* ignore */ + } } } } finally { @@ -689,39 +691,50 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { } @Test - public void testUpdateLocationProvidersAllowedLocked_enableProviders() throws Exception { - setSettingViaFrontEndApiAndAssertSuccessfulChange( + public void testLocationModeChanges_viaFrontEndApi() throws Exception { + setStringViaFrontEndApiSetting( SETTING_TYPE_SECURE, Settings.Secure.LOCATION_MODE, String.valueOf(Settings.Secure.LOCATION_MODE_OFF), UserHandle.USER_SYSTEM); - - // Enable one provider - updateStringViaProviderApiSetting( - SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+gps"); - assertEquals( "Wrong location providers", - "gps", - queryStringViaProviderApi( - SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)); + "", + getStringViaFrontEndApiSetting( + SETTING_TYPE_SECURE, + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + UserHandle.USER_SYSTEM)); - // Enable a list of providers, including the one that is already enabled - updateStringViaProviderApiSetting( + setStringViaFrontEndApiSetting( SETTING_TYPE_SECURE, - Settings.Secure.LOCATION_PROVIDERS_ALLOWED, - "+gps,+network,+network"); + Settings.Secure.LOCATION_MODE, + String.valueOf(Settings.Secure.LOCATION_MODE_BATTERY_SAVING), + UserHandle.USER_SYSTEM); + assertEquals( + "Wrong location providers", + "network", + getStringViaFrontEndApiSetting( + SETTING_TYPE_SECURE, + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + UserHandle.USER_SYSTEM)); + setStringViaFrontEndApiSetting( + SETTING_TYPE_SECURE, + Settings.Secure.LOCATION_MODE, + String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY), + UserHandle.USER_SYSTEM); assertEquals( "Wrong location providers", "gps,network", - queryStringViaProviderApi( - SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)); + getStringViaFrontEndApiSetting( + SETTING_TYPE_SECURE, + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + UserHandle.USER_SYSTEM)); } @Test - public void testUpdateLocationProvidersAllowedLocked_disableProviders() throws Exception { - setSettingViaFrontEndApiAndAssertSuccessfulChange( + public void testLocationProvidersAllowed_disableProviders() throws Exception { + setStringViaFrontEndApiSetting( SETTING_TYPE_SECURE, Settings.Secure.LOCATION_MODE, String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY), @@ -732,7 +745,6 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-gps,-network"); - assertEquals( "Wrong location providers", "", @@ -744,7 +756,6 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test"); - assertEquals( "Wrong location providers", "", @@ -753,8 +764,8 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { } @Test - public void testUpdateLocationProvidersAllowedLocked_enableAndDisable() throws Exception { - setSettingViaFrontEndApiAndAssertSuccessfulChange( + public void testLocationProvidersAllowed_enableAndDisable() throws Exception { + setStringViaFrontEndApiSetting( SETTING_TYPE_SECURE, Settings.Secure.LOCATION_MODE, String.valueOf(Settings.Secure.LOCATION_MODE_OFF), @@ -775,8 +786,8 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { } @Test - public void testUpdateLocationProvidersAllowedLocked_invalidInput() throws Exception { - setSettingViaFrontEndApiAndAssertSuccessfulChange( + public void testLocationProvidersAllowedLocked_invalidInput() throws Exception { + setStringViaFrontEndApiSetting( SETTING_TYPE_SECURE, Settings.Secure.LOCATION_MODE, String.valueOf(Settings.Secure.LOCATION_MODE_OFF), diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index e31dd1e6b606..3725940f159c 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -216,6 +216,7 @@ <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> + <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> <application android:name=".SystemUIApplication" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index 5fe362fc4d10..6b6566cc1d68 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -415,10 +415,10 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { return false; } NotificationGroup group = mGroupMap.get(getGroupKey(sbn)); - if (group == null) { + if (group == null || group.summary == null) { return false; } - return !group.children.isEmpty(); + return !group.children.isEmpty() && Objects.equals(group.summary.notification, sbn); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 7ec4db21b694..7316c02dd226 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -732,10 +732,12 @@ public class StatusBar extends SystemUI implements DemoMode, IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService( Context.VR_SERVICE)); - try { - vrManager.registerListener(mVrStateCallbacks); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to register VR mode state listener: " + e); + if (vrManager != null) { + try { + vrManager.registerListener(mVrStateCallbacks); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register VR mode state listener: " + e); + } } IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index 3c16329e6f19..e9efaa14ef7c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -205,6 +205,8 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof public void onTetheringFailed() { if (DEBUG) Log.d(TAG, "onTetheringFailed"); mWaitingForCallback = false; + // TODO(b/110697252): stopTethering must be called to reset soft ap state after failure + mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI); fireHotspotChangedCallback(isHotspotEnabled()); // TODO: Show error. } diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 8b1324a77a5e..e73c70b29b74 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -17,6 +17,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:tools="http://schemas.android.com/tools" + android:sharedUserId="android.uid.system" package="com.android.systemui.tests"> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java new file mode 100644 index 000000000000..6a3c8a850831 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; + +import android.app.ActivityManager; +import android.app.Notification; +import android.os.UserHandle; +import android.service.notification.StatusBarNotification; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener; +import com.android.systemui.statusbar.policy.HeadsUpManager; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class NotificationGroupManagerTest extends SysuiTestCase { + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + private static final String TEST_CHANNEL_ID = "test_channel"; + private static final String TEST_GROUP_ID = "test_group"; + private static final String TEST_PACKAGE_NAME = "test_pkg"; + private NotificationGroupManager mGroupManager = new NotificationGroupManager(); + private int mId = 0; + + @Mock HeadsUpManager mHeadsUpManager; + + @Before + public void setup() { + mGroupManager.setHeadsUpManager(mHeadsUpManager); + mGroupManager.setOnGroupChangeListener(mock(OnGroupChangeListener.class)); + } + + @Test + public void testIsOnlyChildInGroup() { + NotificationData.Entry childEntry = createChildNotification(); + NotificationData.Entry summaryEntry = createSummaryNotification(); + + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + + assertTrue(mGroupManager.isOnlyChildInGroup(childEntry.notification)); + } + + @Test + public void testIsChildInGroupWithSummary() { + NotificationData.Entry childEntry = createChildNotification(); + NotificationData.Entry summaryEntry = createSummaryNotification(); + + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + mGroupManager.onEntryAdded(createChildNotification()); + + assertTrue(mGroupManager.isChildInGroupWithSummary(childEntry.notification)); + } + + @Test + public void testIsSummaryOfGroupWithChildren() { + NotificationData.Entry childEntry = createChildNotification(); + NotificationData.Entry summaryEntry = createSummaryNotification(); + + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + mGroupManager.onEntryAdded(createChildNotification()); + + assertTrue(mGroupManager.isSummaryOfGroup(summaryEntry.notification)); + assertEquals(summaryEntry.row, mGroupManager.getGroupSummary(childEntry.notification)); + } + + @Test + public void testRemoveChildFromGroupWithSummary() { + NotificationData.Entry childEntry = createChildNotification(); + NotificationData.Entry summaryEntry = createSummaryNotification(); + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + mGroupManager.onEntryAdded(createChildNotification()); + + mGroupManager.onEntryRemoved(childEntry); + + assertFalse(mGroupManager.isChildInGroupWithSummary(childEntry.notification)); + } + + @Test + public void testRemoveSummaryFromGroupWithSummary() { + NotificationData.Entry childEntry = createChildNotification(); + NotificationData.Entry summaryEntry = createSummaryNotification(); + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + mGroupManager.onEntryAdded(createChildNotification()); + + mGroupManager.onEntryRemoved(summaryEntry); + + assertNull(mGroupManager.getGroupSummary(childEntry.notification)); + assertFalse(mGroupManager.isSummaryOfGroup(summaryEntry.notification)); + } + + @Test + public void testHeadsUpEntryIsIsolated() { + NotificationData.Entry childEntry = createChildNotification(); + NotificationData.Entry summaryEntry = createSummaryNotification(); + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + mGroupManager.onEntryAdded(createChildNotification()); + when(childEntry.row.isHeadsUp()).thenReturn(true); + when(mHeadsUpManager.contains(childEntry.key)).thenReturn(true); + + mGroupManager.onHeadsUpStateChanged(childEntry, true); + + // Child entries that are heads upped should be considered separate groups visually even if + // they are the same group logically + assertEquals(childEntry.row, mGroupManager.getGroupSummary(childEntry.notification)); + assertEquals(summaryEntry.row, + mGroupManager.getLogicalGroupSummary(childEntry.notification)); + } + + @Test + public void testSuppressedSummaryHeadsUpTransfersToChild() { + NotificationData.Entry summaryEntry = createSummaryNotification(); + when(summaryEntry.row.isHeadsUp()).thenReturn(true); + when(mHeadsUpManager.contains(summaryEntry.key)).thenReturn(true); + NotificationData.Entry childEntry = createChildNotification(); + + // Summary will be suppressed because there is only one child + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + + // A suppressed summary should transfer its heads up state to the child + verify(mHeadsUpManager, never()).showNotification(summaryEntry); + verify(mHeadsUpManager).showNotification(childEntry); + } + + @Test + public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() { + mHeadsUpManager = new HeadsUpManager(mContext) {}; + mGroupManager.setHeadsUpManager(mHeadsUpManager); + NotificationData.Entry summaryEntry = + createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); + when(summaryEntry.row.isHeadsUp()).thenReturn(true); + NotificationData.Entry childEntry = + createChildNotification(Notification.GROUP_ALERT_SUMMARY); + NotificationData.Entry childEntry2 = + createChildNotification(Notification.GROUP_ALERT_SUMMARY); + // Trigger a transfer of heads up state from summary to child. + mGroupManager.onEntryAdded(summaryEntry); + mGroupManager.onEntryAdded(childEntry); + when(summaryEntry.row.isHeadsUp()).thenReturn(false); + when(childEntry.row.isHeadsUp()).thenReturn(true); + + // Add second child notification so that summary is no longer suppressed. + mGroupManager.onEntryAdded(childEntry2); + + // The heads up state should transfer back to the summary as there is now more than one + // child and the summary should no longer be suppressed. + assertTrue(mHeadsUpManager.contains(summaryEntry.key)); + assertFalse(mHeadsUpManager.contains(childEntry.key)); + } + + private NotificationData.Entry createSummaryNotification() { + return createSummaryNotification(Notification.GROUP_ALERT_ALL); + } + + private NotificationData.Entry createSummaryNotification(int groupAlertBehavior) { + return createEntry(true, groupAlertBehavior); + } + + private NotificationData.Entry createChildNotification() { + return createChildNotification(Notification.GROUP_ALERT_ALL); + } + + private NotificationData.Entry createChildNotification(int groupAlertBehavior) { + return createEntry(false, groupAlertBehavior); + } + + private NotificationData.Entry createEntry(boolean isSummary, int groupAlertBehavior) { + Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID) + .setContentTitle("Title") + .setSmallIcon(R.drawable.ic_person) + .setGroupAlertBehavior(groupAlertBehavior) + .setGroupSummary(isSummary) + .setGroup(TEST_GROUP_ID) + .build(); + StatusBarNotification sbn = new StatusBarNotification( + TEST_PACKAGE_NAME /* pkg */, + TEST_PACKAGE_NAME, + mId++, + null /* tag */, + 0, /* uid */ + 0 /* initialPid */, + notif, + new UserHandle(ActivityManager.getCurrentUser()), + null /* overrideGroupKey */, + 0 /* postTime */); + NotificationData.Entry entry = new NotificationData.Entry(sbn); + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + entry.row = row; + when(row.getEntry()).thenReturn(entry); + when(row.getStatusBarNotification()).thenReturn(sbn); + return entry; + } +} diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index 371f93253a11..cf9f233b8fe2 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -170,6 +170,20 @@ class TouchExplorer extends BaseEventStreamTransformation * action. */ public TouchExplorer(Context context, AccessibilityManagerService service) { + this(context, service, null); + } + + /** + * Creates a new instance. + * + * @param context A context handle for accessing resources. + * @param service The service to notify touch interaction and gesture completed and to perform + * action. + * @param detector The gesture detector to handle accessibility touch event. If null the default + * one created in place, or for testing purpose. + */ + public TouchExplorer(Context context, AccessibilityManagerService service, + AccessibilityGestureDetector detector) { mContext = context; mAms = service; mReceivedPointerTracker = new ReceivedPointerTracker(); @@ -186,7 +200,11 @@ class TouchExplorer extends BaseEventStreamTransformation mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed( AccessibilityEvent.TYPE_TOUCH_INTERACTION_END, mDetermineUserIntentTimeout); - mGestureDetector = new AccessibilityGestureDetector(context, this); + if (detector == null) { + mGestureDetector = new AccessibilityGestureDetector(context, this); + } else { + mGestureDetector = detector; + } final float density = context.getResources().getDisplayMetrics().density; mScaledMinPointerDistanceToUseMiddleLocation = (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density); diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index 15673a7d12f9..51d95a2c1a58 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -118,10 +118,22 @@ public class BinderCallsStatsService extends Binder { this.mBinderCallsStats = binderCallsStats; } + /** @see BinderCallsStats#reset */ + public void reset() { + mBinderCallsStats.reset(); + } + + /** + * @see BinderCallsStats#getExportedCallStats. + * + * Note that binder calls stats will be reset by statsd every time + * the data is exported. + */ public ArrayList<BinderCallsStats.ExportedCallStat> getExportedCallStats() { return mBinderCallsStats.getExportedCallStats(); } + /** @see BinderCallsStats#getExportedExceptionStats */ public ArrayMap<String, Integer> getExportedExceptionStats() { return mBinderCallsStats.getExportedExceptionStats(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 2c8f2fcd8af1..3a0289cbfd63 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -68,6 +68,7 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_BOUND_SERVICE_CRASH_MAX_RETRY = "service_crash_max_retry"; static final String KEY_PROCESS_START_ASYNC = "process_start_async"; static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time"; + static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration"; private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000; @@ -97,6 +98,7 @@ final class ActivityManagerConstants extends ContentObserver { private static final int DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY = 16; private static final boolean DEFAULT_PROCESS_START_ASYNC = true; private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000; + private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000; // Maximum number of cached processes we will allow. public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; @@ -212,6 +214,10 @@ final class ActivityManagerConstants extends ContentObserver { // throttle requests from apps. public long MEMORY_INFO_THROTTLE_TIME = DEFAULT_MEMORY_INFO_THROTTLE_TIME; + // Allow app just moving from TOP to FOREGROUND_SERVICE to stay in a higher adj value for + // this long. + public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION; + // Indicates whether the activity starts logging is enabled. // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED boolean mFlagActivityStartsLoggingEnabled; @@ -355,6 +361,8 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_PROCESS_START_ASYNC); MEMORY_INFO_THROTTLE_TIME = mParser.getLong(KEY_MEMORY_INFO_THROTTLE_TIME, DEFAULT_MEMORY_INFO_THROTTLE_TIME); + TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION, + DEFAULT_TOP_TO_FGS_GRACE_DURATION); updateMaxCachedProcesses(); } @@ -438,6 +446,8 @@ final class ActivityManagerConstants extends ContentObserver { pw.println(FLAG_PROCESS_START_ASYNC); pw.print(" "); pw.print(KEY_MEMORY_INFO_THROTTLE_TIME); pw.print("="); pw.println(MEMORY_INFO_THROTTLE_TIME); + pw.print(" "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("="); + pw.println(TOP_TO_FGS_GRACE_DURATION); pw.println(); if (mOverrideMaxCachedProcesses >= 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b64e8b87aeec..7533db1c15cd 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -17778,6 +17778,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } + // If the app was recently in the foreground and moved to a foreground service status, + // allow it to get a higher rank in memory for some time, compared to other foreground + // services so that it can finish performing any persistence/processing of in-memory state. + if (app.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now + || app.setProcState <= ActivityManager.PROCESS_STATE_TOP)) { + adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; + app.adjType = "fg-service-act"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app); + } + } + if (adj > ProcessList.PERCEPTIBLE_APP_ADJ || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) { if (app.forcingToImportant != null) { @@ -18045,6 +18058,10 @@ public class ActivityManagerService extends IActivityManager.Stub cr.trackProcState(procState, mAdjSeq, now); trackedProcState = true; } + } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0 + && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ + && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) { + newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1; } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ && adj > ProcessList.PERCEPTIBLE_APP_ADJ) { @@ -19044,6 +19061,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Must be called before updating setProcState maybeUpdateUsageStatsLocked(app, nowElapsed); + maybeUpdateLastTopTime(app, now); + app.setProcState = app.curProcState; if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { app.notCachedSinceIdle = false; @@ -19268,6 +19287,13 @@ public class ActivityManagerService extends IActivityManager.Stub } } + private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) { + if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP + && app.curProcState > ActivityManager.PROCESS_STATE_TOP) { + app.lastTopTime = nowUptime; + } + } + private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) { if (proc.thread != null && proc.baseProcessTracker != null) { proc.baseProcessTracker.setState( diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 784d62e51966..3ac7885eba37 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -104,6 +104,11 @@ public final class ProcessList { static final int VISIBLE_APP_ADJ = 100; static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1; + // This is a process that was recently TOP and moved to FGS. Continue to treat it almost + // like a foreground app for a while. + // @see TOP_TO_FGS_GRACE_PERIOD + static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50; + // This is the process running the current foreground app. We'd really // rather not kill it! static final int FOREGROUND_APP_ADJ = 0; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 144f18b219dc..d3dc0f34cbf1 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -198,6 +198,7 @@ final class ProcessRecord implements WindowProcessListener { long lastRequestedGc; // When we last asked the app to do a gc long lastLowMemory; // When we last told the app that memory is low long lastProviderTime; // The last time someone else was using a provider in this process. + long lastTopTime; // The last time the process was in the TOP state or greater. boolean reportLowMemory; // Set to true when waiting to report low mem boolean empty; // Is this an empty background process? boolean cached; // Is this a cached process? @@ -415,6 +416,11 @@ final class ProcessRecord implements WindowProcessListener { TimeUtils.formatDuration(lastProviderTime, nowUptime, pw); pw.println(); } + if (lastTopTime > 0) { + pw.print(prefix); pw.print("lastTopTime="); + TimeUtils.formatDuration(lastTopTime, nowUptime, pw); + pw.println(); + } if (hasStartedServices) { pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices); } diff --git a/services/core/java/com/android/server/biometrics/BiometricPromptService.java b/services/core/java/com/android/server/biometrics/BiometricPromptService.java index 29eda8ba126e..d1371d1e0bf5 100644 --- a/services/core/java/com/android/server/biometrics/BiometricPromptService.java +++ b/services/core/java/com/android/server/biometrics/BiometricPromptService.java @@ -41,7 +41,6 @@ import android.os.UserHandle; import android.util.Slog; import com.android.internal.R; -import com.android.internal.os.SomeArgs; import com.android.server.SystemService; import java.util.ArrayList; @@ -133,6 +132,12 @@ public class BiometricPromptService extends SystemService { // AppOps and foreground check. checkPermission(); + if (token == null || receiver == null || opPackageName == null || bundle == null + || dialogReceiver == null) { + Slog.e(TAG, "Unable to authenticate, one or more null arguments"); + return; + } + final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); @@ -166,6 +171,11 @@ public class BiometricPromptService extends SystemService { throws RemoteException { checkPermission(); + if (token == null || opPackageName == null) { + Slog.e(TAG, "Unable to cancel, one or more null arguments"); + return; + } + final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 44fb9ea91dee..b2287acc635a 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -130,10 +130,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; -import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController; -import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; -import com.android.internal.inputmethod.InputMethodUtils; -import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.HandlerCaller; @@ -153,6 +149,8 @@ import com.android.internal.view.InputMethodClient; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; +import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings; import com.android.server.statusbar.StatusBarManagerService; import com.android.server.wm.WindowManagerInternal; diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java index 14ac2f6cfe31..77b2fee82dc8 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.inputmethod; +package com.android.server.inputmethod; import android.annotation.Nullable; import android.content.Context; @@ -27,7 +27,7 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings; +import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings; import java.util.ArrayList; import java.util.Collections; @@ -41,13 +41,11 @@ import java.util.TreeMap; /** * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes. - * <p> - * This class is designed to be used from and only from - * {@link com.android.server.InputMethodManagerService} by using - * {@link com.android.server.InputMethodManagerService#mMethodMap} as a global lock. - * </p> + * + * <p>This class is designed to be used from and only from {@link InputMethodManagerService} by + * using {@link InputMethodManagerService#mMethodMap} as a global lock.</p> */ -public class InputMethodSubtypeSwitchingController { +final class InputMethodSubtypeSwitchingController { private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName(); private static final boolean DEBUG = false; private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID; diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java index 1e5b5c80f31b..e951b27e85c6 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.inputmethod; +package com.android.server.inputmethod; import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR; import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS; @@ -53,10 +53,14 @@ import java.util.List; import java.util.Locale; /** - * InputMethodManagerUtils contains some static methods that provides IME informations. - * This methods are supposed to be used in both the framework and the Settings application. + * This class provides random static utility methods for {@link InputMethodManagerService} and its + * utility classes. + * + * <p>This class is intentionally package-private. Utility methods here are tightly coupled with + * implementation details in {@link InputMethodManagerService}. Hence this class is not suitable + * for other components to directly use.</p> */ -public class InputMethodUtils { +final class InputMethodUtils { public static final boolean DEBUG = false; public static final int NOT_A_SUBTYPE_ID = -1; public static final String SUBTYPE_MODE_ANY = null; @@ -334,32 +338,6 @@ public class InputMethodUtils { return getDefaultEnabledImes(context, imis, false /* onlyMinimum */); } - public static Locale constructLocaleFromString(String localeStr) { - if (TextUtils.isEmpty(localeStr)) { - return null; - } - // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. - String[] localeParams = localeStr.split("_", 3); - if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { - // Convert a locale whose language is "tl" to one whose language is "fil". - // For example, "tl_PH" will get converted to "fil_PH". - // Versions of Android earlier than Lollipop did not support three letter language - // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). - // On Lollipop and above, the current three letter version must be used. - localeParams[0] = "fil"; - } - // The length of localeStr is guaranteed to always return a 1 <= value <= 3 - // because localeStr is not empty. - if (localeParams.length == 1) { - return new Locale(localeParams[0]); - } else if (localeParams.length == 2) { - return new Locale(localeParams[0], localeParams[1]); - } else if (localeParams.length == 3) { - return new Locale(localeParams[0], localeParams[1], localeParams[2]); - } - return null; - } - public static boolean containsSubtypeOf(final InputMethodInfo imi, @Nullable final Locale locale, final boolean checkCountry, final String mode) { if (locale == null) { @@ -1320,133 +1298,6 @@ public class InputMethodUtils { } } - // For spell checker service manager. - // TODO: Should we have TextServicesUtils.java? - private static final Locale LOCALE_EN_US = new Locale("en", "US"); - private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); - - /** - * Returns a list of {@link Locale} in the order of appropriateness for the default spell - * checker service. - * - * <p>If the system language is English, and the region is also explicitly specified in the - * system locale, the following fallback order will be applied.</p> - * <ul> - * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> - * <li>(system-locale-language, system-locale-region)</li> - * <li>("en", "US")</li> - * <li>("en", "GB")</li> - * <li>("en")</li> - * </ul> - * - * <p>If the system language is English, but no region is specified in the system locale, - * the following fallback order will be applied.</p> - * <ul> - * <li>("en")</li> - * <li>("en", "US")</li> - * <li>("en", "GB")</li> - * </ul> - * - * <p>If the system language is not English, the following fallback order will be applied.</p> - * <ul> - * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> - * <li>(system-locale-language, system-locale-region) (if exists)</li> - * <li>(system-locale-language) (if exists)</li> - * <li>("en", "US")</li> - * <li>("en", "GB")</li> - * <li>("en")</li> - * </ul> - * - * @param systemLocale the current system locale to be taken into consideration. - * @return a list of {@link Locale}. The first one is considered to be most appropriate. - */ - @VisibleForTesting - public static ArrayList<Locale> getSuitableLocalesForSpellChecker( - @Nullable final Locale systemLocale) { - final Locale systemLocaleLanguageCountryVariant; - final Locale systemLocaleLanguageCountry; - final Locale systemLocaleLanguage; - if (systemLocale != null) { - final String language = systemLocale.getLanguage(); - final boolean hasLanguage = !TextUtils.isEmpty(language); - final String country = systemLocale.getCountry(); - final boolean hasCountry = !TextUtils.isEmpty(country); - final String variant = systemLocale.getVariant(); - final boolean hasVariant = !TextUtils.isEmpty(variant); - if (hasLanguage && hasCountry && hasVariant) { - systemLocaleLanguageCountryVariant = new Locale(language, country, variant); - } else { - systemLocaleLanguageCountryVariant = null; - } - if (hasLanguage && hasCountry) { - systemLocaleLanguageCountry = new Locale(language, country); - } else { - systemLocaleLanguageCountry = null; - } - if (hasLanguage) { - systemLocaleLanguage = new Locale(language); - } else { - systemLocaleLanguage = null; - } - } else { - systemLocaleLanguageCountryVariant = null; - systemLocaleLanguageCountry = null; - systemLocaleLanguage = null; - } - - final ArrayList<Locale> locales = new ArrayList<>(); - if (systemLocaleLanguageCountryVariant != null) { - locales.add(systemLocaleLanguageCountryVariant); - } - - if (Locale.ENGLISH.equals(systemLocaleLanguage)) { - if (systemLocaleLanguageCountry != null) { - // If the system language is English, and the region is also explicitly specified, - // following fallback order will be applied. - // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] - // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] - // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] - // - en - if (systemLocaleLanguageCountry != null) { - locales.add(systemLocaleLanguageCountry); - } - if (!LOCALE_EN_US.equals(systemLocaleLanguageCountry)) { - locales.add(LOCALE_EN_US); - } - if (!LOCALE_EN_GB.equals(systemLocaleLanguageCountry)) { - locales.add(LOCALE_EN_GB); - } - locales.add(Locale.ENGLISH); - } else { - // If the system language is English, but no region is specified, following - // fallback order will be applied. - // - en - // - en_US - // - en_GB - locales.add(Locale.ENGLISH); - locales.add(LOCALE_EN_US); - locales.add(LOCALE_EN_GB); - } - } else { - // If the system language is not English, the fallback order will be - // - systemLocaleLanguageCountry [if non-null] - // - systemLocaleLanguage [if non-null] - // - en_US - // - en_GB - // - en - if (systemLocaleLanguageCountry != null) { - locales.add(systemLocaleLanguageCountry); - } - if (systemLocaleLanguage != null) { - locales.add(systemLocaleLanguage); - } - locales.add(LOCALE_EN_US); - locales.add(LOCALE_EN_GB); - locales.add(Locale.ENGLISH); - } - return locales; - } - public static boolean isSoftInputModeStateVisibleAllowed( int targetSdkVersion, int controlFlags) { if (targetSdkVersion < Build.VERSION_CODES.P) { diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/services/core/java/com/android/server/inputmethod/LocaleUtils.java index eeb3854bcc55..4958eceb4fb5 100644 --- a/core/java/com/android/internal/inputmethod/LocaleUtils.java +++ b/services/core/java/com/android/server/inputmethod/LocaleUtils.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package com.android.internal.inputmethod; - -import com.android.internal.annotations.VisibleForTesting; +package com.android.server.inputmethod; import android.annotation.IntRange; import android.annotation.NonNull; @@ -31,9 +29,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; -public final class LocaleUtils { - - @VisibleForTesting +final class LocaleUtils { public interface LocaleExtractor<T> { @Nullable Locale get(@Nullable T source); @@ -149,7 +145,6 @@ public final class LocaleUtils { * @param dest Destination into which the filtered items will be added. * @param <T> Type of the data items. */ - @VisibleForTesting public static <T> void filterByLanguage( @NonNull List<T> sources, @NonNull LocaleExtractor<T> extractor, diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 7751f5f9bcb8..050a075dd993 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -178,6 +178,10 @@ abstract public class ManagedServices { } } + protected int getBindFlags() { + return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT; + } + protected void onServiceRemovedLocked(ManagedServiceInfo removed) { } private ManagedServiceInfo newServiceInfo(IInterface service, @@ -1064,9 +1068,9 @@ abstract public class ManagedServices { } }; if (!mContext.bindServiceAsUser(intent, - serviceConnection, - BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT, - new UserHandle(userid))) { + serviceConnection, + getBindFlags(), + new UserHandle(userid))) { mServicesBound.remove(servicesBindingTag); Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent); return; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6e4d9e03f28f..2e2a3c1750d3 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -33,6 +33,10 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static android.content.Context.BIND_ADJUST_BELOW_PERCEPTIBLE; +import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; +import static android.content.Context.BIND_AUTO_CREATE; +import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; @@ -4084,25 +4088,30 @@ public class NotificationManagerService extends SystemService { public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, int userId) { checkCallerIsSystem(); - mHandler.post(new Runnable() { - @Override - public void run() { - synchronized (mNotificationLock) { - removeForegroundServiceFlagByListLocked( - mEnqueuedNotifications, pkg, notificationId, userId); - removeForegroundServiceFlagByListLocked( - mNotificationList, pkg, notificationId, userId); + mHandler.post(() -> { + synchronized (mNotificationLock) { + // strip flag from all enqueued notifications. listeners will be informed + // in post runnable. + List<NotificationRecord> enqueued = findNotificationsByListLocked( + mEnqueuedNotifications, pkg, null, notificationId, userId); + for (int i = 0; i < enqueued.size(); i++) { + removeForegroundServiceFlagLocked(enqueued.get(i)); + } + + // if posted notification exists, strip its flag and tell listeners + NotificationRecord r = findNotificationByListLocked( + mNotificationList, pkg, null, notificationId, userId); + if (r != null) { + removeForegroundServiceFlagLocked(r); + mRankingHelper.sort(mNotificationList); + mListeners.notifyPostedLocked(r, r); } } }); } @GuardedBy("mNotificationLock") - private void removeForegroundServiceFlagByListLocked( - ArrayList<NotificationRecord> notificationList, String pkg, int notificationId, - int userId) { - NotificationRecord r = findNotificationByListLocked( - notificationList, pkg, null, notificationId, userId); + private void removeForegroundServiceFlagLocked(NotificationRecord r) { if (r == null) { return; } @@ -4113,8 +4122,6 @@ public class NotificationManagerService extends SystemService { // initially *and* force remove FLAG_FOREGROUND_SERVICE. sbn.getNotification().flags = (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE); - mRankingHelper.sort(mNotificationList); - mListeners.notifyPostedLocked(r, r); } }; @@ -6267,6 +6274,21 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") + private List<NotificationRecord> findNotificationsByListLocked( + ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) { + List<NotificationRecord> matching = new ArrayList<>(); + final int len = list.size(); + for (int i = 0; i < len; i++) { + NotificationRecord r = list.get(i); + if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && + TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { + matching.add(r); + } + } + return matching; + } + + @GuardedBy("mNotificationLock") private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list, String key) { final int N = list.size(); @@ -6800,6 +6822,16 @@ public class NotificationManagerService extends SystemService { } @Override + protected int getBindFlags() { + // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE + // because too many 3P apps could be kept in memory as notification listeners and + // cause extreme memory pressure. + // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation. + return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE + | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT; + } + + @Override protected Config getConfig() { Config c = new Config(); c.caption = "notification listener"; diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index 560ca92f494d..5bf323ac2239 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -378,7 +378,7 @@ public class ComponentResolver { for (int i = newIntents.size() - 1; i >= 0; --i) { final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i); final PackageParser.Package disabledPkg = sPackageManagerInternal - .getDisabledPackage(intentInfo.activity.info.packageName); + .getDisabledSystemPackage(intentInfo.activity.info.packageName); final List<PackageParser.Activity> systemActivities = disabledPkg != null ? disabledPkg.activities : null; adjustPriority(systemActivities, intentInfo, setupWizardPackage); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index db0c13cbf7d2..91af0eca8707 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -718,6 +718,8 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mPackages") final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>(); + private PackageManager mPackageManager; + class PackageParserCallback implements PackageParser.Callback { @Override public final boolean hasFeature(String feature) { return PackageManagerService.this.hasSystemFeature(feature, 0); @@ -22236,6 +22238,22 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public boolean isPlatformSigned(String packageName) { + PackageSetting packageSetting = mSettings.mPackages.get(packageName); + if (packageSetting == null) { + return false; + } + PackageParser.Package pkg = packageSetting.pkg; + if (pkg == null) { + // May happen if package in on a removable sd card + return false; + } + return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails) + || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails, + PackageParser.SigningDetails.CertCapabilities.PERMISSION); + } + + @Override public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) { SigningDetails sd = getSigningDetails(packageName); if (sd == null) { @@ -22347,7 +22365,7 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public PackageParser.Package getDisabledPackage(String packageName) { + public PackageParser.Package getDisabledSystemPackage(String packageName) { synchronized (mPackages) { final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); return (ps != null) ? ps.pkg : null; @@ -22355,6 +22373,12 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) { + PackageParser.Package pkg = getDisabledSystemPackage(packageName); + return pkg == null ? null : pkg.packageName; + } + + @Override public String getKnownPackageName(int knownPackage, int userId) { switch(knownPackage) { case PackageManagerInternal.PACKAGE_BROWSER: @@ -22392,21 +22416,6 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void setSmsAppPackagesProvider(PackagesProvider provider) { - mDefaultPermissionPolicy.setSmsAppPackagesProvider(provider); - } - - @Override - public void setDialerAppPackagesProvider(PackagesProvider provider) { - mDefaultPermissionPolicy.setDialerAppPackagesProvider(provider); - } - - @Override - public void setSimCallManagerPackagesProvider(PackagesProvider provider) { - mDefaultPermissionPolicy.setSimCallManagerPackagesProvider(provider); - } - - @Override public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) { mDefaultPermissionPolicy.setUseOpenWifiAppPackagesProvider(provider); } @@ -22417,22 +22426,10 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) { - mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSmsApp(packageName, userId); - } - - @Override - public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) { + public void onDefaultDialerAppChanged(String packageName, int userId) { synchronized (mPackages) { mSettings.setDefaultDialerPackageNameLPw(packageName, userId); } - mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerApp(packageName, userId); - } - - @Override - public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) { - mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSimCallManager( - packageName, userId); } @Override diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 846c7b7a7e0c..d9eb7e8d729c 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -23,12 +23,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.DownloadManager; +import android.app.SearchManager; import android.app.admin.DevicePolicyManager; import android.companion.CompanionDeviceManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageList; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackagesProvider; @@ -53,6 +54,7 @@ import android.provider.ContactsContract; import android.provider.MediaStore; import android.provider.Telephony.Sms.Intents; import android.security.Credentials; +import android.speech.RecognitionService; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; @@ -61,6 +63,7 @@ import android.util.Log; import android.util.Slog; import android.util.Xml; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; import com.android.server.LocalServices; @@ -73,6 +76,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -94,10 +98,15 @@ public final class DefaultPermissionGrantPolicy { private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars private static final boolean DEBUG = false; - private static final int DEFAULT_FLAGS = + @PackageManager.ResolveInfoFlags + private static final int DEFAULT_INTENT_QUERY_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_UNINSTALLED_PACKAGES; + @PackageManager.PackageInfoFlags + private static final int DEFAULT_PACKAGE_INFO_QUERY_FLAGS = + PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS; + private static final String AUDIO_MIME_TYPE = "audio/mpeg"; private static final String TAG_EXCEPTIONS = "exceptions"; @@ -108,6 +117,8 @@ public final class DefaultPermissionGrantPolicy { private static final String ATTR_FIXED = "fixed"; private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>(); + + static { PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE); PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE); @@ -219,7 +230,7 @@ public final class DefaultPermissionGrantPolicy { private final DefaultPermissionGrantedCallback mPermissionGrantedCallback; public interface DefaultPermissionGrantedCallback { /** Callback when permissions have been granted */ - public void onDefaultRuntimePermissionsGranted(int userId); + void onDefaultRuntimePermissionsGranted(int userId); } public DefaultPermissionGrantPolicy(Context context, Looper looper, @@ -291,9 +302,9 @@ public final class DefaultPermissionGrantPolicy { grantDefaultPermissionExceptions(userId); } - private void grantRuntimePermissionsForPackage(int userId, PackageParser.Package pkg) { + private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) { Set<String> permissions = new ArraySet<>(); - for (String permission : pkg.requestedPermissions) { + for (String permission : pkg.requestedPermissions) { final BasePermission bp = mPermissionManager.getPermission(permission); if (bp == null) { continue; @@ -307,36 +318,71 @@ public final class DefaultPermissionGrantPolicy { } } - private void grantAllRuntimePermissions(int userId) { - Log.i(TAG, "Granting all runtime permissions for user " + userId); - final PackageList packageList = mServiceInternal.getPackageList(); - for (String packageName : packageList.getPackageNames()) { - final PackageParser.Package pkg = mServiceInternal.getPackage(packageName); - if (pkg == null) { - continue; - } - grantRuntimePermissionsForPackage(userId, pkg); - } - } - public void scheduleReadDefaultPermissionExceptions() { mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS); } private void grantPermissionsToSysComponentsAndPrivApps(int userId) { Log.i(TAG, "Granting permissions to platform components for user " + userId); - final PackageList packageList = mServiceInternal.getPackageList(); - for (String packageName : packageList.getPackageNames()) { - final PackageParser.Package pkg = mServiceInternal.getPackage(packageName); + List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser( + DEFAULT_PACKAGE_INFO_QUERY_FLAGS, UserHandle.USER_SYSTEM); + for (PackageInfo pkg : packages) { if (pkg == null) { continue; } if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg) || !doesPackageSupportRuntimePermissions(pkg) - || pkg.requestedPermissions.isEmpty()) { + || ArrayUtils.isEmpty(pkg.requestedPermissions)) { continue; } - grantRuntimePermissionsForPackage(userId, pkg); + grantRuntimePermissionsForSystemPackage(userId, pkg); + } + } + + @SafeVarargs + private final void grantIgnoringSystemPackage(String packageName, int userId, + Set<String>... permissionGroups) { + grantPermissionsToSystemPackage(packageName, userId, false, true, permissionGroups); + } + + @SafeVarargs + private final void grantSystemFixedPermissionsToSystemPackage(String packageName, int userId, + Set<String>... permissionGroups) { + grantPermissionsToSystemPackage(packageName, userId, true, false, permissionGroups); + } + + @SafeVarargs + private final void grantPermissionsToSystemPackage( + String packageName, int userId, Set<String>... permissionGroups) { + grantPermissionsToSystemPackage(packageName, userId, false, false, permissionGroups); + } + + @SafeVarargs + private final void grantPermissionsToSystemPackage(String packageName, int userId, + boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) { + if (!ignoreSystemPackage && !isSystemPackage(packageName)) { + return; + } + grantRuntimePermissionsToPackage(getSystemPackageInfo(packageName), + userId, systemFixed, ignoreSystemPackage, permissionGroups); + } + + @SafeVarargs + private final void grantRuntimePermissionsToPackage(String packageName, int userId, + boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) { + grantRuntimePermissionsToPackage(getPackageInfo(packageName), + userId, systemFixed, ignoreSystemPackage, permissionGroups); + } + + @SafeVarargs + private final void grantRuntimePermissionsToPackage(PackageInfo packageName, int userId, + boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) { + if (packageName == null) return; + if (doesPackageSupportRuntimePermissions(packageName)) { + for (Set<String> permissionGroup : permissionGroups) { + grantRuntimePermissions(packageName, permissionGroup, systemFixed, + ignoreSystemPackage, userId); + } } } @@ -379,594 +425,373 @@ public final class DefaultPermissionGrantPolicy { syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null; // Installer - final String installerPackageName = mServiceInternal.getKnownPackageName( - PackageManagerInternal.PACKAGE_INSTALLER, userId); - PackageParser.Package installerPackage = getSystemPackage(installerPackageName); - if (installerPackage != null - && doesPackageSupportRuntimePermissions(installerPackage)) { - grantRuntimePermissions(installerPackage, STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getKnownPackage(PackageManagerInternal.PACKAGE_INSTALLER, userId), + userId, STORAGE_PERMISSIONS); // Verifier - final String verifierPackageName = mServiceInternal.getKnownPackageName( - PackageManagerInternal.PACKAGE_VERIFIER, userId); - PackageParser.Package verifierPackage = getSystemPackage(verifierPackageName); - if (verifierPackage != null - && doesPackageSupportRuntimePermissions(verifierPackage)) { - grantRuntimePermissions(verifierPackage, STORAGE_PERMISSIONS, true, userId); - grantRuntimePermissions(verifierPackage, PHONE_PERMISSIONS, false, userId); - grantRuntimePermissions(verifierPackage, SMS_PERMISSIONS, false, userId); - } + final String verifier = getKnownPackage(PackageManagerInternal.PACKAGE_VERIFIER, userId); + grantSystemFixedPermissionsToSystemPackage(verifier, userId, STORAGE_PERMISSIONS); + grantPermissionsToSystemPackage(verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS); // SetupWizard - final String setupWizardPackageName = mServiceInternal.getKnownPackageName( - PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId); - PackageParser.Package setupPackage = getSystemPackage(setupWizardPackageName); - if (setupPackage != null - && doesPackageSupportRuntimePermissions(setupPackage)) { - grantRuntimePermissions(setupPackage, PHONE_PERMISSIONS, userId); - grantRuntimePermissions(setupPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(setupPackage, LOCATION_PERMISSIONS, userId); - grantRuntimePermissions(setupPackage, CAMERA_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getKnownPackage(PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId), userId, + PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, LOCATION_PERMISSIONS, CAMERA_PERMISSIONS); // Camera - Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - PackageParser.Package cameraPackage = getDefaultSystemHandlerActivityPackage( - cameraIntent, userId); - if (cameraPackage != null - && doesPackageSupportRuntimePermissions(cameraPackage)) { - grantRuntimePermissions(cameraPackage, CAMERA_PERMISSIONS, userId); - grantRuntimePermissions(cameraPackage, MICROPHONE_PERMISSIONS, userId); - grantRuntimePermissions(cameraPackage, STORAGE_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage(MediaStore.ACTION_IMAGE_CAPTURE, userId), + userId, CAMERA_PERMISSIONS, MICROPHONE_PERMISSIONS, STORAGE_PERMISSIONS); // Media provider - PackageParser.Package mediaStorePackage = getDefaultProviderAuthorityPackage( - MediaStore.AUTHORITY, userId); - if (mediaStorePackage != null) { - grantRuntimePermissions(mediaStorePackage, STORAGE_PERMISSIONS, true, userId); - grantRuntimePermissions(mediaStorePackage, MEDIA_AURAL_PERMISSIONS, true, userId); - grantRuntimePermissions(mediaStorePackage, MEDIA_VISUAL_PERMISSIONS, true, userId); - grantRuntimePermissions(mediaStorePackage, PHONE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultProviderAuthorityPackage(MediaStore.AUTHORITY, userId), userId, + STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS, + PHONE_PERMISSIONS); // Downloads provider - PackageParser.Package downloadsPackage = getDefaultProviderAuthorityPackage( - "downloads", userId); - if (downloadsPackage != null) { - grantRuntimePermissions(downloadsPackage, STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultProviderAuthorityPackage("downloads", userId), userId, + STORAGE_PERMISSIONS); // Downloads UI - Intent downloadsUiIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS); - PackageParser.Package downloadsUiPackage = getDefaultSystemHandlerActivityPackage( - downloadsUiIntent, userId); - if (downloadsUiPackage != null - && doesPackageSupportRuntimePermissions(downloadsUiPackage)) { - grantRuntimePermissions(downloadsUiPackage, STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage( + DownloadManager.ACTION_VIEW_DOWNLOADS, userId), + userId, STORAGE_PERMISSIONS); // Storage provider - PackageParser.Package storagePackage = getDefaultProviderAuthorityPackage( - "com.android.externalstorage.documents", userId); - if (storagePackage != null) { - grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultProviderAuthorityPackage("com.android.externalstorage.documents", userId), + userId, STORAGE_PERMISSIONS); // CertInstaller - Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION); - PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage( - certInstallerIntent, userId); - if (certInstallerPackage != null - && doesPackageSupportRuntimePermissions(certInstallerPackage)) { - grantRuntimePermissions(certInstallerPackage, STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage(Credentials.INSTALL_ACTION, userId), userId, + STORAGE_PERMISSIONS); // Dialer if (dialerAppPackageNames == null) { - Intent dialerIntent = new Intent(Intent.ACTION_DIAL); - PackageParser.Package dialerPackage = getDefaultSystemHandlerActivityPackage( - dialerIntent, userId); - if (dialerPackage != null) { - grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId); - } + String dialerPackage = + getDefaultSystemHandlerActivityPackage(Intent.ACTION_DIAL, userId); + grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId); } else { for (String dialerAppPackageName : dialerAppPackageNames) { - PackageParser.Package dialerPackage = getSystemPackage(dialerAppPackageName); - if (dialerPackage != null) { - grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId); - } + grantDefaultPermissionsToDefaultSystemDialerApp(dialerAppPackageName, userId); } } // Sim call manager if (simCallManagerPackageNames != null) { for (String simCallManagerPackageName : simCallManagerPackageNames) { - PackageParser.Package simCallManagerPackage = - getSystemPackage(simCallManagerPackageName); - if (simCallManagerPackage != null) { - grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage, - userId); - } + grantDefaultPermissionsToDefaultSystemSimCallManager( + simCallManagerPackageName, userId); } } // Use Open Wifi if (useOpenWifiAppPackageNames != null) { for (String useOpenWifiPackageName : useOpenWifiAppPackageNames) { - PackageParser.Package useOpenWifiPackage = - getSystemPackage(useOpenWifiPackageName); - if (useOpenWifiPackage != null) { - grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(useOpenWifiPackage, - userId); - } + grantDefaultPermissionsToDefaultSystemUseOpenWifiApp( + useOpenWifiPackageName, userId); } } // SMS if (smsAppPackageNames == null) { - Intent smsIntent = new Intent(Intent.ACTION_MAIN); - smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING); - PackageParser.Package smsPackage = getDefaultSystemHandlerActivityPackage( - smsIntent, userId); - if (smsPackage != null) { - grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId); - } + String smsPackage = getDefaultSystemHandlerActivityPackageForCategory( + Intent.CATEGORY_APP_MESSAGING, userId); + grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId); } else { - for (String smsPackageName : smsAppPackageNames) { - PackageParser.Package smsPackage = getSystemPackage(smsPackageName); - if (smsPackage != null) { - grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId); - } + for (String smsPackage : smsAppPackageNames) { + grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId); } } // Cell Broadcast Receiver - Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION); - PackageParser.Package cbrPackage = - getDefaultSystemHandlerActivityPackage(cbrIntent, userId); - if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) { - grantRuntimePermissions(cbrPackage, SMS_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage(Intents.SMS_CB_RECEIVED_ACTION, userId), + userId, SMS_PERMISSIONS); // Carrier Provisioning Service - Intent carrierProvIntent = new Intent(Intents.SMS_CARRIER_PROVISION_ACTION); - PackageParser.Package carrierProvPackage = - getDefaultSystemHandlerServicePackage(carrierProvIntent, userId); - if (carrierProvPackage != null - && doesPackageSupportRuntimePermissions(carrierProvPackage)) { - grantRuntimePermissions(carrierProvPackage, SMS_PERMISSIONS, false, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerServicePackage(Intents.SMS_CARRIER_PROVISION_ACTION, userId), + userId, SMS_PERMISSIONS); // Calendar - Intent calendarIntent = new Intent(Intent.ACTION_MAIN); - calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR); - PackageParser.Package calendarPackage = getDefaultSystemHandlerActivityPackage( - calendarIntent, userId); - if (calendarPackage != null - && doesPackageSupportRuntimePermissions(calendarPackage)) { - grantRuntimePermissions(calendarPackage, CALENDAR_PERMISSIONS, userId); - grantRuntimePermissions(calendarPackage, CONTACTS_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackageForCategory( + Intent.CATEGORY_APP_CALENDAR, userId), + userId, CALENDAR_PERMISSIONS, CONTACTS_PERMISSIONS); // Calendar provider - PackageParser.Package calendarProviderPackage = getDefaultProviderAuthorityPackage( - CalendarContract.AUTHORITY, userId); - if (calendarProviderPackage != null) { - grantRuntimePermissions(calendarProviderPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(calendarProviderPackage, CALENDAR_PERMISSIONS, - true, userId); - grantRuntimePermissions(calendarProviderPackage, STORAGE_PERMISSIONS, userId); - } + String calendarProvider = + getDefaultProviderAuthorityPackage(CalendarContract.AUTHORITY, userId); + grantPermissionsToSystemPackage(calendarProvider, userId, + CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS); + grantSystemFixedPermissionsToSystemPackage(calendarProvider, userId, CALENDAR_PERMISSIONS); // Calendar provider sync adapters - List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackages( - calendarSyncAdapterPackages, userId); - final int calendarSyncAdapterCount = calendarSyncAdapters.size(); - for (int i = 0; i < calendarSyncAdapterCount; i++) { - PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i); - if (doesPackageSupportRuntimePermissions(calendarSyncAdapter)) { - grantRuntimePermissions(calendarSyncAdapter, CALENDAR_PERMISSIONS, userId); - } - } + grantPermissionToEachSystemPackage( + getHeadlessSyncAdapterPackages(calendarSyncAdapterPackages, userId), + userId, CALENDAR_PERMISSIONS); // Contacts - Intent contactsIntent = new Intent(Intent.ACTION_MAIN); - contactsIntent.addCategory(Intent.CATEGORY_APP_CONTACTS); - PackageParser.Package contactsPackage = getDefaultSystemHandlerActivityPackage( - contactsIntent, userId); - if (contactsPackage != null - && doesPackageSupportRuntimePermissions(contactsPackage)) { - grantRuntimePermissions(contactsPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(contactsPackage, PHONE_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackageForCategory( + Intent.CATEGORY_APP_CONTACTS, userId), + userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS); // Contacts provider sync adapters - List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackages( - contactsSyncAdapterPackages, userId); - final int contactsSyncAdapterCount = contactsSyncAdapters.size(); - for (int i = 0; i < contactsSyncAdapterCount; i++) { - PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i); - if (doesPackageSupportRuntimePermissions(contactsSyncAdapter)) { - grantRuntimePermissions(contactsSyncAdapter, CONTACTS_PERMISSIONS, userId); - } - } + grantPermissionToEachSystemPackage( + getHeadlessSyncAdapterPackages(contactsSyncAdapterPackages, userId), + userId, CONTACTS_PERMISSIONS); // Contacts provider - PackageParser.Package contactsProviderPackage = getDefaultProviderAuthorityPackage( - ContactsContract.AUTHORITY, userId); - if (contactsProviderPackage != null) { - grantRuntimePermissions(contactsProviderPackage, CONTACTS_PERMISSIONS, - true, userId); - grantRuntimePermissions(contactsProviderPackage, PHONE_PERMISSIONS, - true, userId); - grantRuntimePermissions(contactsProviderPackage, STORAGE_PERMISSIONS, userId); - } + String contactsProviderPackage = + getDefaultProviderAuthorityPackage(ContactsContract.AUTHORITY, userId); + grantSystemFixedPermissionsToSystemPackage(contactsProviderPackage, userId, + CONTACTS_PERMISSIONS, PHONE_PERMISSIONS); + grantPermissionsToSystemPackage(contactsProviderPackage, userId, STORAGE_PERMISSIONS); // Device provisioning - Intent deviceProvisionIntent = new Intent( - DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE); - PackageParser.Package deviceProvisionPackage = - getDefaultSystemHandlerActivityPackage(deviceProvisionIntent, userId); - if (deviceProvisionPackage != null - && doesPackageSupportRuntimePermissions(deviceProvisionPackage)) { - grantRuntimePermissions(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage( + DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId), + userId, CONTACTS_PERMISSIONS); // Maps - Intent mapsIntent = new Intent(Intent.ACTION_MAIN); - mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS); - PackageParser.Package mapsPackage = getDefaultSystemHandlerActivityPackage( - mapsIntent, userId); - if (mapsPackage != null - && doesPackageSupportRuntimePermissions(mapsPackage)) { - grantRuntimePermissions(mapsPackage, LOCATION_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId), + userId, LOCATION_PERMISSIONS); // Gallery - Intent galleryIntent = new Intent(Intent.ACTION_MAIN); - galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY); - PackageParser.Package galleryPackage = getDefaultSystemHandlerActivityPackage( - galleryIntent, userId); - if (galleryPackage != null - && doesPackageSupportRuntimePermissions(galleryPackage)) { - grantRuntimePermissions(galleryPackage, STORAGE_PERMISSIONS, userId); - grantRuntimePermissions(galleryPackage, MEDIA_VISUAL_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackageForCategory( + Intent.CATEGORY_APP_GALLERY, userId), + userId, STORAGE_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS); // Email - Intent emailIntent = new Intent(Intent.ACTION_MAIN); - emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL); - PackageParser.Package emailPackage = getDefaultSystemHandlerActivityPackage( - emailIntent, userId); - if (emailPackage != null - && doesPackageSupportRuntimePermissions(emailPackage)) { - grantRuntimePermissions(emailPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(emailPackage, CALENDAR_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackageForCategory( + Intent.CATEGORY_APP_EMAIL, userId), + userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS); // Browser - PackageParser.Package browserPackage = null; - String defaultBrowserPackage = mServiceInternal.getKnownPackageName( - PackageManagerInternal.PACKAGE_BROWSER, userId); - if (defaultBrowserPackage != null) { - browserPackage = getPackage(defaultBrowserPackage); - } + String browserPackage = getKnownPackage(PackageManagerInternal.PACKAGE_BROWSER, userId); if (browserPackage == null) { - Intent browserIntent = new Intent(Intent.ACTION_MAIN); - browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER); - browserPackage = getDefaultSystemHandlerActivityPackage( - browserIntent, userId); - } - if (browserPackage != null - && doesPackageSupportRuntimePermissions(browserPackage)) { - grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, userId); + browserPackage = getDefaultSystemHandlerActivityPackageForCategory( + Intent.CATEGORY_APP_BROWSER, userId); + if (!isSystemPackage(browserPackage)) { + browserPackage = null; + } } + grantRuntimePermissionsToPackage(browserPackage, userId, + false /* systemFixed */, false /* ignoreSystemPackage */, + LOCATION_PERMISSIONS); // Voice interaction if (voiceInteractPackageNames != null) { for (String voiceInteractPackageName : voiceInteractPackageNames) { - PackageParser.Package voiceInteractPackage = getSystemPackage( - voiceInteractPackageName); - if (voiceInteractPackage != null - && doesPackageSupportRuntimePermissions(voiceInteractPackage)) { - grantRuntimePermissions(voiceInteractPackage, - CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(voiceInteractPackage, - CALENDAR_PERMISSIONS, userId); - grantRuntimePermissions(voiceInteractPackage, - MICROPHONE_PERMISSIONS, userId); - grantRuntimePermissions(voiceInteractPackage, - PHONE_PERMISSIONS, userId); - grantRuntimePermissions(voiceInteractPackage, - SMS_PERMISSIONS, userId); - grantRuntimePermissions(voiceInteractPackage, - LOCATION_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage(voiceInteractPackageName, userId, + CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS, + PHONE_PERMISSIONS, SMS_PERMISSIONS, LOCATION_PERMISSIONS); } } if (ActivityManager.isLowRamDeviceStatic()) { // Allow voice search on low-ram devices - Intent globalSearchIntent = new Intent("android.search.action.GLOBAL_SEARCH"); - PackageParser.Package globalSearchPickerPackage = - getDefaultSystemHandlerActivityPackage(globalSearchIntent, userId); - - if (globalSearchPickerPackage != null - && doesPackageSupportRuntimePermissions(globalSearchPickerPackage)) { - grantRuntimePermissions(globalSearchPickerPackage, - MICROPHONE_PERMISSIONS, false, userId); - grantRuntimePermissions(globalSearchPickerPackage, - LOCATION_PERMISSIONS, false, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage( + SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId), + userId, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS); } // Voice recognition - Intent voiceRecoIntent = new Intent("android.speech.RecognitionService"); - voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT); - PackageParser.Package voiceRecoPackage = getDefaultSystemHandlerServicePackage( - voiceRecoIntent, userId); - if (voiceRecoPackage != null - && doesPackageSupportRuntimePermissions(voiceRecoPackage)) { - grantRuntimePermissions(voiceRecoPackage, MICROPHONE_PERMISSIONS, userId); - } + Intent voiceRecoIntent = new Intent(RecognitionService.SERVICE_INTERFACE) + .addCategory(Intent.CATEGORY_DEFAULT); + grantPermissionsToSystemPackage( + getDefaultSystemHandlerServicePackage(voiceRecoIntent, userId), userId, + MICROPHONE_PERMISSIONS); // Location if (locationPackageNames != null) { for (String packageName : locationPackageNames) { - PackageParser.Package locationPackage = getSystemPackage(packageName); - if (locationPackage != null - && doesPackageSupportRuntimePermissions(locationPackage)) { - grantRuntimePermissions(locationPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(locationPackage, CALENDAR_PERMISSIONS, userId); - grantRuntimePermissions(locationPackage, MICROPHONE_PERMISSIONS, userId); - grantRuntimePermissions(locationPackage, PHONE_PERMISSIONS, userId); - grantRuntimePermissions(locationPackage, SMS_PERMISSIONS, userId); - grantRuntimePermissions(locationPackage, LOCATION_PERMISSIONS, - true, userId); - grantRuntimePermissions(locationPackage, CAMERA_PERMISSIONS, userId); - grantRuntimePermissions(locationPackage, SENSORS_PERMISSIONS, userId); - grantRuntimePermissions(locationPackage, STORAGE_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage(packageName, userId, + CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS, + PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS, + SENSORS_PERMISSIONS, STORAGE_PERMISSIONS); + grantSystemFixedPermissionsToSystemPackage(packageName, userId, + LOCATION_PERMISSIONS); } } // Music - Intent musicIntent = new Intent(Intent.ACTION_VIEW); - musicIntent.addCategory(Intent.CATEGORY_DEFAULT); - musicIntent.setDataAndType(Uri.fromFile(new File("foo.mp3")), - AUDIO_MIME_TYPE); - PackageParser.Package musicPackage = getDefaultSystemHandlerActivityPackage( - musicIntent, userId); - if (musicPackage != null - && doesPackageSupportRuntimePermissions(musicPackage)) { - grantRuntimePermissions(musicPackage, STORAGE_PERMISSIONS, userId); - grantRuntimePermissions(musicPackage, MEDIA_AURAL_PERMISSIONS, userId); - } + Intent musicIntent = new Intent(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_DEFAULT) + .setDataAndType(Uri.fromFile(new File("foo.mp3")), AUDIO_MIME_TYPE); + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage(musicIntent, userId), userId, + STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS); // Home - Intent homeIntent = new Intent(Intent.ACTION_MAIN); - homeIntent.addCategory(Intent.CATEGORY_HOME); - homeIntent.addCategory(Intent.CATEGORY_LAUNCHER_APP); - PackageParser.Package homePackage = getDefaultSystemHandlerActivityPackage( - homeIntent, userId); - if (homePackage != null - && doesPackageSupportRuntimePermissions(homePackage)) { - grantRuntimePermissions(homePackage, LOCATION_PERMISSIONS, false, userId); - } + Intent homeIntent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_HOME) + .addCategory(Intent.CATEGORY_LAUNCHER_APP); + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage(homeIntent, userId), userId, + LOCATION_PERMISSIONS); // Watches if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) { // Home application on watches - Intent wearHomeIntent = new Intent(Intent.ACTION_MAIN); - wearHomeIntent.addCategory(Intent.CATEGORY_HOME_MAIN); - - PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackage( - wearHomeIntent, userId); - - if (wearHomePackage != null - && doesPackageSupportRuntimePermissions(wearHomePackage)) { - grantRuntimePermissions(wearHomePackage, CONTACTS_PERMISSIONS, false, - userId); - grantRuntimePermissions(wearHomePackage, PHONE_PERMISSIONS, true, userId); - grantRuntimePermissions(wearHomePackage, MICROPHONE_PERMISSIONS, false, - userId); - grantRuntimePermissions(wearHomePackage, LOCATION_PERMISSIONS, false, - userId); - } + + String wearPackage = getDefaultSystemHandlerActivityPackageForCategory( + Intent.CATEGORY_HOME_MAIN, userId); + grantPermissionsToSystemPackage(wearPackage, userId, + CONTACTS_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS); + grantSystemFixedPermissionsToSystemPackage(wearPackage, userId, PHONE_PERMISSIONS); // Fitness tracking on watches - Intent trackIntent = new Intent(ACTION_TRACK); - PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackage( - trackIntent, userId); - if (trackPackage != null - && doesPackageSupportRuntimePermissions(trackPackage)) { - grantRuntimePermissions(trackPackage, SENSORS_PERMISSIONS, false, userId); - grantRuntimePermissions(trackPackage, LOCATION_PERMISSIONS, false, userId); - } + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage(ACTION_TRACK, userId), userId, + SENSORS_PERMISSIONS, LOCATION_PERMISSIONS); } // Print Spooler - PackageParser.Package printSpoolerPackage = getSystemPackage( - PrintManager.PRINT_SPOOLER_PACKAGE_NAME); - if (printSpoolerPackage != null - && doesPackageSupportRuntimePermissions(printSpoolerPackage)) { - grantRuntimePermissions(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage(PrintManager.PRINT_SPOOLER_PACKAGE_NAME, userId, + LOCATION_PERMISSIONS); // EmergencyInfo - Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE); - PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackage( - emergencyInfoIntent, userId); - if (emergencyInfoPckg != null - && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) { - grantRuntimePermissions(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId); - grantRuntimePermissions(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage( + TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId), + userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS); // NFC Tag viewer - Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW); - nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg"); - PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackage( - nfcTagIntent, userId); - if (nfcTagPkg != null - && doesPackageSupportRuntimePermissions(nfcTagPkg)) { - grantRuntimePermissions(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId); - grantRuntimePermissions(nfcTagPkg, PHONE_PERMISSIONS, false, userId); - } + Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW) + .setType("vnd.android.cursor.item/ndef_msg"); + grantPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage(nfcTagIntent, userId), userId, + CONTACTS_PERMISSIONS, PHONE_PERMISSIONS); // Storage Manager - Intent storageManagerIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE); - PackageParser.Package storageManagerPckg = getDefaultSystemHandlerActivityPackage( - storageManagerIntent, userId); - if (storageManagerPckg != null - && doesPackageSupportRuntimePermissions(storageManagerPckg)) { - grantRuntimePermissions(storageManagerPckg, STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage( + StorageManager.ACTION_MANAGE_STORAGE, userId), + userId, STORAGE_PERMISSIONS); // Companion devices - PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackage( - CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME); - if (companionDeviceDiscoveryPackage != null - && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) { - grantRuntimePermissions(companionDeviceDiscoveryPackage, - LOCATION_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, userId, + LOCATION_PERMISSIONS); // Ringtone Picker - Intent ringtonePickerIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); - PackageParser.Package ringtonePickerPackage = - getDefaultSystemHandlerActivityPackage(ringtonePickerIntent, userId); - if (ringtonePickerPackage != null - && doesPackageSupportRuntimePermissions(ringtonePickerPackage)) { - grantRuntimePermissions(ringtonePickerPackage, - STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage( + getDefaultSystemHandlerActivityPackage( + RingtoneManager.ACTION_RINGTONE_PICKER, userId), + userId, STORAGE_PERMISSIONS); // TextClassifier Service String textClassifierPackageName = mContext.getPackageManager().getSystemTextClassifierPackageName(); if (!TextUtils.isEmpty(textClassifierPackageName)) { - PackageParser.Package textClassifierPackage = - getSystemPackage(textClassifierPackageName); - if (textClassifierPackage != null - && doesPackageSupportRuntimePermissions(textClassifierPackage)) { - grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, false, userId); - grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, false, userId); - grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, false, userId); - grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, false, userId); - grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, false, userId); - } + grantPermissionsToSystemPackage(textClassifierPackageName, userId, + PHONE_PERMISSIONS, SMS_PERMISSIONS, CALENDAR_PERMISSIONS, + LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS); } // There is no real "marker" interface to identify the shared storage backup, it is // hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE. - PackageParser.Package sharedStorageBackupPackage = getSystemPackage( - "com.android.sharedstoragebackup"); - if (sharedStorageBackupPackage != null) { - grantRuntimePermissions(sharedStorageBackupPackage, STORAGE_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId, + STORAGE_PERMISSIONS); if (mPermissionGrantedCallback != null) { mPermissionGrantedCallback.onDefaultRuntimePermissionsGranted(userId); } } - private void grantDefaultPermissionsToDefaultSystemDialerApp( - PackageParser.Package dialerPackage, int userId) { - if (doesPackageSupportRuntimePermissions(dialerPackage)) { - boolean isPhonePermFixed = - mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0); - grantRuntimePermissions( - dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId); - grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, userId); - grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, userId); - grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, userId); + private String getDefaultSystemHandlerActivityPackageForCategory(String category, int userId) { + return getDefaultSystemHandlerActivityPackage( + new Intent(Intent.ACTION_MAIN).addCategory(category), userId); + } + + @SafeVarargs + private final void grantPermissionToEachSystemPackage( + ArrayList<String> packages, int userId, Set<String>... permissions) { + if (packages == null) return; + final int count = packages.size(); + for (int i = 0; i < count; i++) { + grantPermissionsToSystemPackage(packages.get(i), userId, permissions); } } - private void grantDefaultPermissionsToDefaultSystemSmsApp( - PackageParser.Package smsPackage, int userId) { - if (doesPackageSupportRuntimePermissions(smsPackage)) { - grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, userId); - grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, userId); - grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, userId); - grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, userId); - grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, userId); + private String getKnownPackage(int knownPkgId, int userId) { + return mServiceInternal.getKnownPackageName(knownPkgId, userId); + } + + private void grantDefaultPermissionsToDefaultSystemDialerApp( + String dialerPackage, int userId) { + if (dialerPackage == null) { + return; } + boolean isPhonePermFixed = + mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0); + if (isPhonePermFixed) { + grantSystemFixedPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS); + } else { + grantPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS); + } + grantPermissionsToSystemPackage(dialerPackage, userId, + CONTACTS_PERMISSIONS, SMS_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS); + } + + private void grantDefaultPermissionsToDefaultSystemSmsApp(String smsPackage, int userId) { + grantPermissionsToSystemPackage(smsPackage, userId, + PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS, + STORAGE_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS); } private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp( - PackageParser.Package useOpenWifiPackage, int userId) { - if (doesPackageSupportRuntimePermissions(useOpenWifiPackage)) { - grantRuntimePermissions(useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, userId); - } + String useOpenWifiPackage, int userId) { + grantPermissionsToSystemPackage( + useOpenWifiPackage, userId, COARSE_LOCATION_PERMISSIONS); } public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) { Log.i(TAG, "Granting permissions to default sms app for user:" + userId); - if (packageName == null) { - return; - } - PackageParser.Package smsPackage = getPackage(packageName); - if (smsPackage != null && doesPackageSupportRuntimePermissions(smsPackage)) { - grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, false, true, userId); - grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, false, true, userId); - grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, false, true, userId); - grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, false, true, userId); - grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, false, true, userId); - grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, false, true, userId); - } + grantIgnoringSystemPackage(packageName, userId, + PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS, STORAGE_PERMISSIONS, + MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS); } public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) { + mServiceInternal.onDefaultDialerAppChanged(packageName, userId); Log.i(TAG, "Granting permissions to default dialer app for user:" + userId); - if (packageName == null) { - return; - } - PackageParser.Package dialerPackage = getPackage(packageName); - if (dialerPackage != null - && doesPackageSupportRuntimePermissions(dialerPackage)) { - grantRuntimePermissions(dialerPackage, PHONE_PERMISSIONS, false, true, userId); - grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId); - grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, false, true, userId); - grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId); - grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, false, true, userId); - } + grantIgnoringSystemPackage(packageName, userId, + PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS, + MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS); } public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) { Log.i(TAG, "Granting permissions to default Use Open WiFi app for user:" + userId); - if (packageName == null) { - return; - } - PackageParser.Package useOpenWifiPackage = getPackage(packageName); - if (useOpenWifiPackage != null - && doesPackageSupportRuntimePermissions(useOpenWifiPackage)) { - grantRuntimePermissions( - useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, false, true, userId); - } - } - - private void grantDefaultPermissionsToDefaultSimCallManager( - PackageParser.Package simCallManagerPackage, int userId) { - Log.i(TAG, "Granting permissions to sim call manager for user:" + userId); - if (doesPackageSupportRuntimePermissions(simCallManagerPackage)) { - grantRuntimePermissions(simCallManagerPackage, PHONE_PERMISSIONS, userId); - grantRuntimePermissions(simCallManagerPackage, MICROPHONE_PERMISSIONS, userId); - } + grantIgnoringSystemPackage(packageName, userId, COARSE_LOCATION_PERMISSIONS); } public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) { if (packageName == null) { return; } - PackageParser.Package simCallManagerPackage = getPackage(packageName); - if (simCallManagerPackage != null) { - grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage, userId); + Log.i(TAG, "Granting permissions to sim call manager for user:" + userId); + grantRuntimePermissionsToPackage(packageName, userId, false, false, + PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS); + } + + private void grantDefaultPermissionsToDefaultSystemSimCallManager( + String packageName, int userId) { + if (isSystemPackage(packageName)) { + grantDefaultPermissionsToDefaultSimCallManager(packageName, userId); } } @@ -976,13 +801,8 @@ public final class DefaultPermissionGrantPolicy { return; } for (String packageName : packageNames) { - PackageParser.Package carrierPackage = getSystemPackage(packageName); - if (carrierPackage != null - && doesPackageSupportRuntimePermissions(carrierPackage)) { - grantRuntimePermissions(carrierPackage, PHONE_PERMISSIONS, userId); - grantRuntimePermissions(carrierPackage, LOCATION_PERMISSIONS, userId); - grantRuntimePermissions(carrierPackage, SMS_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage(packageName, userId, + PHONE_PERMISSIONS, LOCATION_PERMISSIONS, SMS_PERMISSIONS); } } @@ -992,15 +812,9 @@ public final class DefaultPermissionGrantPolicy { return; } for (String packageName : packageNames) { - PackageParser.Package imsServicePackage = getSystemPackage(packageName); - if (imsServicePackage != null - && doesPackageSupportRuntimePermissions(imsServicePackage)) { - grantRuntimePermissions(imsServicePackage, PHONE_PERMISSIONS, userId); - grantRuntimePermissions(imsServicePackage, MICROPHONE_PERMISSIONS, userId); - grantRuntimePermissions(imsServicePackage, LOCATION_PERMISSIONS, userId); - grantRuntimePermissions(imsServicePackage, CAMERA_PERMISSIONS, userId); - grantRuntimePermissions(imsServicePackage, CONTACTS_PERMISSIONS, userId); - } + grantPermissionsToSystemPackage(packageName, userId, + PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS, + CAMERA_PERMISSIONS, CONTACTS_PERMISSIONS); } } @@ -1011,15 +825,12 @@ public final class DefaultPermissionGrantPolicy { return; } for (String packageName : packageNames) { - PackageParser.Package dataServicePackage = getSystemPackage(packageName); - if (dataServicePackage != null - && doesPackageSupportRuntimePermissions(dataServicePackage)) { - // Grant these permissions as system-fixed, so that nobody can accidentally - // break cellular data. - grantRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId); - grantRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId); - } + // Grant these permissions as system-fixed, so that nobody can accidentally + // break cellular data. + grantSystemFixedPermissionsToSystemPackage(packageName, userId, + PHONE_PERMISSIONS, LOCATION_PERMISSIONS); } + } public void revokeDefaultPermissionsFromDisabledTelephonyDataServices( @@ -1029,25 +840,17 @@ public final class DefaultPermissionGrantPolicy { return; } for (String packageName : packageNames) { - PackageParser.Package dataServicePackage = getSystemPackage(packageName); - if (dataServicePackage != null - && doesPackageSupportRuntimePermissions(dataServicePackage)) { - revokeRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId); - revokeRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId); + PackageInfo pkg = getSystemPackageInfo(packageName); + if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) { + revokeRuntimePermissions(packageName, PHONE_PERMISSIONS, true, userId); + revokeRuntimePermissions(packageName, LOCATION_PERMISSIONS, true, userId); } } } public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) { Log.i(TAG, "Granting permissions to active LUI app for user:" + userId); - if (packageName == null) { - return; - } - PackageParser.Package luiAppPackage = getSystemPackage(packageName); - if (luiAppPackage != null - && doesPackageSupportRuntimePermissions(luiAppPackage)) { - grantRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId); - } + grantSystemFixedPermissionsToSystemPackage(packageName, userId, CAMERA_PERMISSIONS); } public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) { @@ -1056,123 +859,116 @@ public final class DefaultPermissionGrantPolicy { return; } for (String packageName : packageNames) { - PackageParser.Package luiAppPackage = getSystemPackage(packageName); - if (luiAppPackage != null - && doesPackageSupportRuntimePermissions(luiAppPackage)) { - revokeRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId); + PackageInfo pkg = getSystemPackageInfo(packageName); + if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) { + revokeRuntimePermissions(packageName, CAMERA_PERMISSIONS, true, userId); } } } public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) { Log.i(TAG, "Granting permissions to default browser for user:" + userId); - if (packageName == null) { - return; - } - PackageParser.Package browserPackage = getSystemPackage(packageName); - if (browserPackage != null - && doesPackageSupportRuntimePermissions(browserPackage)) { - grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, false, false, userId); - } + grantPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS); } - private PackageParser.Package getDefaultSystemHandlerActivityPackage( - Intent intent, int userId) { + private String getDefaultSystemHandlerActivityPackage(String intentAction, int userId) { + return getDefaultSystemHandlerActivityPackage(new Intent(intentAction), userId); + } + + private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) { ResolveInfo handler = mServiceInternal.resolveIntent(intent, - intent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS, userId, false, - Binder.getCallingUid()); + intent.resolveType(mContext.getContentResolver()), DEFAULT_INTENT_QUERY_FLAGS, + userId, false, Binder.getCallingUid()); if (handler == null || handler.activityInfo == null) { return null; } if (mServiceInternal.isResolveActivityComponent(handler.activityInfo)) { return null; } - return getSystemPackage(handler.activityInfo.packageName); + String packageName = handler.activityInfo.packageName; + return isSystemPackage(packageName) ? packageName : null; + } + + private String getDefaultSystemHandlerServicePackage(String intentAction, int userId) { + return getDefaultSystemHandlerServicePackage(new Intent(intentAction), userId); } - private PackageParser.Package getDefaultSystemHandlerServicePackage( + private String getDefaultSystemHandlerServicePackage( Intent intent, int userId) { List<ResolveInfo> handlers = mServiceInternal.queryIntentServices( - intent, DEFAULT_FLAGS, Binder.getCallingUid(), userId); + intent, DEFAULT_INTENT_QUERY_FLAGS, Binder.getCallingUid(), userId); if (handlers == null) { return null; } final int handlerCount = handlers.size(); for (int i = 0; i < handlerCount; i++) { ResolveInfo handler = handlers.get(i); - PackageParser.Package handlerPackage = getSystemPackage( - handler.serviceInfo.packageName); - if (handlerPackage != null) { + String handlerPackage = handler.serviceInfo.packageName; + if (isSystemPackage(handlerPackage)) { return handlerPackage; } } return null; } - private List<PackageParser.Package> getHeadlessSyncAdapterPackages( + private ArrayList<String> getHeadlessSyncAdapterPackages( String[] syncAdapterPackageNames, int userId) { - List<PackageParser.Package> syncAdapterPackages = new ArrayList<>(); + ArrayList<String> syncAdapterPackages = new ArrayList<>(); - Intent homeIntent = new Intent(Intent.ACTION_MAIN); - homeIntent.addCategory(Intent.CATEGORY_LAUNCHER); + Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER); for (String syncAdapterPackageName : syncAdapterPackageNames) { homeIntent.setPackage(syncAdapterPackageName); ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent, - homeIntent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS, + homeIntent.resolveType(mContext.getContentResolver()), + DEFAULT_INTENT_QUERY_FLAGS, userId, false, Binder.getCallingUid()); if (homeActivity != null) { continue; } - PackageParser.Package syncAdapterPackage = getSystemPackage(syncAdapterPackageName); - if (syncAdapterPackage != null) { - syncAdapterPackages.add(syncAdapterPackage); + if (isSystemPackage(syncAdapterPackageName)) { + syncAdapterPackages.add(syncAdapterPackageName); } } return syncAdapterPackages; } - private PackageParser.Package getDefaultProviderAuthorityPackage( - String authority, int userId) { - ProviderInfo provider = - mServiceInternal.resolveContentProvider(authority, DEFAULT_FLAGS, userId); + private String getDefaultProviderAuthorityPackage(String authority, int userId) { + ProviderInfo provider = mServiceInternal.resolveContentProvider( + authority, DEFAULT_INTENT_QUERY_FLAGS, userId); if (provider != null) { - return getSystemPackage(provider.packageName); + return provider.packageName; } return null; } - private PackageParser.Package getPackage(String packageName) { - return mServiceInternal.getPackage(packageName); + private boolean isSystemPackage(String packageName) { + return isSystemPackage(getSystemPackageInfo(packageName)); } - private PackageParser.Package getSystemPackage(String packageName) { - PackageParser.Package pkg = getPackage(packageName); - if (pkg != null && pkg.isSystem()) { - return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null; + private boolean isSystemPackage(PackageInfo pkg) { + if (pkg == null) { + return false; } - return null; + return pkg.applicationInfo.isSystemApp() + && !isSysComponentOrPersistentPlatformSignedPrivApp(pkg); } - private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions, - int userId) { - grantRuntimePermissions(pkg, permissions, false, false, userId); - } - - private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions, + private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissions, boolean systemFixed, int userId) { grantRuntimePermissions(pkg, permissions, systemFixed, false, userId); } - private void revokeRuntimePermissions(PackageParser.Package pkg, Set<String> permissions, + private void revokeRuntimePermissions(String packageName, Set<String> permissions, boolean systemFixed, int userId) { - if (pkg.requestedPermissions.isEmpty()) { + PackageInfo pkg = getSystemPackageInfo(packageName); + if (ArrayUtils.isEmpty(pkg.requestedPermissions)) { return; } - Set<String> revokablePermissions = new ArraySet<>(pkg.requestedPermissions); + Set<String> revokablePermissions = new ArraySet<>(Arrays.asList(pkg.requestedPermissions)); for (String permission : permissions) { // We can't revoke what wasn't requested. @@ -1181,7 +977,7 @@ public final class DefaultPermissionGrantPolicy { } final int flags = mServiceInternal.getPermissionFlagsTEMP( - permission, pkg.packageName, userId); + permission, packageName, userId); // We didn't get this through the default grant policy. Move along. if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) { @@ -1197,29 +993,35 @@ public final class DefaultPermissionGrantPolicy { if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) { continue; } - mServiceInternal.revokeRuntimePermission(pkg.packageName, permission, userId, false); + mServiceInternal.revokeRuntimePermission(packageName, permission, userId, false); if (DEBUG) { Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ") - + permission + " to " + pkg.packageName); + + permission + " to " + packageName); } // Remove the GRANTED_BY_DEFAULT flag without touching the others. // Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains // sticky once set. - mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName, + mServiceInternal.updatePermissionFlagsTEMP(permission, packageName, PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, userId); } } - private void grantRuntimePermissions(PackageParser.Package pkg, + private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage, int userId) { - if (pkg.requestedPermissions.isEmpty()) { + if (pkg == null) { + return; + } + + String[] requestedPermissions = pkg.requestedPermissions; + if (ArrayUtils.isEmpty(requestedPermissions)) { return; } final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits); + ApplicationInfo applicationInfo = pkg.applicationInfo; // Automatically attempt to grant split permissions to older APKs final int numSplitPerms = PackageParser.SPLIT_PERMISSIONS.length; @@ -1227,13 +1029,13 @@ public final class DefaultPermissionGrantPolicy { final PackageParser.SplitPermissionInfo splitPerm = PackageParser.SPLIT_PERMISSIONS[splitPermNum]; - if (pkg.applicationInfo.targetSdkVersion < splitPerm.targetSdk + if (applicationInfo != null + && applicationInfo.targetSdkVersion < splitPerm.targetSdk && permissionsWithoutSplits.contains(splitPerm.rootPerm)) { Collections.addAll(permissions, splitPerm.newPerms); } } - List<String> requestedPermissions = pkg.requestedPermissions; Set<String> grantablePermissions = null; // In some cases, like for the Phone or SMS app, we grant permissions regardless @@ -1242,23 +1044,25 @@ public final class DefaultPermissionGrantPolicy { // choice to grant this app the permissions needed to function. For all other // apps, (default grants on first boot and user creation) we don't grant default // permissions if the version on the system image does not declare them. - if (!ignoreSystemPackage && pkg.isUpdatedSystemApp()) { - final PackageParser.Package disabledPkg = - mServiceInternal.getDisabledPackage(pkg.packageName); + if (!ignoreSystemPackage + && applicationInfo != null + && applicationInfo.isUpdatedSystemApp()) { + final PackageInfo disabledPkg = getSystemPackageInfo( + mServiceInternal.getDisabledSystemPackageName(pkg.packageName)); if (disabledPkg != null) { - if (disabledPkg.requestedPermissions.isEmpty()) { + if (ArrayUtils.isEmpty(disabledPkg.requestedPermissions)) { return; } if (!requestedPermissions.equals(disabledPkg.requestedPermissions)) { - grantablePermissions = new ArraySet<>(requestedPermissions); + grantablePermissions = new ArraySet<>(Arrays.asList(requestedPermissions)); requestedPermissions = disabledPkg.requestedPermissions; } } } - final int grantablePermissionCount = requestedPermissions.size(); + final int grantablePermissionCount = requestedPermissions.length; for (int i = 0; i < grantablePermissionCount; i++) { - String permission = requestedPermissions.get(i); + String permission = requestedPermissions[i]; // If there is a disabled system app it may request a permission the updated // version ot the data partition doesn't, In this case skip the permission. @@ -1288,7 +1092,7 @@ public final class DefaultPermissionGrantPolicy { pkg.packageName, permission, userId, false); if (DEBUG) { Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ") - + permission + " to default handler " + pkg.packageName); + + permission + " to default handler " + pkg); } int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; @@ -1307,7 +1111,7 @@ public final class DefaultPermissionGrantPolicy { && !systemFixed) { if (DEBUG) { Log.i(TAG, "Granted not fixed " + permission + " to default handler " - + pkg.packageName); + + pkg); } mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName, PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId); @@ -1316,28 +1120,42 @@ public final class DefaultPermissionGrantPolicy { } } - private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) { + private PackageInfo getSystemPackageInfo(String pkg) { + //TODO not MATCH_SYSTEM_ONLY? + return getPackageInfo(pkg, PackageManager.MATCH_FACTORY_ONLY); + } + + private PackageInfo getPackageInfo(String pkg) { + return getPackageInfo(pkg, 0 /* extraFlags */); + } + + private PackageInfo getPackageInfo(String pkg, + @PackageManager.PackageInfoFlags int extraFlags) { + return mServiceInternal.getPackageInfo(pkg, + DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags, + //TODO is this the right filterCallingUid? + UserHandle.USER_SYSTEM, UserHandle.USER_SYSTEM); + } + + private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) { if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) { return true; } - if (!pkg.isPrivileged()) { + if (!pkg.applicationInfo.isPrivilegedApp()) { return false; } - final PackageParser.Package disabledPkg = - mServiceInternal.getDisabledPackage(pkg.packageName); + final PackageInfo disabledPkg = getSystemPackageInfo( + mServiceInternal.getDisabledSystemPackageName(pkg.applicationInfo.packageName)); if (disabledPkg != null) { - if ((disabledPkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) { + ApplicationInfo disabledPackageAppInfo = disabledPkg.applicationInfo; + if (disabledPackageAppInfo != null + && (disabledPackageAppInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) { return false; } } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) { return false; } - final String systemPackageName = mServiceInternal.getKnownPackageName( - PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM); - final PackageParser.Package systemPackage = getPackage(systemPackageName); - return pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails) - || systemPackage.mSigningDetails.checkCapability(pkg.mSigningDetails, - PackageParser.SigningDetails.CertCapabilities.PERMISSION); + return mServiceInternal.isPlatformSigned(pkg.packageName); } private void grantDefaultPermissionExceptions(int userId) { @@ -1357,7 +1175,7 @@ public final class DefaultPermissionGrantPolicy { final int exceptionCount = mGrantExceptions.size(); for (int i = 0; i < exceptionCount; i++) { String packageName = mGrantExceptions.keyAt(i); - PackageParser.Package pkg = getSystemPackage(packageName); + PackageInfo pkg = getSystemPackageInfo(packageName); List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i); final int permissionGrantCount = permissionGrants.size(); for (int j = 0; j < permissionGrantCount; j++) { @@ -1368,8 +1186,7 @@ public final class DefaultPermissionGrantPolicy { permissions.clear(); } permissions.add(permissionGrant.name); - grantRuntimePermissions(pkg, permissions, - permissionGrant.fixed, userId); + grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId); } } } @@ -1474,15 +1291,14 @@ public final class DefaultPermissionGrantPolicy { outGrantExceptions.get(packageName); if (packageExceptions == null) { // The package must be on the system image - PackageParser.Package pkg = getSystemPackage(packageName); - if (pkg == null) { + if (!isSystemPackage(packageName)) { Log.w(TAG, "Unknown package:" + packageName); XmlUtils.skipCurrentTag(parser); continue; } // The package must support runtime permissions - if (!doesPackageSupportRuntimePermissions(pkg)) { + if (!doesPackageSupportRuntimePermissions(getSystemPackageInfo(packageName))) { Log.w(TAG, "Skipping non supporting runtime permissions package:" + packageName); XmlUtils.skipCurrentTag(parser); @@ -1527,8 +1343,9 @@ public final class DefaultPermissionGrantPolicy { } } - private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) { - return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1; + private static boolean doesPackageSupportRuntimePermissions(PackageInfo pkg) { + return pkg.applicationInfo != null + && pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1; } private static final class DefaultPermissionGrant { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index c4f90a125c71..4b6760c6405a 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1189,7 +1189,7 @@ public class PermissionManagerService { // is granted only if it had been defined by the original application. if (pkg.isUpdatedSystemApp()) { final PackageParser.Package disabledPkg = - mPackageManagerInt.getDisabledPackage(pkg.packageName); + mPackageManagerInt.getDisabledSystemPackage(pkg.packageName); final PackageSetting disabledPs = (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null; if (disabledPs != null @@ -1221,7 +1221,7 @@ public class PermissionManagerService { // packages can also get the permission. if (pkg.parentPackage != null) { final PackageParser.Package disabledParentPkg = mPackageManagerInt - .getDisabledPackage(pkg.parentPackage.packageName); + .getDisabledSystemPackage(pkg.parentPackage.packageName); final PackageSetting disabledParentPs = (disabledParentPkg != null) ? (PackageSetting) disabledParentPkg.mExtras : null; if (disabledParentPkg != null @@ -1372,7 +1372,7 @@ public class PermissionManagerService { return; } final PackageParser.Package disabledPkg = - mPackageManagerInt.getDisabledPackage(pkg.parentPackage.packageName); + mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName); if (disabledPkg == null || disabledPkg.mExtras == null) { return; } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 6f9d8033cd88..20918995a8ee 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -44,6 +44,8 @@ import android.os.IBinder; import android.os.IStatsCompanionService; import android.os.IStatsManager; import android.os.IStoraged; +import android.os.IThermalEventListener; +import android.os.IThermalService; import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; @@ -53,6 +55,7 @@ import android.os.StatsDimensionsValue; import android.os.StatsLogEventWrapper; import android.os.SynchronousResultReceiver; import android.os.SystemClock; +import android.os.Temperature; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; @@ -169,6 +172,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader = new KernelUidCpuClusterTimeReader(); + private static IThermalService sThermalService; + public StatsCompanionService(Context context) { super(); mContext = context; @@ -213,6 +218,24 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile); mKernelUidCpuClusterTimeReader.setThrottleInterval(0); mKernelUidCpuActiveTimeReader.setThrottleInterval(0); + + // Enable push notifications of throttling from vendor thermal + // management subsystem via thermalservice. + IBinder b = ServiceManager.getService("thermalservice"); + + if (b != null) { + sThermalService = IThermalService.Stub.asInterface(b); + try { + sThermalService.registerThermalEventListener( + new ThermalEventListener()); + Slog.i(TAG, "register thermal listener successfully"); + } catch (RemoteException e) { + // Should never happen. + Slog.e(TAG, "register thermal listener error"); + } + } else { + Slog.e(TAG, "cannot find thermalservice, no throttling push notifications"); + } } @Override @@ -906,6 +929,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } List<ExportedCallStat> callStats = binderStats.getExportedCallStats(); + binderStats.reset(); long elapsedNanos = SystemClock.elapsedRealtimeNanos(); for (ExportedCallStat callStat : callStats) { StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 13 /* fields */); @@ -934,6 +958,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats(); + // TODO: decouple binder calls exceptions with the rest of the binder calls data so that we + // can reset the exception stats. long elapsedNanos = SystemClock.elapsedRealtimeNanos(); for (Entry<String, Integer> entry : exceptionStats.entrySet()) { StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2 /* fields */); @@ -1456,4 +1482,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + // Thermal event received from vendor thermal management subsystem + private static final class ThermalEventListener extends IThermalEventListener.Stub { + @Override public void notifyThrottling(boolean isThrottling, Temperature temp) { + StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(), + isThrottling ? 1 : 0, temp.getValue()); + } + } } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 14294ec54ef1..c2d8188649da 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -566,6 +566,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) { + enforceBiometricDialog(); if (mBar != null) { try { mBar.showBiometricDialog(bundle, receiver, type); @@ -576,6 +577,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void onBiometricAuthenticated() { + enforceBiometricDialog(); if (mBar != null) { try { mBar.onBiometricAuthenticated(); @@ -586,6 +588,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void onBiometricHelp(String message) { + enforceBiometricDialog(); if (mBar != null) { try { mBar.onBiometricHelp(message); @@ -596,6 +599,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void onBiometricError(String error) { + enforceBiometricDialog(); if (mBar != null) { try { mBar.onBiometricError(error); @@ -606,6 +610,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void hideBiometricDialog() { + enforceBiometricDialog(); if (mBar != null) { try { mBar.hideBiometricDialog(); @@ -866,6 +871,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub { "StatusBarManagerService"); } + private void enforceBiometricDialog() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_BIOMETRIC_DIALOG, + "StatusBarManagerService"); + } + // ================================================================================ // Callbacks from the status bar service. // ================================================================================ diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java index 6c5452a3cb2e..7a3f030f9dd7 100644 --- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java +++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.pm.PackageManagerInternal; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; @@ -39,12 +38,13 @@ import android.telephony.CarrierConfigManager; import android.util.IntArray; import android.util.Slog; -import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.telephony.SmsApplication; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.UserManagerService; +import com.android.server.pm.permission.DefaultPermissionGrantPolicy; +import com.android.server.pm.permission.PermissionManagerInternal; /** * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup @@ -72,8 +72,8 @@ public class TelecomLoaderService extends SystemService { synchronized (mLock) { if (mDefaultSmsAppRequests != null || mDefaultDialerAppRequests != null || mDefaultSimCallManagerRequests != null) { - final PackageManagerInternal packageManagerInternal = LocalServices - .getService(PackageManagerInternal.class); + final DefaultPermissionGrantPolicy permissionPolicy = + getDefaultPermissionGrantPolicy(); if (mDefaultSmsAppRequests != null) { ComponentName smsComponent = SmsApplication.getDefaultSmsApplication( @@ -83,7 +83,7 @@ public class TelecomLoaderService extends SystemService { for (int i = requestCount - 1; i >= 0; i--) { final int userid = mDefaultSmsAppRequests.get(i); mDefaultSmsAppRequests.remove(i); - packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp( + permissionPolicy.grantDefaultPermissionsToDefaultSmsApp( smsComponent.getPackageName(), userid); } } @@ -97,7 +97,7 @@ public class TelecomLoaderService extends SystemService { for (int i = requestCount - 1; i >= 0; i--) { final int userId = mDefaultDialerAppRequests.get(i); mDefaultDialerAppRequests.remove(i); - packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp( + permissionPolicy.grantDefaultPermissionsToDefaultDialerApp( packageName, userId); } } @@ -113,7 +113,7 @@ public class TelecomLoaderService extends SystemService { for (int i = requestCount - 1; i >= 0; i--) { final int userId = mDefaultSimCallManagerRequests.get(i); mDefaultSimCallManagerRequests.remove(i); - packageManagerInternal + permissionPolicy .grantDefaultPermissionsToDefaultSimCallManager( packageName, userId); } @@ -132,6 +132,11 @@ public class TelecomLoaderService extends SystemService { } } + private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() { + return LocalServices.getService(PermissionManagerInternal.class) + .getDefaultPermissionGrantPolicy(); + } + private static final ComponentName SERVICE_COMPONENT = new ComponentName( "com.android.server.telecom", "com.android.server.telecom.components.TelecomService"); @@ -196,82 +201,68 @@ public class TelecomLoaderService extends SystemService { private void registerDefaultAppProviders() { - final PackageManagerInternal packageManagerInternal = LocalServices.getService( - PackageManagerInternal.class); - - // Set a callback for the package manager to query the default sms app. - packageManagerInternal.setSmsAppPackagesProvider( - new PackageManagerInternal.PackagesProvider() { - @Override - public String[] getPackages(int userId) { - synchronized (mLock) { - if (mServiceConnection == null) { - if (mDefaultSmsAppRequests == null) { - mDefaultSmsAppRequests = new IntArray(); - } - mDefaultSmsAppRequests.add(userId); - return null; + final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy(); + + // Set a callback for the permission grant policy to query the default sms app. + permissionPolicy.setSmsAppPackagesProvider(userId -> { + synchronized (mLock) { + if (mServiceConnection == null) { + if (mDefaultSmsAppRequests == null) { + mDefaultSmsAppRequests = new IntArray(); } + mDefaultSmsAppRequests.add(userId); + return null; } - ComponentName smsComponent = SmsApplication.getDefaultSmsApplication( - mContext, true); - if (smsComponent != null) { - return new String[]{smsComponent.getPackageName()}; - } - return null; } + ComponentName smsComponent = SmsApplication.getDefaultSmsApplication( + mContext, true); + if (smsComponent != null) { + return new String[]{smsComponent.getPackageName()}; + } + return null; }); - // Set a callback for the package manager to query the default dialer app. - packageManagerInternal.setDialerAppPackagesProvider( - new PackageManagerInternal.PackagesProvider() { - @Override - public String[] getPackages(int userId) { - synchronized (mLock) { - if (mServiceConnection == null) { - if (mDefaultDialerAppRequests == null) { - mDefaultDialerAppRequests = new IntArray(); - } - mDefaultDialerAppRequests.add(userId); - return null; + // Set a callback for the permission grant policy to query the default dialer app. + permissionPolicy.setDialerAppPackagesProvider(userId -> { + synchronized (mLock) { + if (mServiceConnection == null) { + if (mDefaultDialerAppRequests == null) { + mDefaultDialerAppRequests = new IntArray(); } + mDefaultDialerAppRequests.add(userId); + return null; } - String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext); - if (packageName != null) { - return new String[]{packageName}; - } - return null; } + String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext); + if (packageName != null) { + return new String[]{packageName}; + } + return null; }); - // Set a callback for the package manager to query the default sim call manager. - packageManagerInternal.setSimCallManagerPackagesProvider( - new PackageManagerInternal.PackagesProvider() { - @Override - public String[] getPackages(int userId) { - synchronized (mLock) { - if (mServiceConnection == null) { - if (mDefaultSimCallManagerRequests == null) { - mDefaultSimCallManagerRequests = new IntArray(); - } - mDefaultSimCallManagerRequests.add(userId); - return null; + // Set a callback for the permission grant policy to query the default sim call manager. + permissionPolicy.setSimCallManagerPackagesProvider(userId -> { + synchronized (mLock) { + if (mServiceConnection == null) { + if (mDefaultSimCallManagerRequests == null) { + mDefaultSimCallManagerRequests = new IntArray(); } + mDefaultSimCallManagerRequests.add(userId); + return null; } - TelecomManager telecomManager = + } + TelecomManager telecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); - PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId); - if (phoneAccount != null) { - return new String[]{phoneAccount.getComponentName().getPackageName()}; - } - return null; + PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId); + if (phoneAccount != null) { + return new String[]{phoneAccount.getComponentName().getPackageName()}; } + return null; }); } private void registerDefaultAppNotifier() { - final PackageManagerInternal packageManagerInternal = LocalServices.getService( - PackageManagerInternal.class); + final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy(); // Notify the package manager on default app changes final Uri defaultSmsAppUri = Settings.Secure.getUriFor( @@ -287,17 +278,17 @@ public class TelecomLoaderService extends SystemService { ComponentName smsComponent = SmsApplication.getDefaultSmsApplication( mContext, true); if (smsComponent != null) { - packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp( + permissionPolicy.grantDefaultPermissionsToDefaultSmsApp( smsComponent.getPackageName(), userId); } } else if (defaultDialerAppUri.equals(uri)) { String packageName = DefaultDialerManager.getDefaultDialerApplication( mContext); if (packageName != null) { - packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp( + permissionPolicy.grantDefaultPermissionsToDefaultDialerApp( packageName, userId); } - updateSimCallManagerPermissions(packageManagerInternal, userId); + updateSimCallManagerPermissions(permissionPolicy, userId); } } }; @@ -310,14 +301,12 @@ public class TelecomLoaderService extends SystemService { private void registerCarrierConfigChangedReceiver() { - final PackageManagerInternal packageManagerInternal = LocalServices.getService( - PackageManagerInternal.class); BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { for (int userId : UserManagerService.getInstance().getUserIds()) { - updateSimCallManagerPermissions(packageManagerInternal, userId); + updateSimCallManagerPermissions(getDefaultPermissionGrantPolicy(), userId); } } } @@ -327,15 +316,15 @@ public class TelecomLoaderService extends SystemService { new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), null, null); } - private void updateSimCallManagerPermissions(PackageManagerInternal packageManagerInternal, - int userId) { + private void updateSimCallManagerPermissions( + DefaultPermissionGrantPolicy permissionGrantPolicy, int userId) { TelecomManager telecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId); if (phoneAccount != null) { Slog.i(TAG, "updating sim call manager permissions for userId:" + userId); String packageName = phoneAccount.getComponentName().getPackageName(); - packageManagerInternal.grantDefaultPermissionsToDefaultSimCallManager( + permissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager( packageName, userId); } } diff --git a/core/java/com/android/internal/textservice/LazyIntToIntMap.java b/services/core/java/com/android/server/textservices/LazyIntToIntMap.java index ca9936c5fcda..2e7f2a92e1d9 100644 --- a/core/java/com/android/internal/textservice/LazyIntToIntMap.java +++ b/services/core/java/com/android/server/textservices/LazyIntToIntMap.java @@ -14,21 +14,18 @@ * limitations under the License. */ -package com.android.internal.textservice; +package com.android.server.textservices; import android.annotation.NonNull; import android.util.SparseIntArray; -import com.android.internal.annotations.VisibleForTesting; - import java.util.function.IntUnaryOperator; /** * Simple int-to-int key-value-store that is to be lazily initialized with the given * {@link IntUnaryOperator}. */ -@VisibleForTesting -public final class LazyIntToIntMap { +final class LazyIntToIntMap { private final SparseIntArray mMap = new SparseIntArray(); diff --git a/services/core/java/com/android/server/textservices/LocaleUtils.java b/services/core/java/com/android/server/textservices/LocaleUtils.java new file mode 100644 index 000000000000..89d8c1e96614 --- /dev/null +++ b/services/core/java/com/android/server/textservices/LocaleUtils.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.textservices; + +import android.annotation.Nullable; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * Provides {@code Locale} related utility methods for {@link TextServicesManagerService}. + * <p>This class is intentionally package-private. Utility methods here are tightly coupled with + * implementation details in {@link TextServicesManagerService}. Hence this class is not suitable + * for other components to directly use.</p> + */ +final class LocaleUtils { + /** + * Returns a list of {@link Locale} in the order of appropriateness for the default spell + * checker service. + * + * <p>If the system language is English, and the region is also explicitly specified in the + * system locale, the following fallback order will be applied.</p> + * <ul> + * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> + * <li>(system-locale-language, system-locale-region)</li> + * <li>("en", "US")</li> + * <li>("en", "GB")</li> + * <li>("en")</li> + * </ul> + * + * <p>If the system language is English, but no region is specified in the system locale, + * the following fallback order will be applied.</p> + * <ul> + * <li>("en")</li> + * <li>("en", "US")</li> + * <li>("en", "GB")</li> + * </ul> + * + * <p>If the system language is not English, the following fallback order will be applied.</p> + * <ul> + * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> + * <li>(system-locale-language, system-locale-region) (if exists)</li> + * <li>(system-locale-language) (if exists)</li> + * <li>("en", "US")</li> + * <li>("en", "GB")</li> + * <li>("en")</li> + * </ul> + * + * @param systemLocale the current system locale to be taken into consideration. + * @return a list of {@link Locale}. The first one is considered to be most appropriate. + */ + public static ArrayList<Locale> getSuitableLocalesForSpellChecker( + @Nullable final Locale systemLocale) { + final Locale systemLocaleLanguageCountryVariant; + final Locale systemLocaleLanguageCountry; + final Locale systemLocaleLanguage; + if (systemLocale != null) { + final String language = systemLocale.getLanguage(); + final boolean hasLanguage = !TextUtils.isEmpty(language); + final String country = systemLocale.getCountry(); + final boolean hasCountry = !TextUtils.isEmpty(country); + final String variant = systemLocale.getVariant(); + final boolean hasVariant = !TextUtils.isEmpty(variant); + if (hasLanguage && hasCountry && hasVariant) { + systemLocaleLanguageCountryVariant = new Locale(language, country, variant); + } else { + systemLocaleLanguageCountryVariant = null; + } + if (hasLanguage && hasCountry) { + systemLocaleLanguageCountry = new Locale(language, country); + } else { + systemLocaleLanguageCountry = null; + } + if (hasLanguage) { + systemLocaleLanguage = new Locale(language); + } else { + systemLocaleLanguage = null; + } + } else { + systemLocaleLanguageCountryVariant = null; + systemLocaleLanguageCountry = null; + systemLocaleLanguage = null; + } + + final ArrayList<Locale> locales = new ArrayList<>(); + if (systemLocaleLanguageCountryVariant != null) { + locales.add(systemLocaleLanguageCountryVariant); + } + + if (Locale.ENGLISH.equals(systemLocaleLanguage)) { + if (systemLocaleLanguageCountry != null) { + // If the system language is English, and the region is also explicitly specified, + // following fallback order will be applied. + // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] + // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] + // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] + // - en + if (systemLocaleLanguageCountry != null) { + locales.add(systemLocaleLanguageCountry); + } + if (!Locale.US.equals(systemLocaleLanguageCountry)) { + locales.add(Locale.US); + } + if (!Locale.UK.equals(systemLocaleLanguageCountry)) { + locales.add(Locale.UK); + } + locales.add(Locale.ENGLISH); + } else { + // If the system language is English, but no region is specified, following + // fallback order will be applied. + // - en + // - en_US + // - en_GB + locales.add(Locale.ENGLISH); + locales.add(Locale.US); + locales.add(Locale.UK); + } + } else { + // If the system language is not English, the fallback order will be + // - systemLocaleLanguageCountry [if non-null] + // - systemLocaleLanguage [if non-null] + // - en_US + // - en_GB + // - en + if (systemLocaleLanguageCountry != null) { + locales.add(systemLocaleLanguageCountry); + } + if (systemLocaleLanguage != null) { + locales.add(systemLocaleLanguage); + } + locales.add(Locale.US); + locales.add(Locale.UK); + locales.add(Locale.ENGLISH); + } + return locales; + } +} diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java index 40f81b3c2850..23c29f8f8997 100644 --- a/services/core/java/com/android/server/TextServicesManagerService.java +++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java @@ -14,21 +14,21 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.textservices; import static android.view.textservice.TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; -import com.android.internal.inputmethod.InputMethodUtils; +import com.android.internal.inputmethod.SubtypeLocaleUtils; import com.android.internal.textservice.ISpellCheckerService; import com.android.internal.textservice.ISpellCheckerServiceCallback; import com.android.internal.textservice.ISpellCheckerSession; import com.android.internal.textservice.ISpellCheckerSessionListener; import com.android.internal.textservice.ITextServicesManager; import com.android.internal.textservice.ITextServicesSessionListener; -import com.android.internal.textservice.LazyIntToIntMap; import com.android.internal.util.DumpUtils; +import com.android.server.SystemService; import org.xmlpull.v1.XmlPullParserException; @@ -461,7 +461,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { // is pre-installed or not. final Locale systemLocal = mContext.getResources().getConfiguration().locale; final ArrayList<Locale> suitableLocales = - InputMethodUtils.getSuitableLocalesForSpellChecker(systemLocal); + LocaleUtils.getSuitableLocalesForSpellChecker(systemLocal); if (DBG) { Slog.w(TAG, "findAvailSystemSpellCheckerLocked suitableLocales=" + Arrays.toString(suitableLocales.toArray(new Locale[suitableLocales.size()]))); @@ -475,7 +475,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { final int subtypeCount = info.getSubtypeCount(); for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) { final SpellCheckerSubtype subtype = info.getSubtypeAt(subtypeIndex); - final Locale subtypeLocale = InputMethodUtils.constructLocaleFromString( + final Locale subtypeLocale = SubtypeLocaleUtils.constructLocaleFromString( subtype.getLocale()); if (locale.equals(subtypeLocale)) { // TODO: We may have more spell checkers that fall into this category. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 5d0101f88c69..ac6582634bf8 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3606,6 +3606,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final int targetPosition = findPositionForStack(position, child, false /* adding */); super.positionChildAt(targetPosition, child, includingParents); + if (includingParents) { + // We still want to move the display of this stack container to top because even the + // target position is adjusted to non-top, the intention of the condition is to have + // higher z-order to gain focus (e.g. moving a task of a fullscreen stack to front + // in a non-top display which is using picture-in-picture mode). + final int topChildPosition = getChildCount() - 1; + if (targetPosition < topChildPosition && position >= topChildPosition) { + getParent().positionChildAt(POSITION_TOP, this /* child */, + true /* includingParents */); + } + } + setLayoutNeeded(); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 33097986b2e1..ef3a770390ef 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -268,11 +268,11 @@ final class InputMonitor { } final InputWindowHandle dragWindowHandle = mService.mDragDropController.getInputWindowHandleLocked(); - if (dragWindowHandle != null) { - addInputWindowHandle(dragWindowHandle); - } else { + if (dragWindowHandle == null) { Slog.w(TAG_WM, "Drag is in progress but there is no " + "drag window handle."); + } else if (dragWindowHandle.displayId == mDisplayId) { + addInputWindowHandle(dragWindowHandle); } } @@ -283,11 +283,11 @@ final class InputMonitor { } final InputWindowHandle dragWindowHandle = mService.mTaskPositioningController.getDragWindowHandleLocked(); - if (dragWindowHandle != null) { - addInputWindowHandle(dragWindowHandle); - } else { + if (dragWindowHandle == null) { Slog.e(TAG_WM, "Repositioning is in progress but there is no drag window handle."); + } else if (dragWindowHandle.displayId == mDisplayId) { + addInputWindowHandle(dragWindowHandle); } } diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 8effc6bbdd59..d2696c0479af 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -19,17 +19,17 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.RESIZE_MODE_USER; import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; + +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; 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.WindowManagerService.dipToPixel; -import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP; import android.annotation.IntDef; -import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.graphics.Point; import android.graphics.Rect; @@ -51,7 +51,6 @@ import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.server.input.InputApplicationHandle; import com.android.server.input.InputWindowHandle; -import com.android.server.wm.WindowManagerService.H; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -209,7 +208,6 @@ class TaskPositioner { // Post back to WM to handle clean-ups. We still need the input // event handler for the last finishInputEvent()! mService.mTaskPositioningController.finishTaskPositioning(); - mTask.getDisplayContent().getInputMonitor().updateInputWindowsLw(true /*force*/); } handled = true; } catch (Exception e) { @@ -237,7 +235,7 @@ class TaskPositioner { } /** - * @param display The Display that the window being dragged is on. + * @param displayContent The Display that the window being dragged is on. */ void register(DisplayContent displayContent) { final Display display = displayContent.getDisplay(); @@ -303,6 +301,9 @@ class TaskPositioner { } mDisplayContent.pauseRotationLocked(); + // Notify InputMonitor to take mDragWindowHandle. + mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); + mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics); @@ -334,6 +335,9 @@ class TaskPositioner { mDragApplicationHandle = null; mDragEnded = true; + // Notify InputMonitor to remove mDragWindowHandle. + mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); + // Resume rotations after a drag. if (DEBUG_ORIENTATION) { Slog.d(TAG, "Resuming rotation after re-position"); diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 9cdc6b75c3b6..33416f66f85b 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -20,14 +20,13 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITION import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.Nullable; -import android.app.IActivityManager; import android.app.IActivityTaskManager; -import android.os.RemoteException; import android.os.Handler; import android.os.Looper; +import android.os.RemoteException; import android.util.Slog; -import android.view.Display; import android.view.IWindow; + import com.android.internal.annotations.GuardedBy; import com.android.server.input.InputManagerService; import com.android.server.input.InputWindowHandle; @@ -124,10 +123,8 @@ class TaskPositioningController { return false; } - Display display = displayContent.getDisplay(); mTaskPositioner = TaskPositioner.create(mService); mTaskPositioner.register(displayContent); - displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); // We need to grab the touch focus so that the touch events during the // resizing/scrolling are not sent to the app. 'win' is the main window diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java index 9381fc61821e..cbe7d9d05e28 100644 --- a/services/core/java/com/android/server/wm/WindowFrames.java +++ b/services/core/java/com/android/server/wm/WindowFrames.java @@ -286,8 +286,9 @@ public class WindowFrames { boolean overrideBottomInset = !windowsAreFloating && !inFullscreenContainer && mFrame.bottom > windowBounds.bottom; - mTmpRect.set(mFrame.left, mFrame.top, overrideRightInset ? mTmpRect.right : mFrame.right, - overrideBottomInset ? mTmpRect.bottom : mFrame.bottom); + mTmpRect.set(mFrame.left, mFrame.top, + overrideRightInset ? windowBounds.right : mFrame.right, + overrideBottomInset ? windowBounds.bottom : mFrame.bottom); InsetUtils.insetsBetweenFrames(mTmpRect, mContentFrame, mContentInsets); InsetUtils.insetsBetweenFrames(mTmpRect, mVisibleFrame, mVisibleInsets); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index bb08345b2fe1..9d63305b5858 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -118,6 +118,7 @@ import com.android.server.statusbar.StatusBarManagerService; import com.android.server.storage.DeviceStorageMonitorService; import com.android.server.telecom.TelecomLoaderService; import com.android.server.textclassifier.TextClassificationManagerService; +import com.android.server.textservices.TextServicesManagerService; import com.android.server.trust.TrustManagerService; import com.android.server.tv.TvInputManagerService; import com.android.server.tv.TvRemoteService; @@ -797,6 +798,9 @@ public final class SystemServer { boolean isWatch = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_WATCH); + boolean enableVrService = context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE); + // For debugging RescueParty if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) { throw new RuntimeException(); @@ -930,7 +934,7 @@ public final class SystemServer { traceLog.traceEnd(); }, START_HIDL_SERVICES); - if (!isWatch) { + if (!isWatch && enableVrService) { traceBeginAndSlog("StartVrManagerService"); mSystemServiceManager.startService(VrManagerService.class); traceEnd(); diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java index 33010a19d810..823c0a1ac7b0 100644 --- a/services/net/java/android/net/ip/IpServer.java +++ b/services/net/java/android/net/ip/IpServer.java @@ -430,6 +430,8 @@ public class IpServer extends StateMachine { params.mtu = v6only.getMtu(); params.hasDefaultRoute = v6only.hasIPv6DefaultRoute(); + if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName()); + for (LinkAddress linkAddr : v6only.getLinkAddresses()) { if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue; @@ -549,6 +551,20 @@ public class IpServer extends StateMachine { } } + private byte getHopLimit(String upstreamIface) { + try { + int upstreamHopLimit = Integer.parseUnsignedInt( + mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit")); + // Add one hop to account for this forwarding device + upstreamHopLimit++; + // Cap the hop limit to 255. + return (byte) Integer.min(upstreamHopLimit, 255); + } catch (Exception e) { + mLog.e("Failed to find upstream interface hop limit", e); + } + return RaParams.DEFAULT_HOPLIMIT; + } + private void setRaParams(RaParams newParams) { if (mRaDaemon != null) { final RaParams deprecatedParams = diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java index 1c025cf671d9..aad7230bbc89 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java @@ -18,23 +18,22 @@ package com.android.server.accessibility; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityService; import android.content.Context; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; -import android.os.Looper; import android.util.DisplayMetrics; import android.view.GestureDetector; import android.view.MotionEvent; -import java.util.ArrayList; + import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; +import java.util.ArrayList; /** * Tests for AccessibilityGestureDetector @@ -50,14 +49,6 @@ public class AccessibilityGestureDetectorTest { private AccessibilityGestureDetector mDetector; private AccessibilityGestureDetector.Listener mResultListener; - - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() { // Construct a mock Context. @@ -67,7 +58,6 @@ public class AccessibilityGestureDetectorTest { Resources mockResources = mock(Resources.class); when(mockResources.getDisplayMetrics()).thenReturn(displayMetricsMock); Context contextMock = mock(Context.class); - when(contextMock.getMainLooper()).thenReturn(Looper.myLooper()); when(contextMock.getResources()).thenReturn(mockResources); // Construct a testable AccessibilityGestureDetector. diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java index 4c0f38aa2998..b9b6d55b52d6 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java @@ -29,7 +29,6 @@ import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; import android.app.Instrumentation; -import android.os.Looper; import android.os.UserHandle; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -41,8 +40,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.IntPair; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -63,13 +62,6 @@ public class AccessibilityManagerTest { private MessageCapturingHandler mHandler; private Instrumentation mInstrumentation; - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -77,6 +69,12 @@ public class AccessibilityManagerTest { mInstrumentation = InstrumentationRegistry.getInstrumentation(); } + @After + public void tearDown() { + mHandler.removeAllMessages(); + } + + private AccessibilityManager createManager(boolean enabled) throws Exception { long serviceReturnValue = IntPair.of( (enabled) ? AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED : 0, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java index 412e8445fef9..66d934541260 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java @@ -33,16 +33,14 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import com.android.server.wm.WindowManagerInternal; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -74,13 +72,6 @@ public class AccessibilityServiceConnectionTest { MessageCapturingHandler mHandler = new MessageCapturingHandler(null); - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -98,6 +89,12 @@ public class AccessibilityServiceConnectionTest { mMockGlobalActionPerformer); } + @After + public void tearDown() { + mHandler.removeAllMessages(); + } + + @Test public void bind_requestsContextToBindService() { mConnection.bindLocked(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java index a3decb93a9e7..44a514f7623c 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java @@ -16,19 +16,8 @@ package com.android.server.accessibility; -import android.accessibilityservice.FingerprintGestureController; -import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback; -import android.accessibilityservice.IAccessibilityServiceConnection; -import android.os.Looper; -import android.support.test.filters.FlakyTest; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static android.accessibilityservice.FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN; +import static android.accessibilityservice.FingerprintGestureController + .FINGERPRINT_GESTURE_SWIPE_DOWN; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -38,6 +27,15 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import android.accessibilityservice.FingerprintGestureController; +import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback; +import android.accessibilityservice.IAccessibilityServiceConnection; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + /** * Tests for FingerprintGestureController. * TODO: These tests aren't really for server code, so this isn't their ideal home. @@ -47,13 +45,6 @@ public class FingerprintGestureControllerTest { @Mock FingerprintGestureCallback mMockFingerprintGestureCallback; FingerprintGestureController mFingerprintGestureController; - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -97,7 +88,6 @@ public class FingerprintGestureControllerTest { } @Test - @FlakyTest public void testDetectionActiveCallback_withHandler_shouldPostRunnableToHandler() { MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> { message.getCallback().run(); @@ -127,6 +117,8 @@ public class FingerprintGestureControllerTest { mFingerprintGestureController.onGestureDetectionActiveChanged(false); assertFalse(messageCapturingHandler.hasMessages()); verifyZeroInteractions(mMockFingerprintGestureCallback); + + messageCapturingHandler.removeAllMessages(); } @Test @@ -145,7 +137,6 @@ public class FingerprintGestureControllerTest { } @Test - @FlakyTest public void testGestureCallback_withHandler_shouldPostRunnableToHandler() { MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> { message.getCallback().run(); @@ -167,5 +158,7 @@ public class FingerprintGestureControllerTest { mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN); assertFalse(messageCapturingHandler.hasMessages()); verifyZeroInteractions(mMockFingerprintGestureCallback); + + messageCapturingHandler.removeAllMessages(); } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java index 6ce7bbe6117e..de7bc443b8c5 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java @@ -16,18 +16,24 @@ package com.android.server.accessibility; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import android.accessibilityservice.FingerprintGestureController; import android.content.res.Resources; import android.hardware.fingerprint.IFingerprintService; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; import android.view.KeyEvent; import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -35,15 +41,6 @@ import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.Collections; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - /** * Tests for FingerprintGestureDispatcher */ @@ -57,13 +54,6 @@ public class FingerprintGestureDispatcherTest { private MessageCapturingHandler mMessageCapturingHandler; private FingerprintGestureDispatcher mFingerprintGestureDispatcher; - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -77,6 +67,12 @@ public class FingerprintGestureDispatcherTest { when(mGestureCapturingClient.isCapturingFingerprintGestures()).thenReturn(true); } + @After + public void tearDown() { + mMessageCapturingHandler.removeAllMessages(); + } + + @Test public void testNoServices_doesNotCrashOrConsumeGestures() { mFingerprintGestureDispatcher.onClientActiveChanged(true); @@ -171,7 +167,7 @@ public class FingerprintGestureDispatcherTest { } @Test - public void ifGestureDectionNotSupported_neverSaysAvailable() throws Exception { + public void ifGestureDetectionNotSupported_neverSaysAvailable() throws Exception { when(mMockResources.getBoolean(anyInt())).thenReturn(false); // Need to create a new dispatcher, since it picks up the resource value in its // constructor. This is fine since hardware config values don't change dynamically. diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java index 236b45894fb3..23ce483be107 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java @@ -40,6 +40,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.view.KeyEvent; +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter; @@ -47,16 +48,14 @@ import com.android.server.policy.WindowManagerPolicy; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.List; /** * Tests for KeyEventDispatcher @@ -68,7 +67,7 @@ public class KeyEventDispatcherTest { private final KeyEvent mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x40); private final KeyEvent mOtherKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x50); private final Object mLock = new Object(); - private MessageCapturingHandler mInputEventsHander; + private MessageCapturingHandler mInputEventsHandler; private KeyEventDispatcher mKeyEventDispatcher; private KeyEventFilter mKeyEventFilter1; private KeyEventFilter mKeyEventFilter2; @@ -77,23 +76,17 @@ public class KeyEventDispatcherTest { private ArgumentCaptor<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class); private ArgumentCaptor<Integer> mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class); - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() { - mInputEventsHander = new MessageCapturingHandler(); + Looper looper = InstrumentationRegistry.getContext().getMainLooper(); + mInputEventsHandler = new MessageCapturingHandler(looper, null); mMockPowerManagerService = mock(IPowerManager.class); // TODO: It would be better to mock PowerManager rather than its binder, but the class is // final. PowerManager powerManager = - new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler()); - mMessageCapturingHandler = new MessageCapturingHandler(); - mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHander, SEND_FRAMEWORK_KEY_EVENT, + new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler(looper)); + mMessageCapturingHandler = new MessageCapturingHandler(looper, null); + mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHandler, SEND_FRAMEWORK_KEY_EVENT, mLock, powerManager, mMessageCapturingHandler); mKeyEventFilter1 = mock(KeyEventFilter.class); @@ -107,10 +100,17 @@ public class KeyEventDispatcherTest { .thenReturn(true); } + @After + public void tearDown() { + mInputEventsHandler.removeAllMessages(); + mMessageCapturingHandler.removeAllMessages(); + } + + @Test public void testNotifyKeyEvent_withNoBoundServices_shouldReturnFalse() { assertFalse(mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Collections.EMPTY_LIST)); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @Test @@ -119,7 +119,7 @@ public class KeyEventDispatcherTest { when(keyEventFilter.onKeyEvent((KeyEvent) anyObject(), anyInt())).thenReturn(false); assertFalse(mKeyEventDispatcher .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(keyEventFilter))); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @Test @@ -152,9 +152,9 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @Test @@ -166,10 +166,10 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getValue()); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @Test @@ -182,9 +182,9 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @Test @@ -198,10 +198,10 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true, mFilter2SequenceCaptor.getValue()); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @Test @@ -215,10 +215,10 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @Test @@ -232,10 +232,10 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true, mFilter2SequenceCaptor.getValue()); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } // Each event should have its result set only once, but if it's set twice, we should ignore @@ -249,14 +249,14 @@ public class KeyEventDispatcherTest { mFilter1SequenceCaptor.getValue()); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); // Verify event is sent properly when other service responds mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); - assertFalse(mMessageCapturingHandler.isTimeoutPending()); + assertFalse(isTimeoutPending(mMessageCapturingHandler)); } @@ -269,9 +269,9 @@ public class KeyEventDispatcherTest { mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); - mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); + mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0)); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @@ -284,9 +284,9 @@ public class KeyEventDispatcherTest { mFilter1SequenceCaptor.getValue()); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); - mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); + mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0)); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @@ -300,9 +300,9 @@ public class KeyEventDispatcherTest { mFilter1SequenceCaptor.getValue()); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); - mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); + mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); } @@ -310,34 +310,34 @@ public class KeyEventDispatcherTest { @Test public void testEventTimesOut_thenServiceReturnsFalse_shouldPassToFrameworkOnce() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); - mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); - mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT); + mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @Test public void testEventTimesOut_afterServiceReturnsFalse_shouldPassToFrameworkOnce() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); - mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT); + mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); - mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); + mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @@ -349,9 +349,9 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getValue()); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); - mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); + mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); } @@ -362,11 +362,11 @@ public class KeyEventDispatcherTest { @Test public void testFlushService_withPendingEvent_shouldPassToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.flush(mKeyEventFilter1); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test @@ -377,7 +377,7 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.flush(mKeyEventFilter1); mKeyEventDispatcher.flush(mKeyEventFilter2); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test @@ -389,7 +389,7 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true, mFilter2SequenceCaptor.getValue()); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test @@ -401,7 +401,7 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); - assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test @@ -417,11 +417,11 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(0)); - mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT); + mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(1)); @@ -433,14 +433,14 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test @@ -448,7 +448,7 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(0)); @@ -463,7 +463,7 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(0)); @@ -478,9 +478,9 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); - mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); + mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, @@ -494,7 +494,7 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher.notifyKeyEventLocked( mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); @@ -513,7 +513,7 @@ public class KeyEventDispatcherTest { mKeyEventDispatcher.flush(mKeyEventFilter1); mKeyEventDispatcher.notifyKeyEventLocked( mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter2)); - assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); + assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getAllValues().get(0)); @@ -543,24 +543,34 @@ public class KeyEventDispatcherTest { } private void assertOneKeyEventSentToFramework(KeyEvent event) { - assertEquals(1, mInputEventsHander.timedMessages.size()); - assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what); - assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, - mInputEventsHander.timedMessages.get(0).arg1); - assertTrue(new KeyEventMatcher(event).matches(mInputEventsHander.timedMessages.get(0).obj)); + assertEquals(1, mInputEventsHandler.timedMessages.size()); + + Message m = getTimedMessage(mInputEventsHandler, 0); + assertEquals(SEND_FRAMEWORK_KEY_EVENT, m.what); + assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m.arg1); + assertTrue(new KeyEventMatcher(event).matches(m.obj)); } private void assertTwoKeyEventsSentToFrameworkInOrder(KeyEvent first, KeyEvent second) { - assertEquals(2, mInputEventsHander.timedMessages.size()); - assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what); - assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, - mInputEventsHander.timedMessages.get(0).arg1); - assertTrue(new KeyEventMatcher(first).matches(mInputEventsHander.timedMessages.get(0).obj)); - assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(1).what); - assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, - mInputEventsHander.timedMessages.get(1).arg1); - assertTrue(new KeyEventMatcher(second) - .matches(mInputEventsHander.timedMessages.get(1).obj)); + assertEquals(2, mInputEventsHandler.timedMessages.size()); + + Message m0 = getTimedMessage(mInputEventsHandler, 0); + assertEquals(SEND_FRAMEWORK_KEY_EVENT, m0.what); + assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m0.arg1); + assertTrue(new KeyEventMatcher(first).matches(m0.obj)); + + Message m1 = getTimedMessage(mInputEventsHandler, 1); + assertEquals(SEND_FRAMEWORK_KEY_EVENT, m1.what); + assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m1.arg1); + assertTrue(new KeyEventMatcher(second).matches(m1.obj)); + } + + private static Message getTimedMessage(MessageCapturingHandler handler, int i) { + return handler.timedMessages.get(i).first; + } + + private static boolean isTimeoutPending(MessageCapturingHandler handler) { + return handler.hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT); } private class KeyEventMatcher extends TypeSafeMatcher<KeyEvent> { @@ -581,18 +591,4 @@ public class KeyEventDispatcherTest { description.appendText("Key event matcher"); } } - - private class MessageCapturingHandler extends Handler { - List<Message> timedMessages = new ArrayList<>(); - - @Override - public boolean sendMessageAtTime(Message message, long uptimeMillis) { - timedMessages.add(Message.obtain(message)); - return super.sendMessageAtTime(message, uptimeMillis); - } - - public boolean isTimeoutPending() { - return hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT); - } - } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java index 851e22173420..9926a09dd105 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java @@ -28,7 +28,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.hamcrest.MockitoHamcrest.argThat; -import android.os.Looper; import android.view.KeyEvent; import androidx.test.runner.AndroidJUnit4; @@ -38,8 +37,8 @@ import com.android.server.policy.WindowManagerPolicy.WindowState; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; @@ -58,19 +57,18 @@ public class KeyboardInterceptorTest { @Mock AccessibilityManagerService mMockAms; @Mock WindowManagerPolicy mMockPolicy; - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() { MockitoAnnotations.initMocks(this); mInterceptor = new KeyboardInterceptor(mMockAms, mMockPolicy, mHandler); } + @After + public void tearDown() { + mHandler.removeAllMessages(); + } + + @Test public void whenNonspecialKeyArrives_withNothingInQueue_eventGoesToAms() { KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java index d6d21c63b1c5..c88b87328809 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java @@ -43,9 +43,9 @@ import android.graphics.Region; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.support.test.filters.FlakyTest; import android.view.MagnificationSpec; +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; @@ -55,8 +55,8 @@ import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks; import org.hamcrest.CoreMatchers; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -67,7 +67,6 @@ import org.mockito.stubbing.Answer; import java.util.Locale; @RunWith(AndroidJUnit4.class) -@FlakyTest public class MagnificationControllerTest { static final Rect INITIAL_MAGNIFICATION_BOUNDS = new Rect(0, 0, 100, 200); static final PointF INITIAL_MAGNIFICATION_BOUNDS_CENTER = new PointF( @@ -75,8 +74,10 @@ public class MagnificationControllerTest { static final PointF INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER = new PointF(25, 50); static final PointF INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(75, 150); static final Rect OTHER_MAGNIFICATION_BOUNDS = new Rect(100, 200, 500, 600); + static final Rect OTHER_MAGNIFICATION_BOUNDS_COMPAT = new Rect(50, 100, 450, 500); static final PointF OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(400, 500); static final Region INITIAL_MAGNIFICATION_REGION = new Region(INITIAL_MAGNIFICATION_BOUNDS); + static final Region OTHER_REGION_COMPAT = new Region(OTHER_MAGNIFICATION_BOUNDS_COMPAT); static final Region OTHER_REGION = new Region(OTHER_MAGNIFICATION_BOUNDS); static final int SERVICE_ID_1 = 1; static final int SERVICE_ID_2 = 2; @@ -91,25 +92,17 @@ public class MagnificationControllerTest { return mMagnificationController.handleMessage(msg); } }); - final ArgumentCaptor<MagnificationSpec> mMagnificationSpecCaptor = - ArgumentCaptor.forClass(MagnificationSpec.class); final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class); MagnificationController.SettingsBridge mMockSettingsBridge; - MagnificationController mMagnificationController; ValueAnimator.AnimatorUpdateListener mTargetAnimationListener; - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() { - when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper()); + Looper looper = InstrumentationRegistry.getContext().getMainLooper(); + // Pretending ID of the Thread associated with looper as main thread ID in controller + when(mMockContext.getMainLooper()).thenReturn(looper); Resources mockResources = mock(Resources.class); when(mMockContext.getResources()).thenReturn(mockResources); when(mockResources.getInteger(R.integer.config_longAnimTime)) @@ -136,6 +129,12 @@ public class MagnificationControllerTest { Mockito.reset(mMockValueAnimator); // Ignore other initialization } + @After + public void tearDown() { + mMessageCapturingHandler.removeAllMessages(); + } + + @Test public void testRegister_WindowManagerAndContextRegisterListeners() { mMagnificationController.register(); @@ -202,6 +201,7 @@ public class MagnificationControllerTest { final PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale); assertTrue(mMagnificationController .setScale(scale, center.x, center.y, false, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); final MagnificationSpec expectedSpec = getMagnificationSpec(scale, offsets); verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec))); @@ -219,6 +219,7 @@ public class MagnificationControllerTest { PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER; assertTrue(mMagnificationController .setScale(scale, pivotPoint.x, pivotPoint.y, true, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); // New center should be halfway between original center and pivot PointF newCenter = new PointF((pivotPoint.x + INITIAL_MAGNIFICATION_BOUNDS.centerX()) / 2, @@ -264,6 +265,7 @@ public class MagnificationControllerTest { PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER; assertTrue(mMagnificationController .setCenter(newCenter.x, newCenter.y, false, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale); MagnificationSpec expectedSpec = getMagnificationSpec(scale, expectedOffsets); @@ -284,6 +286,7 @@ public class MagnificationControllerTest { assertTrue(mMagnificationController.setScaleAndCenter(scale, newCenter.x, newCenter.y, true, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5); assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5); @@ -325,6 +328,7 @@ public class MagnificationControllerTest { assertTrue(mMagnificationController.setScaleAndCenter( MagnificationController.MAX_SCALE + 1.0f, newCenter.x, newCenter.y, false, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5); assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5); @@ -335,6 +339,7 @@ public class MagnificationControllerTest { assertTrue(mMagnificationController.setScaleAndCenter(0.5f, INITIAL_MAGNIFICATION_BOUNDS_CENTER.x, INITIAL_MAGNIFICATION_BOUNDS_CENTER.y, false, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); assertEquals(INITIAL_MAGNIFICATION_BOUNDS_CENTER.x, mMagnificationController.getCenterX(), 0.5); @@ -351,6 +356,7 @@ public class MagnificationControllerTest { // Off the edge to the top and left assertTrue(mMagnificationController.setScaleAndCenter( scale, -100f, -200f, false, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER; PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale); @@ -364,6 +370,7 @@ public class MagnificationControllerTest { assertTrue(mMagnificationController.setScaleAndCenter(scale, INITIAL_MAGNIFICATION_BOUNDS.right + 1, INITIAL_MAGNIFICATION_BOUNDS.bottom + 1, false, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER; newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale); assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5); @@ -391,12 +398,14 @@ public class MagnificationControllerTest { // First zoom in assertTrue(mMagnificationController .setScaleAndCenter(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); Mockito.reset(mMockWindowManager); PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER; PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale); mMagnificationController.offsetMagnifiedRegion( startOffsets.x - newOffsets.x, startOffsets.y - newOffsets.y, SERVICE_ID_1); + mMessageCapturingHandler.sendAllMessages(); MagnificationSpec expectedSpec = getMagnificationSpec(scale, newOffsets); verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec))); @@ -490,6 +499,7 @@ public class MagnificationControllerTest { public void testResetIfNeeded_doesWhatItSays() { mMagnificationController.register(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); reset(mMockAms); assertTrue(mMagnificationController.resetIfNeeded(false)); verify(mMockAms).notifyMagnificationChanged( @@ -507,6 +517,7 @@ public class MagnificationControllerTest { broadcastReceiverCaptor.capture(), (IntentFilter) anyObject()); BroadcastReceiver br = broadcastReceiverCaptor.getValue(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); br.onReceive(mMockContext, null); mMessageCapturingHandler.sendAllMessages(); assertFalse(mMagnificationController.isMagnifying()); @@ -517,6 +528,7 @@ public class MagnificationControllerTest { mMagnificationController.register(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); callbacks.onUserContextChanged(); mMessageCapturingHandler.sendAllMessages(); assertFalse(mMagnificationController.isMagnifying()); @@ -539,10 +551,11 @@ public class MagnificationControllerTest { // Going from a small region to a large one leads to no issues mMagnificationController.register(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); MagnificationSpec startSpec = getCurrentMagnificationSpec(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); Mockito.reset(mMockWindowManager); - callbacks.onMagnificationRegionChanged(OTHER_REGION); + callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT); mMessageCapturingHandler.sendAllMessages(); assertThat(getCurrentMagnificationSpec(), closeTo(startSpec)); verifyNoMoreInteractions(mMockWindowManager); @@ -553,11 +566,12 @@ public class MagnificationControllerTest { mMagnificationController.register(); PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER; float scale = 2.0f; + // setting animate parameter to true is differ from zoomIn2xToMiddle() mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1); MagnificationSpec startSpec = getCurrentMagnificationSpec(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); Mockito.reset(mMockWindowManager); - callbacks.onMagnificationRegionChanged(OTHER_REGION); + callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT); mMessageCapturingHandler.sendAllMessages(); assertThat(getCurrentMagnificationSpec(), closeTo(startSpec)); verifyNoMoreInteractions(mMockWindowManager); @@ -573,6 +587,7 @@ public class MagnificationControllerTest { PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER; float scale = 2.0f; mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1); + mMessageCapturingHandler.sendAllMessages(); MagnificationSpec startSpec = getCurrentMagnificationSpec(); verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(startSpec))); Mockito.reset(mMockWindowManager); @@ -597,8 +612,9 @@ public class MagnificationControllerTest { PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER; float scale = 2.0f; mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1); + mMessageCapturingHandler.sendAllMessages(); MagnificationSpec startSpec = getCurrentMagnificationSpec(); - when (mMockValueAnimator.isRunning()).thenReturn(true); + when(mMockValueAnimator.isRunning()).thenReturn(true); callbacks.onMagnificationRegionChanged(INITIAL_MAGNIFICATION_REGION); mMessageCapturingHandler.sendAllMessages(); @@ -616,6 +632,7 @@ public class MagnificationControllerTest { public void testRequestRectOnScreen_rectAlreadyOnScreen_doesNothing() { mMagnificationController.register(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); MagnificationSpec startSpec = getCurrentMagnificationSpec(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); Mockito.reset(mMockWindowManager); @@ -631,6 +648,7 @@ public class MagnificationControllerTest { public void testRequestRectOnScreen_rectCanFitOnScreen_pansToGetRectOnScreen() { mMagnificationController.register(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); Mockito.reset(mMockWindowManager); callbacks.onRectangleOnScreenRequested(0, 0, 1, 1); @@ -644,6 +662,7 @@ public class MagnificationControllerTest { public void testRequestRectOnScreen_garbageInput_doesNothing() { mMagnificationController.register(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); MagnificationSpec startSpec = getCurrentMagnificationSpec(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); Mockito.reset(mMockWindowManager); @@ -653,12 +672,12 @@ public class MagnificationControllerTest { verifyNoMoreInteractions(mMockWindowManager); } - @Test public void testRequestRectOnScreen_rectTooWide_pansToGetStartOnScreenBasedOnLocale() { Locale.setDefault(new Locale("en", "us")); mMagnificationController.register(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); MagnificationSpec startSpec = getCurrentMagnificationSpec(); Mockito.reset(mMockWindowManager); @@ -685,6 +704,7 @@ public class MagnificationControllerTest { public void testRequestRectOnScreen_rectTooTall_pansMinimumToGetTopOnScreen() { mMagnificationController.register(); zoomIn2xToMiddle(); + mMessageCapturingHandler.sendAllMessages(); MagnificationCallbacks callbacks = getMagnificationCallbacks(); MagnificationSpec startSpec = getCurrentMagnificationSpec(); Mockito.reset(mMockWindowManager); @@ -708,6 +728,7 @@ public class MagnificationControllerTest { assertTrue(mMagnificationController.setScaleAndCenter(scale, firstCenter.x, firstCenter.y, true, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); assertEquals(firstCenter.x, mMagnificationController.getCenterX(), 0.5); assertEquals(firstCenter.y, mMagnificationController.getCenterY(), 0.5); @@ -736,6 +757,7 @@ public class MagnificationControllerTest { scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale)); assertTrue(mMagnificationController.setCenter( newCenter.x, newCenter.y, true, SERVICE_ID_1)); + mMessageCapturingHandler.sendAllMessages(); // Animation should have been restarted verify(mMockValueAnimator, times(2)).start(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java index e3ee47f3421d..e2b517f875db 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java @@ -16,11 +16,13 @@ package com.android.server.accessibility; -import android.app.Notification; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.util.Pair; +import androidx.test.InstrumentationRegistry; + import java.util.ArrayList; import java.util.List; @@ -34,13 +36,22 @@ public class MessageCapturingHandler extends Handler { Handler.Callback mCallback; public MessageCapturingHandler(Handler.Callback callback) { + this(InstrumentationRegistry.getContext().getMainLooper(), callback); + } + + public MessageCapturingHandler(Looper looper, Callback callback) { + super(looper); mCallback = callback; } + /** + * Holding messages in queue, but never dispatching. + * @see #removeAllMessages() + */ @Override public boolean sendMessageAtTime(Message message, long uptimeMillis) { timedMessages.add(new Pair<>(Message.obtain(message), uptimeMillis)); - return super.sendMessageAtTime(message, uptimeMillis); + return super.sendMessageAtTime(message, Long.MAX_VALUE); } public void setCallback(Handler.Callback callback) { @@ -67,6 +78,22 @@ public class MessageCapturingHandler extends Handler { removeStaleMessages(); } + /** + * Clear messages sent from this handler in queue. + * <p> + * If main looper is used, this method should be called in tear down function + * to ensure messages isolation between test cases. + * </p> + */ + public void removeAllMessages() { + if (hasMessages()) { + for (int i = 0; i < timedMessages.size(); i++) { + Message message = timedMessages.get(i).first; + removeMessages(message.what, message.obj); + } + } + } + public boolean hasMessages() { removeStaleMessages(); return !timedMessages.isEmpty(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java index 5f0fa874b7da..2cba9d022866 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java @@ -43,7 +43,6 @@ import android.accessibilityservice.GestureDescription.TouchPoint; import android.accessibilityservice.IAccessibilityServiceClient; import android.graphics.Point; import android.os.Handler; -import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; @@ -57,8 +56,8 @@ import androidx.test.runner.AndroidJUnit4; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -127,13 +126,6 @@ public class MotionEventInjectorTest { Matcher<MotionEvent> mIsClickDown; Matcher<MotionEvent> mIsClickUp; - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() { mMessageCapturingHandler = new MessageCapturingHandler(new Handler.Callback() { @@ -172,6 +164,12 @@ public class MotionEventInjectorTest { hasTimeFromDown(CLICK_DURATION)); } + @After + public void tearDown() { + mMessageCapturingHandler.removeAllMessages(); + } + + @Test public void testInjectEvents_shouldEmergeInOrderWithCorrectTiming() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java index c47885f0c632..2645461b5912 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java @@ -16,12 +16,14 @@ package com.android.server.accessibility; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import android.content.Context; import android.graphics.PointF; import android.os.SystemClock; +import android.testing.DexmakerShareClassLoaderRule; import android.util.DebugUtils; import android.view.InputDevice; import android.view.MotionEvent; @@ -30,6 +32,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -66,6 +69,11 @@ public class TouchExplorerTest { private TouchExplorer mTouchExplorer; private long mLastDownTime = Integer.MIN_VALUE; + // mock package-private AccessibilityGestureDetector class + @Rule + public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = + new DexmakerShareClassLoaderRule(); + /** * {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object * is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation @@ -93,8 +101,9 @@ public class TouchExplorerTest { public void setUp() { Context context = InstrumentationRegistry.getContext(); AccessibilityManagerService ams = new AccessibilityManagerService(context); + AccessibilityGestureDetector detector = mock(AccessibilityGestureDetector.class); mCaptor = new EventCaptor(); - mTouchExplorer = new TouchExplorer(context, ams); + mTouchExplorer = new TouchExplorer(context, ams, detector); mTouchExplorer.setNext(mCaptor); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java index 8853db2a8558..8e09d6001310 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java @@ -32,13 +32,12 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.IBinder; -import android.os.Looper; import android.view.accessibility.AccessibilityEvent; import com.android.server.wm.WindowManagerInternal; +import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -66,13 +65,6 @@ public class UiAutomationManagerTest { @Mock IAccessibilityServiceClient mMockAccessibilityServiceClient; @Mock IBinder mMockServiceAsBinder; - @BeforeClass - public static void oneTimeInitialization() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -88,6 +80,12 @@ public class UiAutomationManagerTest { mMessageCapturingHandler = new MessageCapturingHandler(null); } + @After + public void tearDown() { + mMessageCapturingHandler.removeAllMessages(); + } + + @Test public void isRunning_returnsTrueOnlyWhenRunning() { assertFalse(mUiAutomationManager.isUiAutomationRunningLocked()); diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java index 8a83518705f8..910d4339e568 100644 --- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.inputmethod; +package com.android.server.inputmethod; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -23,15 +23,15 @@ import static org.junit.Assert.assertTrue; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; -import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl; -import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; -import com.android.internal.inputmethod.InputMethodUtils; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl; +import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java index 3064afaeaab1..4d0278fe7a07 100644 --- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.inputmethod; +package com.android.server.inputmethod; import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR; import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS; @@ -37,13 +37,14 @@ import android.content.res.Resources; import android.os.Build; import android.os.LocaleList; import android.os.Parcel; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; @@ -71,15 +72,11 @@ public class InputMethodUtilsTest { private static final Locale LOCALE_FR = new Locale("fr"); private static final Locale LOCALE_FR_CA = new Locale("fr", "CA"); private static final Locale LOCALE_HI = new Locale("hi"); - private static final Locale LOCALE_JA = new Locale("ja"); private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN"); private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW"); private static final Locale LOCALE_IN = new Locale("in"); private static final Locale LOCALE_ID = new Locale("id"); - private static final Locale LOCALE_TH = new Locale("ht"); - private static final Locale LOCALE_TH_TH = new Locale("ht", "TH"); - private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH"); private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; private static final String SUBTYPE_MODE_VOICE = "voice"; private static final String SUBTYPE_MODE_HANDWRITING = "handwriting"; @@ -1087,122 +1084,6 @@ public class InputMethodUtilsTest { } @Test - public void testGetSuitableLocalesForSpellChecker() throws Exception { - { - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US); - assertEquals(3, locales.size()); - assertEquals(LOCALE_EN_US, locales.get(0)); - assertEquals(LOCALE_EN_GB, locales.get(1)); - assertEquals(LOCALE_EN, locales.get(2)); - } - - { - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB); - assertEquals(3, locales.size()); - assertEquals(LOCALE_EN_GB, locales.get(0)); - assertEquals(LOCALE_EN_US, locales.get(1)); - assertEquals(LOCALE_EN, locales.get(2)); - } - - { - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN); - assertEquals(3, locales.size()); - assertEquals(LOCALE_EN, locales.get(0)); - assertEquals(LOCALE_EN_US, locales.get(1)); - assertEquals(LOCALE_EN_GB, locales.get(2)); - } - - { - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN); - assertEquals(4, locales.size()); - assertEquals(LOCALE_EN_IN, locales.get(0)); - assertEquals(LOCALE_EN_US, locales.get(1)); - assertEquals(LOCALE_EN_GB, locales.get(2)); - assertEquals(LOCALE_EN, locales.get(3)); - } - - { - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP); - assertEquals(5, locales.size()); - assertEquals(LOCALE_JA_JP, locales.get(0)); - assertEquals(LOCALE_JA, locales.get(1)); - assertEquals(LOCALE_EN_US, locales.get(2)); - assertEquals(LOCALE_EN_GB, locales.get(3)); - assertEquals(Locale.ENGLISH, locales.get(4)); - } - - // Test 3-letter language code. - { - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH); - assertEquals(5, locales.size()); - assertEquals(LOCALE_FIL_PH, locales.get(0)); - assertEquals(LOCALE_FIL, locales.get(1)); - assertEquals(LOCALE_EN_US, locales.get(2)); - assertEquals(LOCALE_EN_GB, locales.get(3)); - assertEquals(Locale.ENGLISH, locales.get(4)); - } - - // Test variant. - { - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH); - assertEquals(6, locales.size()); - assertEquals(LOCALE_TH_TH_TH, locales.get(0)); - assertEquals(LOCALE_TH_TH, locales.get(1)); - assertEquals(LOCALE_TH, locales.get(2)); - assertEquals(LOCALE_EN_US, locales.get(3)); - assertEquals(LOCALE_EN_GB, locales.get(4)); - assertEquals(Locale.ENGLISH, locales.get(5)); - } - - // Test Locale extension. - { - final Locale localeWithoutVariant = LOCALE_JA_JP; - final Locale localeWithVariant = new Locale.Builder() - .setLocale(LOCALE_JA_JP) - .setExtension('x', "android") - .build(); - assertFalse(localeWithoutVariant.equals(localeWithVariant)); - - final ArrayList<Locale> locales = - InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant); - assertEquals(5, locales.size()); - assertEquals(LOCALE_JA_JP, locales.get(0)); - assertEquals(LOCALE_JA, locales.get(1)); - assertEquals(LOCALE_EN_US, locales.get(2)); - assertEquals(LOCALE_EN_GB, locales.get(3)); - assertEquals(Locale.ENGLISH, locales.get(4)); - } - } - - @Test - public void testConstructLocaleFromString() throws Exception { - assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en")); - assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US")); - assertEquals(new Locale("en", "US", "POSIX"), - InputMethodUtils.constructLocaleFromString("en_US_POSIX")); - - // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not - // support three letter language codes, and used "tl" (Tagalog) as the language string for - // "fil" (Filipino). - assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl")); - assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH")); - assertEquals(new Locale("fil", "PH", "POSIX"), - InputMethodUtils.constructLocaleFromString("tl_PH_POSIX")); - - // So far rejecting an invalid/unexpected locale string is out of the scope of this method. - assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a")); - assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c")); - assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US")); - } - - @Test public void testIsSoftInputModeStateVisibleAllowed() { // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always // allowed, regardless of the focused view state. diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java index 549511a420eb..3fc0e4fa4a2c 100644 --- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package com.android.internal.inputmethod; +package com.android.server.inputmethod; import static org.junit.Assert.assertEquals; import android.os.LocaleList; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java b/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java index 351852710773..f80afb2ebbbf 100644 --- a/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java +++ b/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.textservice; +package com.android.server.textservices; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyInt; @@ -25,8 +25,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java b/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java new file mode 100644 index 000000000000..3766d24b93d0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.textservices; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Locale; + +public class LocaleUtilsTest { + private static final Locale LOCALE_EN = new Locale("en"); + private static final Locale LOCALE_EN_US = new Locale("en", "US"); + private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); + private static final Locale LOCALE_EN_IN = new Locale("en", "IN"); + private static final Locale LOCALE_FIL = new Locale("fil"); + private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH"); + private static final Locale LOCALE_JA = new Locale("ja"); + private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); + private static final Locale LOCALE_TH = new Locale("ht"); + private static final Locale LOCALE_TH_TH = new Locale("ht", "TH"); + private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH"); + + @Test + public void testGetSuitableLocalesForSpellChecker() throws Exception { + { + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US); + assertEquals(3, locales.size()); + assertEquals(LOCALE_EN_US, locales.get(0)); + assertEquals(LOCALE_EN_GB, locales.get(1)); + assertEquals(LOCALE_EN, locales.get(2)); + } + + { + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB); + assertEquals(3, locales.size()); + assertEquals(LOCALE_EN_GB, locales.get(0)); + assertEquals(LOCALE_EN_US, locales.get(1)); + assertEquals(LOCALE_EN, locales.get(2)); + } + + { + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN); + assertEquals(3, locales.size()); + assertEquals(LOCALE_EN, locales.get(0)); + assertEquals(LOCALE_EN_US, locales.get(1)); + assertEquals(LOCALE_EN_GB, locales.get(2)); + } + + { + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN); + assertEquals(4, locales.size()); + assertEquals(LOCALE_EN_IN, locales.get(0)); + assertEquals(LOCALE_EN_US, locales.get(1)); + assertEquals(LOCALE_EN_GB, locales.get(2)); + assertEquals(LOCALE_EN, locales.get(3)); + } + + { + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP); + assertEquals(5, locales.size()); + assertEquals(LOCALE_JA_JP, locales.get(0)); + assertEquals(LOCALE_JA, locales.get(1)); + assertEquals(LOCALE_EN_US, locales.get(2)); + assertEquals(LOCALE_EN_GB, locales.get(3)); + assertEquals(Locale.ENGLISH, locales.get(4)); + } + + // Test 3-letter language code. + { + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH); + assertEquals(5, locales.size()); + assertEquals(LOCALE_FIL_PH, locales.get(0)); + assertEquals(LOCALE_FIL, locales.get(1)); + assertEquals(LOCALE_EN_US, locales.get(2)); + assertEquals(LOCALE_EN_GB, locales.get(3)); + assertEquals(Locale.ENGLISH, locales.get(4)); + } + + // Test variant. + { + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH); + assertEquals(6, locales.size()); + assertEquals(LOCALE_TH_TH_TH, locales.get(0)); + assertEquals(LOCALE_TH_TH, locales.get(1)); + assertEquals(LOCALE_TH, locales.get(2)); + assertEquals(LOCALE_EN_US, locales.get(3)); + assertEquals(LOCALE_EN_GB, locales.get(4)); + assertEquals(Locale.ENGLISH, locales.get(5)); + } + + // Test Locale extension. + { + final Locale localeWithoutVariant = LOCALE_JA_JP; + final Locale localeWithVariant = new Locale.Builder() + .setLocale(LOCALE_JA_JP) + .setExtension('x', "android") + .build(); + assertFalse(localeWithoutVariant.equals(localeWithVariant)); + + final ArrayList<Locale> locales = + LocaleUtils.getSuitableLocalesForSpellChecker(localeWithVariant); + assertEquals(5, locales.size()); + assertEquals(LOCALE_JA_JP, locales.get(0)); + assertEquals(LOCALE_JA, locales.get(1)); + assertEquals(LOCALE_EN_US, locales.get(2)); + assertEquals(LOCALE_EN_GB, locales.get(3)); + assertEquals(Locale.ENGLISH, locales.get(4)); + } + } +} 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 9fa5ba42204f..ea44279b46a9 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java @@ -109,4 +109,22 @@ public class TaskStackContainersTests extends WindowTestsBase { assertEquals(taskStackContainer.mChildren.get(stackPos), stack1); assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack); } + + @Test + public void testDisplayPositionWithPinnedStack() { + // The display contains pinned stack that was added in {@link #setUp}. + final TaskStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task task = createTaskInStack(stack, 0 /* userId */); + + // Add another display at top. + sWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(), + false /* includingParents */); + + // Move the task of {@code mDisplayContent} to top. + stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */); + final int indexOfDisplayWithPinnedStack = sWm.mRoot.mChildren.indexOf(mDisplayContent); + + assertEquals("The testing DisplayContent should be moved to top with task", + sWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index a1b3b988397c..519b3ae7bc46 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3453,4 +3453,46 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // yay } } + + @Test + public void testRemoveForegroundServiceFlagFromNotification_enqueued() { + Notification n = new Notification.Builder(mContext, "").build(); + n.flags |= FLAG_FOREGROUND_SERVICE; + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0, + n, new UserHandle(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addEnqueuedNotification(r); + + mInternalService.removeForegroundServiceFlagFromNotification( + PKG, r.sbn.getId(), r.sbn.getUserId()); + + waitForIdle(); + + verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); + } + + @Test + public void testRemoveForegroundServiceFlagFromNotification_posted() { + Notification n = new Notification.Builder(mContext, "").build(); + n.flags |= FLAG_FOREGROUND_SERVICE; + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0, + n, new UserHandle(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addNotification(r); + + mInternalService.removeForegroundServiceFlagFromNotification( + PKG, r.sbn.getId(), r.sbn.getUserId()); + + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); + + assertEquals(0, captor.getValue().getNotification().flags); + } } diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index 589bcdc14871..cf47ad3520ec 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -40,6 +40,7 @@ import com.android.internal.util.dump.DualDumpOutputStream; import com.android.server.usb.descriptors.UsbDescriptor; import com.android.server.usb.descriptors.UsbDescriptorParser; import com.android.server.usb.descriptors.UsbDeviceDescriptor; +import com.android.server.usb.descriptors.UsbInterfaceDescriptor; import com.android.server.usb.descriptors.report.TextReportCanvas; import com.android.server.usb.descriptors.tree.UsbDescriptorsTree; @@ -352,8 +353,6 @@ public class UsbHostManager { } return false; } - UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors); - logUsbDevice(parser); if (isBlackListed(deviceClass, deviceSubclass)) { if (DEBUG) { @@ -362,6 +361,15 @@ public class UsbHostManager { return false; } + UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors); + if (deviceClass == UsbConstants.USB_CLASS_PER_INTERFACE + && !checkUsbInterfacesBlackListed(parser)) { + return false; + } + + // Potentially can block as it may read data from the USB device. + logUsbDevice(parser); + synchronized (mLock) { if (mDevices.get(deviceAddress) != null) { Slog.w(TAG, "device already on mDevices list: " + deviceAddress); @@ -513,6 +521,29 @@ public class UsbHostManager { } } + private boolean checkUsbInterfacesBlackListed(UsbDescriptorParser parser) { + // Device class needs to be obtained through the device interface. Ignore device only + // if ALL interfaces are black-listed. + boolean shouldIgnoreDevice = false; + for (UsbDescriptor descriptor: parser.getDescriptors()) { + if (!(descriptor instanceof UsbInterfaceDescriptor)) { + continue; + } + UsbInterfaceDescriptor iface = (UsbInterfaceDescriptor) descriptor; + shouldIgnoreDevice = isBlackListed(iface.getUsbClass(), iface.getUsbSubclass()); + if (!shouldIgnoreDevice) { + break; + } + } + if (shouldIgnoreDevice) { + if (DEBUG) { + Slog.d(TAG, "usb interface class is black listed"); + } + return false; + } + return true; + } + private native void monitorUsbHostBus(); private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress); } diff --git a/startop/scripts/app_startup/force_compiler_filter b/startop/scripts/app_startup/force_compiler_filter new file mode 100755 index 000000000000..78e915bb4d53 --- /dev/null +++ b/startop/scripts/app_startup/force_compiler_filter @@ -0,0 +1,173 @@ +#!/bin/bash +# +# Copyright 2018, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Forces an application APK to be compiled (by ART's dex2oat) +# with a specific compiler filter. +# +# Example usage: +# $> ./force_compiler_filter -p com.google.android.apps.maps -c speed-profile +# +# (The application may be started/stopped as a side effect) +# + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source "$DIR/lib/common" + +usage() { + cat <<EOF +Usage: $(basename $0) [OPTION]... + + Required: + -p, --package package of the app to recompile + -c, --compiler-filter override the compiler filter if set (default none) + valid options are listed by: adb shell cmd package, under compile -m + + Optional: + -a, --activity activity of the app to recompile + -h, --help usage information (this) + -v, --verbose enable extra verbose printing + -w, --wait_time how long to wait for app startup (default 10) in seconds +EOF +} + +wait_time="10" # seconds + +parse_arguments() { + while [[ $# -gt 0 ]]; do + case "$1" in + -a|--activity) + activity="$2" + shift + ;; + -h|--help) + usage + exit 0 + ;; + -p|--package) + package="$2" + shift + ;; + -w|--wait_time) + wait_time="$2" + shift + ;; + -c|--compiler-filter) + compiler_filter="$2" + shift + ;; + -v|--verbose) + verbose="y" + ;; + esac + shift + done + + if [[ -z "$compiler_filter" ]]; then + echo "Missing required --compiler-filter" >&2 + echo "" + usage + exit 1 + fi + if [[ -z "$package" ]]; then + echo "Missing required --package" >&2 + echo "" + usage + exit 1 + fi + + if [[ "$activity" == "" ]]; then + activity="$(get_activity_name "$package")" + if [[ "$activity" == "" ]]; then + echo "Activity name could not be found, invalid package name?" 1>&2 + exit 1 + else + verbose_print "Activity name inferred: " "$activity" + fi + fi +} + +get_activity_name() { + local package="$1" + local action_key="android.intent.action.MAIN:" + + local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")" + verbose_print $activity_line + IFS="/" read -a array <<< "$activity_line" + local activity_name="${array[1]}" + echo "$activity_name" + #adb shell am start "$package/$activity_name" +} + +remote_pidof() { + local procname="$1" + adb shell ps | grep "$procname" | awk '{print $2;}' +} + +remote_pkill() { + local procname="$1" + shift + + local the_pids=$(remote_pidof "$procname") + local pid + + for pid in $the_pids; do + verbose_print adb shell kill "$@" "$pid" + adb shell kill "$@" "$pid" + done +} + +force_package_compilation() { + local arg_compiler_filter="$1" + local arg_package="$2" + + if [[ $arg_compiler_filter == speed-profile ]]; then + # Force the running app to dump its profiles to disk. + remote_pkill "$arg_package" -SIGUSR1 + sleep 1 # give some time for above to complete. + fi + + adb shell cmd package compile -m "$arg_compiler_filter" -f "$arg_package" +} + +main() { + parse_arguments "$@" + + if [[ $compiler_filter == speed-profile ]]; then + # screen needs to be unlocked in order to run an app + "$DIR"/unlock_screen + + am_output="$(adb shell am start -S -W "$package"/"$activity")" + if [[ $? -ne 0 ]]; then + echo "am start failed" >&2 + exit 1 + fi + + verbose_print "$am_output" + # give some time for app startup to complete. + # this is supposed to be an upper bound for measuring startup time. + sleep "$wait_time" + fi + + force_package_compilation "$compiler_filter" "$package" + + # kill the application to ensure next time it's started, + # it picks up the correct compilation filter. + adb shell am force-stop "$package" + remote_pkill "$package" +} + +main "$@" diff --git a/startop/scripts/app_startup/query_compiler_filter.py b/startop/scripts/app_startup/query_compiler_filter.py new file mode 100755 index 000000000000..dc97c6641f35 --- /dev/null +++ b/startop/scripts/app_startup/query_compiler_filter.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +# +# Copyright 2018, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# +# Query the current compiler filter for an application by its package name. +# (By parsing the results of the 'adb shell dumpsys package $package' command). +# The output is a string "$compilation_filter $compilation_reason $isa". +# +# See --help for more details. +# +# ----------------------------------- +# +# Sample usage: +# +# $> ./query_compiler_filter.py --package com.google.android.calculator +# speed-profile unknown arm64 +# + +import argparse +import sys +import re + +# TODO: refactor this with a common library file with analyze_metrics.py +import app_startup_runner +from app_startup_runner import _debug_print +from app_startup_runner import execute_arbitrary_command + +from typing import List, NamedTuple, Iterable + +_DEBUG_FORCE = None # Ignore -d/--debug if this is not none. + +def parse_options(argv: List[str] = None): + """Parse command line arguments and return an argparse Namespace object.""" + parser = argparse.ArgumentParser(description="Query the compiler filter for a package.") + # argparse considers args starting with - and -- optional in --help, even though required=True. + # by using a named argument group --help will clearly say that it's required instead of optional. + required_named = parser.add_argument_group('required named arguments') + required_named.add_argument('-p', '--package', action='store', dest='package', help='package of the application', required=True) + + # optional arguments + # use a group here to get the required arguments to appear 'above' the optional arguments in help. + optional_named = parser.add_argument_group('optional named arguments') + optional_named.add_argument('-i', '--isa', '--instruction-set', action='store', dest='instruction_set', help='which instruction set to select. defaults to the first one available if not specified.', choices=('arm64', 'arm', 'x86_64', 'x86')) + optional_named.add_argument('-s', '--simulate', dest='simulate', action='store_true', help='Print which commands will run, but don\'t run the apps') + optional_named.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output') + + return parser.parse_args(argv) + +def remote_dumpsys_package(package: str, simulate: bool) -> str: + # --simulate is used for interactive debugging/development, but also for the unit test. + if simulate: + return """ +Dexopt state: + [%s] + path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk + arm64: [status=speed-profile] [reason=unknown] + path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk + arm: [status=speed] [reason=first-boot] + path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk + x86: [status=quicken] [reason=install] +""" %(package, package, package, package) + + code, res = execute_arbitrary_command(['adb', 'shell', 'dumpsys', 'package', package], simulate=False, timeout=5) + if code: + return res + else: + raise AssertionError("Failed to dumpsys package, errors = %s", res) + +ParseTree = NamedTuple('ParseTree', [('label', str), ('children', List['ParseTree'])]) +DexoptState = ParseTree # With the Dexopt state: label +ParseResult = NamedTuple('ParseResult', [('remainder', List[str]), ('tree', ParseTree)]) + +def find_parse_subtree(parse_tree: ParseTree, match_regex: str) -> ParseTree: + if re.match(match_regex, parse_tree.label): + return parse_tree + + for node in parse_tree.children: + res = find_parse_subtree(node, match_regex) + if res: + return res + + return None + +def find_parse_children(parse_tree: ParseTree, match_regex: str) -> Iterable[ParseTree]: + for node in parse_tree.children: + if re.match(match_regex, node.label): + yield node + +def parse_tab_subtree(label: str, str_lines: List[str], separator=' ', indent=-1) -> ParseResult: + children = [] + + get_indent_level = lambda line: len(line) - len(line.lstrip()) + + line_num = 0 + + keep_going = True + while keep_going: + keep_going = False + + for line_num in range(len(str_lines)): + line = str_lines[line_num] + current_indent = get_indent_level(line) + + _debug_print("INDENT=%d, LINE=%s" %(current_indent, line)) + + current_label = line.lstrip() + + # skip empty lines + if line.lstrip() == "": + continue + + if current_indent > indent: + parse_result = parse_tab_subtree(current_label, str_lines[line_num+1::], separator, current_indent) + str_lines = parse_result.remainder + children.append(parse_result.tree) + keep_going = True + else: + # current_indent <= indent + keep_going = False + + break + + new_remainder = str_lines[line_num::] + _debug_print("NEW REMAINDER: ", new_remainder) + + parse_tree = ParseTree(label, children) + return ParseResult(new_remainder, parse_tree) + +def parse_tab_tree(str_tree: str, separator=' ', indentation_level=-1) -> ParseTree: + + label = None + lst = [] + + line_num = 0 + line_lst = str_tree.split("\n") + + return parse_tab_subtree("", line_lst, separator, indentation_level).tree + +def parse_dexopt_state(dumpsys_tree: ParseTree) -> DexoptState: + res = find_parse_subtree(dumpsys_tree, "Dexopt(\s+)state[:]?") + if not res: + raise AssertionError("Could not find the Dexopt state") + return res + +def find_first_compiler_filter(dexopt_state: DexoptState, package: str, instruction_set: str) -> str: + lst = find_all_compiler_filters(dexopt_state, package) + + _debug_print("all compiler filters: ", lst) + + for compiler_filter_info in lst: + if not instruction_set: + return compiler_filter_info + + if compiler_filter_info.isa == instruction_set: + return compiler_filter_info + + return None + +CompilerFilterInfo = NamedTuple('CompilerFilterInfo', [('isa', str), ('status', str), ('reason', str)]) + +def find_all_compiler_filters(dexopt_state: DexoptState, package: str) -> List[CompilerFilterInfo]: + + lst = [] + package_tree = find_parse_subtree(dexopt_state, re.escape("[%s]" %package)) + + if not package_tree: + raise AssertionError("Could not find any package subtree for package %s" %(package)) + + _debug_print("package tree: ", package_tree) + + for path_tree in find_parse_children(package_tree, "path: "): + _debug_print("path tree: ", path_tree) + + matchre = re.compile("([^:]+):\s+\[status=([^\]]+)\]\s+\[reason=([^\]]+)\]") + + for isa_node in find_parse_children(path_tree, matchre): + + matches = re.match(matchre, isa_node.label).groups() + + info = CompilerFilterInfo(*matches) + lst.append(info) + + return lst + +def main() -> int: + opts = parse_options() + app_startup_runner._debug = opts.debug + if _DEBUG_FORCE is not None: + app_startup_runner._debug = _DEBUG_FORCE + _debug_print("parsed options: ", opts) + + # Note: This can often 'fail' if the package isn't actually installed. + package_dumpsys = remote_dumpsys_package(opts.package, opts.simulate) + _debug_print("package dumpsys: ", package_dumpsys) + dumpsys_parse_tree = parse_tab_tree(package_dumpsys, package_dumpsys) + _debug_print("parse tree: ", dumpsys_parse_tree) + dexopt_state = parse_dexopt_state(dumpsys_parse_tree) + + filter = find_first_compiler_filter(dexopt_state, opts.package, opts.instruction_set) + + if filter: + print(filter.status, end=' ') + print(filter.reason, end=' ') + print(filter.isa) + else: + print("ERROR: Could not find any compiler-filter for package %s, isa %s" %(opts.package, opts.instruction_set), file=sys.stderr) + return 1 + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/startop/scripts/app_startup/query_compiler_filter_test.py b/startop/scripts/app_startup/query_compiler_filter_test.py new file mode 100755 index 000000000000..a751a43d1d6c --- /dev/null +++ b/startop/scripts/app_startup/query_compiler_filter_test.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# +# Copyright 2018, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" +Unit tests for the query_compiler_filter.py script. + +Install: + $> sudo apt-get install python3-pytest ## OR + $> pip install -U pytest +See also https://docs.pytest.org/en/latest/getting-started.html + +Usage: + $> ./query_compiler_filter.py + $> pytest query_compiler_filter.py + $> python -m pytest query_compiler_filter.py + +See also https://docs.pytest.org/en/latest/usage.html +""" + +# global imports +from contextlib import contextmanager +import io +import shlex +import sys +import typing + +# pip imports +import pytest + +# local imports +import query_compiler_filter as qcf + +@contextmanager +def redirect_stdout_stderr(): + """Redirect stdout/stderr to a new StringIO for duration of context.""" + old_stdout = sys.stdout + old_stderr = sys.stderr + new_stdout = io.StringIO() + sys.stdout = new_stdout + new_stderr = io.StringIO() + sys.stderr = new_stderr + try: + yield (new_stdout, new_stderr) + finally: + sys.stdout = old_stdout + sys.stderr = old_stderr + # Seek back to the beginning so we can read whatever was written into it. + new_stdout.seek(0) + new_stderr.seek(0) + +@contextmanager +def replace_argv(argv): + """ Temporarily replace argv for duration of this context.""" + old_argv = sys.argv + sys.argv = [sys.argv[0]] + argv + try: + yield + finally: + sys.argv = old_argv + +def exec_main(argv): + """Run the query_compiler_filter main function with the provided arguments. + + Returns the stdout result when successful, assertion failure otherwise. + """ + try: + with redirect_stdout_stderr() as (the_stdout, the_stderr): + with replace_argv(argv): + code = qcf.main() + assert 0 == code, the_stderr.readlines() + + all_lines = the_stdout.readlines() + return "".join(all_lines) + finally: + the_stdout.close() + the_stderr.close() + +def test_query_compiler_filter(): + # no --instruction-set specified: provide whatever was the 'first' filter. + assert exec_main(['--simulate', + '--package', 'com.google.android.apps.maps']) == \ + "speed-profile unknown arm64\n" + + # specifying an instruction set finds the exact compiler filter match. + assert exec_main(['--simulate', + '--package', 'com.google.android.apps.maps', + '--instruction-set', 'arm64']) == \ + "speed-profile unknown arm64\n" + + assert exec_main(['--simulate', + '--package', 'com.google.android.apps.maps', + '--instruction-set', 'arm']) == \ + "speed first-boot arm\n" + + assert exec_main(['--simulate', + '--debug', + '--package', 'com.google.android.apps.maps', + '--instruction-set', 'x86']) == \ + "quicken install x86\n" + +if __name__ == '__main__': + pytest.main() diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch index 1ff5fc64116f..ce63ff958613 100755 --- a/startop/scripts/app_startup/run_app_with_prefetch +++ b/startop/scripts/app_startup/run_app_with_prefetch @@ -92,8 +92,7 @@ parse_arguments() { shift ;; --compiler-filter) - # ignore any '--compiler-filter xyz' settings. - # FIXME: app_startup_runner.py should not be passing this flag. + compiler_filter="$2" shift ;; *) @@ -194,9 +193,6 @@ if [[ $? -ne 0 ]]; then fi verbose_print "Package was in path '$package_path'" - - - keep_application_trace_file=n application_trace_file_path="$package_path/TraceFile.pb" trace_file_directory="$package_path" @@ -286,6 +282,47 @@ perform_aot_cleanup() { fi } +configure_compiler_filter() { + local the_compiler_filter="$1" + local the_package="$2" + local the_activity="$3" + + if [[ -z $the_compiler_filter ]]; then + verbose_print "No --compiler-filter specified, don't need to force it." + return 0 + fi + + local current_compiler_filter_info="$("$DIR"/query_compiler_filter.py --package "$the_package")" + local res=$? + if [[ $res -ne 0 ]]; then + return $res + fi + + local current_compiler_filter + local current_reason + local current_isa + read current_compiler_filter current_reason current_isa <<< "$current_compiler_filter_info" + + verbose_print "Compiler Filter="$current_compiler_filter "Reason="$current_reason "Isa="$current_isa + + # Don't trust reasons that aren't 'unknown' because that means we didn't manually force the compilation filter. + # (e.g. if any automatic system-triggered compilations are not unknown). + if [[ $current_reason != "unknown" ]] || [[ $current_compiler_filter != $the_compiler_filter ]]; then + verbose_print "$DIR"/force_compiler_filter --compiler-filter "$the_compiler_filter" --package "$the_package" --activity "$the_activity" + "$DIR"/force_compiler_filter --compiler-filter "$the_compiler_filter" --package "$the_package" --activity "$the_activity" + res=$? + else + verbose_print "Queried compiler-filter matched requested compiler-filter, skip forcing." + res=0 + fi + + return $res +} + +# Ensure the APK is currently compiled with whatever we passed in via --compiler-filter. +# No-op if this option was not passed in. +configure_compiler_filter "$compiler_filter" "$package" "$activity" || exit 1 + # TODO: This loop logic could probably be moved into app_startup_runner.py for ((i=0;i<count;++i)) do verbose_print "==========================================" diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index 8b0211e4b991..3ad0f0cc56fe 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -18,6 +18,7 @@ package android.telecom; import android.annotation.UnsupportedAppUsage; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -118,7 +119,7 @@ public final class ParcelableCall implements Parcelable { } /** The unique ID of the call. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public String getId() { return mId; } diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java index 279804e6aa30..097e3529dead 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -19,6 +19,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; @@ -43,7 +44,7 @@ import java.util.Objects; public final class PhoneAccountHandle implements Parcelable { @UnsupportedAppUsage private final ComponentName mComponentName; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final String mId; private final UserHandle mUserHandle; diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index ed84788e21ac..722df671bad1 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -30,6 +30,7 @@ import android.database.ContentObserver; import android.database.Cursor; import android.database.sqlite.SqliteWrapper; import android.net.Uri; +import android.os.Build; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SmsMessage; @@ -374,7 +375,7 @@ public final class Telephony { * Return cursor for table query. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static Cursor query(ContentResolver cr, String[] projection, String where, String orderBy) { return cr.query(CONTENT_URI, projection, where, diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 8ebfec47c4ea..b01d41948c3b 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -41,6 +41,7 @@ import android.content.res.Resources; import android.net.INetworkPolicyManager; import android.net.NetworkCapabilities; import android.net.Uri; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -191,7 +192,7 @@ public class SubscriptionManager { * The name_source is from the user * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static final int NAME_SOURCE_USER_INPUT = 2; /** @@ -1610,7 +1611,7 @@ public class SubscriptionManager { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static boolean isValidSlotIndex(int slotIndex) { return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount(); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 2ac0afe71894..fa247966af4c 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -39,6 +39,7 @@ import android.net.NetworkStats; import android.net.Uri; import android.os.AsyncTask; import android.os.BatteryStats; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.PersistableBundle; @@ -702,7 +703,7 @@ public class TelephonyManager { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED = "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED"; @@ -1499,23 +1500,24 @@ public class TelephonyManager { Rlog.d(TAG, "getCellLocation returning null because telephony is null"); return null; } + Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName()); - if (bundle.isEmpty()) { - Rlog.d(TAG, "getCellLocation returning null because bundle is empty"); + if (bundle == null || bundle.isEmpty()) { + Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable"); return null; } + CellLocation cl = CellLocation.newFromBundle(bundle); - if (cl.isEmpty()) { - Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty"); + if (cl == null || cl.isEmpty()) { + Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or" + + " phone type doesn't match CellLocation type"); return null; } + return cl; } catch (RemoteException ex) { Rlog.d(TAG, "getCellLocation returning null due to RemoteException " + ex); return null; - } catch (NullPointerException ex) { - Rlog.d(TAG, "getCellLocation returning null due to NullPointerException " + ex); - return null; } } @@ -1690,7 +1692,7 @@ public class TelephonyManager { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int getPhoneTypeFromProperty(int phoneId) { String type = getTelephonyProperty(phoneId, TelephonyProperties.CURRENT_ACTIVE_PHONE, null); diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java index 579d9723977f..1b638747ee09 100644 --- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java +++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.tests.sysmem.host; @@ -24,10 +24,10 @@ import com.android.tradefed.device.ITestDevice; * host. */ public class Cujs { - private ITestDevice device; + private ITestDevice mDevice; public Cujs(ITestDevice device) { - this.device = device; + this.mDevice = device; } /** @@ -38,6 +38,6 @@ public class Cujs { // TODO: Consider exercising the system in other interesting ways as // well. String command = "am instrument -w com.android.tests.sysmem.device/.Cujs"; - device.executeShellCommand(command); + mDevice.executeShellCommand(command); } } diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java index bbec0654b7ea..cfd598da1a5f 100644 --- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java +++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.tests.sysmem.host; @@ -22,46 +22,54 @@ import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics; import com.android.tradefed.testtype.IDeviceTest; -import java.io.IOException; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.IOException; + +/** + * Runs a system memory test. + */ @RunWith(DeviceJUnit4ClassRunner.class) public class MemoryTest implements IDeviceTest { @Rule public TestMetrics testMetrics = new TestMetrics(); @Rule public TestLogData testLogs = new TestLogData(); - private ITestDevice testDevice; - private int iterations = 0; // Number of times cujs have been run. - private Metrics metrics; - private Cujs cujs; + private ITestDevice mTestDevice; + private int mIterations = 0; // Number of times cujs have been run. + private Metrics mMetrics; + private Cujs mCujs; @Override public void setDevice(ITestDevice device) { - testDevice = device; - metrics = new Metrics(device, testMetrics, testLogs); - cujs = new Cujs(device); + mTestDevice = device; + mMetrics = new Metrics(device, testMetrics, testLogs); + mCujs = new Cujs(device); } @Override public ITestDevice getDevice() { - return testDevice; + return mTestDevice; } // Invoke a single iteration of running the cujs. private void runCujs() throws DeviceNotAvailableException { - cujs.run(); - iterations++; + mCujs.run(); + mIterations++; } // Sample desired memory. private void sample() throws DeviceNotAvailableException, IOException, Metrics.MetricsException { - metrics.sample(String.format("%03d", iterations)); + mMetrics.sample(String.format("%03d", mIterations)); } + /** + * Runs the memory tests. + */ @Test public void run() throws Exception { sample(); // Sample before running cujs diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java index 616983e39c50..70bc22c485e1 100644 --- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java +++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.tests.sysmem.host; @@ -22,6 +22,7 @@ import com.android.tradefed.result.FileInputStreamSource; import com.android.tradefed.result.LogDataType; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics; + import java.io.File; import java.io.IOException; import java.io.PrintStream; @@ -33,15 +34,15 @@ import java.util.Scanner; */ class Metrics { - private ITestDevice device; - private TestMetrics metrics; - private TestLogData logs; + private ITestDevice mDevice; + private TestMetrics mMetrics; + private TestLogData mLogs; /** * Exception thrown in case of error sampling metrics. */ public static class MetricsException extends Exception { - public MetricsException(String msg) { + MetricsException(String msg) { super(msg); } @@ -59,22 +60,22 @@ class Metrics { * @param metrics where to log the high level metrics when taking a sample * @param logs where to log detailed breakdowns when taking a sample */ - public Metrics(ITestDevice device, TestMetrics metrics, TestLogData logs) { - this.device = device; - this.metrics = metrics; - this.logs = logs; + Metrics(ITestDevice device, TestMetrics metrics, TestLogData logs) { + this.mDevice = device; + this.mMetrics = metrics; + this.mLogs = logs; } /** * Writes the given <code>text</code> to a log with the given label. */ private void logText(String label, String text) throws IOException { - File file = File.createTempFile(label, "txt"); - PrintStream ps = new PrintStream(file); - ps.print(text); - try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) { - logs.addTestLog(label, LogDataType.TEXT, dataStream); - } + File file = File.createTempFile(label, "txt"); + PrintStream ps = new PrintStream(file); + ps.print(text); + try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) { + mLogs.addTestLog(label, LogDataType.TEXT, dataStream); + } } /** @@ -82,11 +83,11 @@ class Metrics { */ private int getPidForProcess(String name) throws DeviceNotAvailableException, IOException, MetricsException { - String psout = device.executeShellCommand("ps -A -o PID,CMD"); + String psout = mDevice.executeShellCommand("ps -A -o PID,CMD"); Scanner sc = new Scanner(psout); try { // ps output is of the form: - // PID CMD + // PID CMD // 1 init // 2 kthreadd // ... @@ -117,20 +118,22 @@ class Metrics { */ void sample(String label) throws DeviceNotAvailableException, IOException, MetricsException { // adb root access is required to get showmap - device.enableAdbRoot(); + mDevice.enableAdbRoot(); int pid = getPidForProcess("system_server"); // Read showmap for system server and add it as a test log - String showmap = device.executeShellCommand("showmap " + pid); + String showmap = mDevice.executeShellCommand("showmap " + pid); logText(label + ".system_server.showmap", showmap); // Extract VSS, PSS and RSS from the showmap and output them as metrics. // The last lines of the showmap output looks something like: + // CHECKSTYLE:OFF Generated code // virtual shared shared private private // size RSS PSS clean dirty clean dirty swap swapPSS # object //-------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------ // 928480 113016 24860 87348 7916 3632 14120 1968 1968 1900 TOTAL + // CHECKSTYLE:ON Generated code try { int pos = showmap.lastIndexOf("----"); Scanner sc = new Scanner(showmap.substring(pos)); @@ -139,16 +142,16 @@ class Metrics { long rss = sc.nextLong(); long pss = sc.nextLong(); - metrics.addTestMetric(String.format("%s.system_server.vss", label), Long.toString(vss)); - metrics.addTestMetric(String.format("%s.system_server.rss", label), Long.toString(rss)); - metrics.addTestMetric(String.format("%s.system_server.pss", label), Long.toString(pss)); + mMetrics.addTestMetric(label + ".system_server.vss", Long.toString(vss)); + mMetrics.addTestMetric(label + ".system_server.rss", Long.toString(rss)); + mMetrics.addTestMetric(label + ".system_server.pss", Long.toString(pss)); } catch (InputMismatchException e) { throw new MetricsException("unexpected showmap format", e); } // Run debuggerd -j to get GC stats for system server and add it as a // test log - String debuggerd = device.executeShellCommand("debuggerd -j " + pid); + String debuggerd = mDevice.executeShellCommand("debuggerd -j " + pid); logText(label + ".system_server.debuggerd", debuggerd); // TODO: Experiment with other additional metrics. diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp index 0778564ee079..9a7238b584ba 100644 --- a/tools/aapt2/StringPool_test.cpp +++ b/tools/aapt2/StringPool_test.cpp @@ -303,7 +303,7 @@ TEST(StringPoolTest, Flatten) { } } -TEST(StringPoolTest, FlattenModifiedUTF8) { +TEST(StringPoolTest, ModifiedUTF8) { using namespace android; // For NO_ERROR on Windows. StdErrDiagnostics diag; StringPool pool; @@ -315,12 +315,24 @@ TEST(StringPoolTest, FlattenModifiedUTF8) { StringPool::FlattenUtf8(&buffer, pool, &diag); std::unique_ptr<uint8_t[]> data = util::Copy(buffer); - // Check that the 4 byte utf-8 codepoint is encoded using 2 3 byte surrogate pairs + // Check that the codepoints are encoded using two three-byte surrogate pairs ResStringPool test; ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR); - EXPECT_THAT(util::GetString(test, 0), Eq("\xED\xA0\x81\xED\xB0\x80")); - EXPECT_THAT(util::GetString(test, 1), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar")); - EXPECT_THAT(util::GetString(test, 2), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7")); + size_t len; + const char* str = test.string8At(0, &len); + ASSERT_THAT(str, NotNull()); + EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80")); + str = test.string8At(1, &len); + ASSERT_THAT(str, NotNull()); + EXPECT_THAT(std::string(str, len), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar")); + str = test.string8At(2, &len); + ASSERT_THAT(str, NotNull()); + EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7")); + + // Check that retrieving the strings returns the original UTF-8 character bytes + EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80")); + EXPECT_THAT(util::GetString(test, 1), Eq("foo \xF0\x90\x90\xB7 bar")); + EXPECT_THAT(util::GetString(test, 2), Eq("\xF0\x90\x90\x80\xF0\x90\x90\xB7")); } TEST(StringPoolTest, MaxEncodingLength) { diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index c5c78d9d3827..fa6538d7b4e7 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -252,6 +252,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, xml::XmlNodeAction component_action; component_action.Action(RequiredNameIsJavaClassName); component_action["intent-filter"] = intent_filter_action; + component_action["preferred"] = intent_filter_action; component_action["meta-data"] = meta_data_action; // Manifest actions. @@ -414,6 +415,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, application_action["provider"]["grant-uri-permission"]; application_action["provider"]["path-permission"]; + manifest_action["package"] = manifest_action; + return true; } diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp index 9bef54e590c9..59b7fff0f9e3 100644 --- a/tools/aapt2/util/Util.cpp +++ b/tools/aapt2/util/Util.cpp @@ -322,11 +322,11 @@ std::string Utf8ToModifiedUtf8(const std::string& utf8) { output.reserve(modified_size); for (size_t i = 0; i < size; i++) { if (((uint8_t) utf8[i] >> 4) == 0xF) { - auto codepoint = (char32_t) utf32_from_utf8_at(utf8.data(), size, i, nullptr); + int32_t codepoint = utf32_from_utf8_at(utf8.data(), size, i, nullptr); // Calculate the high and low surrogates as UTF-16 would - char32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800; - char32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00; + int32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800; + int32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00; // Encode each surrogate in UTF-8 output.push_back((char) (0xE4 | ((high >> 12) & 0xF))); @@ -344,6 +344,60 @@ std::string Utf8ToModifiedUtf8(const std::string& utf8) { return output; } +std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8) { + // The UTF-8 representation will have a byte length less than or equal to the Modified UTF-8 + // representation. + std::string output; + output.reserve(modified_utf8.size()); + + size_t index = 0; + const size_t modified_size = modified_utf8.size(); + while (index < modified_size) { + size_t next_index; + int32_t high_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, index, + &next_index); + if (high_surrogate < 0) { + return {}; + } + + // Check that the first codepoint is within the high surrogate range + if (high_surrogate >= 0xD800 && high_surrogate <= 0xDB7F) { + int32_t low_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, next_index, + &next_index); + if (low_surrogate < 0) { + return {}; + } + + // Check that the second codepoint is within the low surrogate range + if (low_surrogate >= 0xDC00 && low_surrogate <= 0xDFFF) { + const char32_t codepoint = (char32_t) (((high_surrogate - 0xD800) * 0x400) + + (low_surrogate - 0xDC00) + 0x10000); + + // The decoded codepoint should represent a 4 byte, UTF-8 character + const size_t utf8_length = (size_t) utf32_to_utf8_length(&codepoint, 1); + if (utf8_length != 4) { + return {}; + } + + // Encode the UTF-8 representation of the codepoint into the string + char* start = &output[output.size()]; + output.resize(output.size() + utf8_length); + utf32_to_utf8((char32_t*) &codepoint, 1, start, utf8_length + 1); + + index = next_index; + continue; + } + } + + // Append non-surrogate pairs to the output string + for (size_t i = index; i < next_index; i++) { + output.push_back(modified_utf8[i]); + } + index = next_index; + } + return output; +} + std::u16string Utf8ToUtf16(const StringPiece& utf8) { ssize_t utf16_length = utf8_to_utf16_length( reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length()); @@ -469,7 +523,7 @@ std::string GetString(const android::ResStringPool& pool, size_t idx) { size_t len; const char* str = pool.string8At(idx, &len); if (str != nullptr) { - return std::string(str, len); + return ModifiedUtf8ToUtf8(std::string(str, len)); } return Utf16ToUtf8(GetString16(pool, idx)); } diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h index 36b733376e6f..c6e8e6ef7619 100644 --- a/tools/aapt2/util/Util.h +++ b/tools/aapt2/util/Util.h @@ -199,6 +199,7 @@ inline StringBuilder::operator bool() const { // Converts a UTF8 string into Modified UTF8 std::string Utf8ToModifiedUtf8(const std::string& utf8); +std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8); // Converts a UTF8 string to a UTF16 string. std::u16string Utf8ToUtf16(const android::StringPiece& utf8); diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 018e9c9d5f57..934847f6eec2 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -697,8 +697,8 @@ def verify_layering(clazz): "android.provider", ["android.content","android.graphics.drawable"], "android.database", - "android.graphics", "android.text", + "android.graphics", "android.os", "android.util" ] diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh index bdcc8076dde1..76a2f2d6eba1 100755 --- a/tools/hiddenapi/sort_api.sh +++ b/tools/hiddenapi/sort_api.sh @@ -12,8 +12,8 @@ readarray A < "$source_list" # Sort IFS=$'\n' # Stash away comments -C=( $(grep -E '^#' <<< "${A[*]}") ) -A=( $(grep -v -E '^#' <<< "${A[*]}") ) +C=( $(grep -E '^#' <<< "${A[*]}" || :) ) +A=( $(grep -v -E '^#' <<< "${A[*]}" || :) ) # Sort entries A=( $(LC_COLLATE=C sort -f <<< "${A[*]}") ) A=( $(uniq <<< "${A[*]}") ) diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 57f3973a4eb5..5a4c898c0bcd 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -30,6 +30,7 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo; import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -488,7 +489,7 @@ public class WifiP2pManager { * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which * is a system private class. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public WifiP2pManager(IWifiP2pManager service) { mService = service; } |