summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp272
-rwxr-xr-xapi/current.txt64
-rw-r--r--api/system-current.txt16
-rw-r--r--api/test-current.txt3
-rw-r--r--cmds/incidentd/src/Section.h2
-rw-r--r--cmds/statsd/src/atoms.proto21
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp2
-rw-r--r--config/hiddenapi-light-greylist.txt4
-rw-r--r--config/preloaded-classes6
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java2
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/ActivityThread.java2
-rw-r--r--core/java/android/app/AlertDialog.java2
-rw-r--r--core/java/android/app/AutomaticZenRule.java58
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/Notification.java2
-rw-r--r--core/java/android/app/NotificationManager.java11
-rw-r--r--core/java/android/content/ContentUris.java28
-rw-r--r--core/java/android/content/Context.java3
-rw-r--r--core/java/android/content/pm/AndroidHidlUpdater.java43
-rw-r--r--core/java/android/content/pm/PackageBackwardCompatibility.java2
-rw-r--r--core/java/android/content/pm/SharedLibraryNames.java4
-rw-r--r--core/java/android/content/res/Resources.java4
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java2
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java109
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java42
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java24
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java5
-rw-r--r--core/java/android/net/NetworkFactory.java2
-rw-r--r--core/java/android/net/NetworkSpecifier.java2
-rw-r--r--core/java/android/os/Environment.java9
-rw-r--r--core/java/android/os/FileUtils.java111
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java23
-rw-r--r--core/java/android/os/UserHandle.java5
-rw-r--r--core/java/android/os/storage/StorageManager.java6
-rw-r--r--core/java/android/provider/DocumentsContract.java2
-rw-r--r--core/java/android/provider/DocumentsProvider.java22
-rw-r--r--core/java/android/provider/SearchIndexablesProvider.java6
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java15
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java156
-rw-r--r--core/java/android/service/notification/ZenPolicy.java868
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/view/ViewGroup.java6
-rw-r--r--core/java/android/webkit/SafeBrowsingResponse.java4
-rw-r--r--core/java/android/widget/AdapterView.java2
-rw-r--r--core/java/android/widget/LinearLayout.java4
-rw-r--r--core/java/android/widget/TextView.java2
-rw-r--r--core/proto/android/service/notification.proto3
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java98
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java6
-rw-r--r--core/tests/coretests/src/android/os/FileUtilsTest.java42
-rw-r--r--core/tests/coretests/src/android/text/FontFallbackSetup.java4
-rw-r--r--data/etc/platform.xml6
-rw-r--r--graphics/java/android/graphics/fonts/Font.java12
-rw-r--r--graphics/java/android/graphics/fonts/SystemFonts.java20
-rw-r--r--libs/hwui/DeviceInfo.cpp16
-rw-r--r--libs/hwui/DeviceInfo.h9
-rw-r--r--libs/hwui/LayerUpdateQueue.h1
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp28
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp31
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h13
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp14
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h5
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp8
-rw-r--r--libs/hwui/renderthread/CanvasContext.h3
-rw-r--r--libs/hwui/renderthread/EglManager.cpp45
-rw-r--r--libs/hwui/renderthread/EglManager.h11
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h25
-rw-r--r--libs/hwui/renderthread/VulkanManager.h4
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp2
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp30
-rw-r--r--libs/hwui/utils/Color.cpp39
-rw-r--r--libs/hwui/utils/Color.h5
-rw-r--r--media/java/android/media/AudioTrack.java2
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java89
-rw-r--r--packages/Shell/src/com/android/shell/BugreportStorageProvider.java13
-rw-r--r--packages/SystemUI/res/layout/operator_name.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java240
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricPromptService.java12
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java214
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java66
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java48
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java20
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java50
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java26
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java30
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java11
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java12
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java14
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioningController.java7
-rw-r--r--services/java/com/android/server/SystemServer.java4
-rw-r--r--services/net/java/android/net/ip/IpServer.java (renamed from services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java)99
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java151
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java456
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java35
-rwxr-xr-xstartop/scripts/app_startup/force_compiler_filter173
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java84
-rw-r--r--tests/net/java/android/net/ip/IpServerTest.java (renamed from tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java)190
-rw-r--r--tests/net/java/com/android/server/connectivity/TetheringTest.java63
-rw-r--r--tools/aapt2/Diagnostics.h8
-rw-r--r--tools/aapt2/compile/XmlIdCollector.cpp28
-rw-r--r--tools/aapt2/compile/XmlIdCollector_test.cpp10
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp3
-rw-r--r--tools/aapt2/util/Files.cpp15
108 files changed, 3816 insertions, 841 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 2c2bc5f4d21c..ea21c2dd10b1 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -4385,6 +4385,7 @@ package android.app {
public final class AutomaticZenRule implements android.os.Parcelable {
ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+ ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, boolean);
ctor public AutomaticZenRule(android.os.Parcel);
method public int describeContents();
method public android.net.Uri getConditionId();
@@ -4392,11 +4393,13 @@ package android.app {
method public int getInterruptionFilter();
method public java.lang.String getName();
method public android.content.ComponentName getOwner();
+ method public android.service.notification.ZenPolicy getZenPolicy();
method public boolean isEnabled();
method public void setConditionId(android.net.Uri);
method public void setEnabled(boolean);
method public void setInterruptionFilter(int);
method public void setName(java.lang.String);
+ method public void setZenPolicy(android.service.notification.ZenPolicy);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
}
@@ -9340,6 +9343,7 @@ package android.content {
ctor public ContentUris();
method public static android.net.Uri.Builder appendId(android.net.Uri.Builder, long);
method public static long parseId(android.net.Uri);
+ method public static android.net.Uri removeId(android.net.Uri);
method public static android.net.Uri withAppendedId(android.net.Uri, long);
}
@@ -11928,6 +11932,7 @@ package android.content.res {
method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
+ method public float getFloat(int);
method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
method public float getFraction(int, int, int);
method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
@@ -12655,7 +12660,7 @@ package android.database.sqlite {
ctor public SQLiteMisuseException(java.lang.String);
}
- public abstract class SQLiteOpenHelper {
+ public abstract class SQLiteOpenHelper implements java.lang.AutoCloseable {
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
@@ -16033,6 +16038,7 @@ package android.hardware.camera2 {
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys();
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableSessionKeys();
method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
+ method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
method public java.util.Set<java.lang.String> getPhysicalCameraIds();
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
@@ -39565,6 +39571,7 @@ package android.service.notification {
method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int);
method public final void cancelNotification(java.lang.String);
method public final void cancelNotifications(java.lang.String[]);
+ method public final void clearRequestedListenerHints();
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
method public final int getCurrentInterruptionFilter();
@@ -39680,6 +39687,61 @@ package android.service.notification {
field public static final android.os.Parcelable.Creator<android.service.notification.StatusBarNotification> CREATOR;
}
+ public final class ZenPolicy implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getPriorityCallSenders();
+ method public int getPriorityCategoryAlarms();
+ method public int getPriorityCategoryCalls();
+ method public int getPriorityCategoryEvents();
+ method public int getPriorityCategoryMedia();
+ method public int getPriorityCategoryMessages();
+ method public int getPriorityCategoryReminders();
+ method public int getPriorityCategoryRepeatCallers();
+ method public int getPriorityCategorySystem();
+ method public int getPriorityMessageSenders();
+ method public int getVisualEffectAmbient();
+ method public int getVisualEffectBadge();
+ method public int getVisualEffectFullScreenIntent();
+ method public int getVisualEffectLights();
+ method public int getVisualEffectNotificationList();
+ method public int getVisualEffectPeek();
+ method public int getVisualEffectStatusBar();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.notification.ZenPolicy> CREATOR;
+ field public static final int PEOPLE_TYPE_ANYONE = 1; // 0x1
+ field public static final int PEOPLE_TYPE_CONTACTS = 2; // 0x2
+ field public static final int PEOPLE_TYPE_NONE = 4; // 0x4
+ field public static final int PEOPLE_TYPE_STARRED = 3; // 0x3
+ field public static final int PEOPLE_TYPE_UNSET = 0; // 0x0
+ field public static final int STATE_ALLOW = 1; // 0x1
+ field public static final int STATE_DISALLOW = 2; // 0x2
+ field public static final int STATE_UNSET = 0; // 0x0
+ }
+
+ public static class ZenPolicy.Builder {
+ ctor public ZenPolicy.Builder();
+ method public android.service.notification.ZenPolicy.Builder allowAlarms(boolean);
+ method public android.service.notification.ZenPolicy.Builder allowAllSounds();
+ method public android.service.notification.ZenPolicy.Builder allowCalls(int);
+ method public android.service.notification.ZenPolicy.Builder allowEvents(boolean);
+ method public android.service.notification.ZenPolicy.Builder allowMedia(boolean);
+ method public android.service.notification.ZenPolicy.Builder allowMessages(int);
+ method public android.service.notification.ZenPolicy.Builder allowReminders(boolean);
+ method public android.service.notification.ZenPolicy.Builder allowRepeatCallers(boolean);
+ method public android.service.notification.ZenPolicy.Builder allowSystem(boolean);
+ method public android.service.notification.ZenPolicy build();
+ method public android.service.notification.ZenPolicy.Builder disallowAllSounds();
+ method public android.service.notification.ZenPolicy.Builder hideAllVisualEffects();
+ method public android.service.notification.ZenPolicy.Builder showAllVisualEffects();
+ method public android.service.notification.ZenPolicy.Builder showBadges(boolean);
+ method public android.service.notification.ZenPolicy.Builder showFullScreenIntent(boolean);
+ method public android.service.notification.ZenPolicy.Builder showInAmbientDisplay(boolean);
+ method public android.service.notification.ZenPolicy.Builder showInNotificationList(boolean);
+ method public android.service.notification.ZenPolicy.Builder showLights(boolean);
+ method public android.service.notification.ZenPolicy.Builder showPeeking(boolean);
+ method public android.service.notification.ZenPolicy.Builder showStatusBarIcons(boolean);
+ }
+
}
package android.service.quicksettings {
diff --git a/api/system-current.txt b/api/system-current.txt
index e2c59cb10dd4..d29b2167092f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -355,6 +355,11 @@ package android.app {
field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
}
+ public final class AutomaticZenRule implements android.os.Parcelable {
+ ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean, long);
+ ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean, long, android.service.notification.ZenPolicy);
+ }
+
public class BroadcastOptions {
method public static android.app.BroadcastOptions makeBasic();
method public void setDontSendToRestrictedApps(boolean);
@@ -3807,6 +3812,14 @@ package android.os {
field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
}
+ public class Environment {
+ method public static java.io.File getOdmDirectory();
+ method public static java.io.File getOemDirectory();
+ method public static java.io.File getProductDirectory();
+ method public static java.io.File getProductServicesDirectory();
+ method public static java.io.File getVendorDirectory();
+ }
+
public class HidlSupport {
method public static boolean deepEquals(java.lang.Object, java.lang.Object);
method public static int deepHashCode(java.lang.Object);
@@ -4107,6 +4120,9 @@ package android.os {
method public boolean isSystem();
method public static int myUserId();
method public static android.os.UserHandle of(int);
+ field public static final android.os.UserHandle ALL;
+ field public static final android.os.UserHandle CURRENT;
+ field public static final android.os.UserHandle SYSTEM;
field public static final int USER_NULL = -10000; // 0xffffd8f0
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 28e97347db48..e22f516d9d78 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -259,6 +259,7 @@ package android.content {
}
public abstract class Context {
+ method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.lang.String getOpPackageName();
method public android.os.UserHandle getUser();
method public int getUserId();
@@ -765,6 +766,8 @@ package android.os {
method public static int getAppId(int);
method public int getIdentifier();
method public static boolean isApp(int);
+ field public static final android.os.UserHandle ALL;
+ field public static final android.os.UserHandle CURRENT;
field public static final android.os.UserHandle SYSTEM;
}
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..3bd1bb08fd0c 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:
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 a4f13a0c5788..5d37c5fdbaff 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -728,8 +728,6 @@ Landroid/os/Environment;->buildExternalStorageAppMediaDirs(Ljava/lang/String;)[L
Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File;
Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File;
Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File;
-Landroid/os/Environment;->getOemDirectory()Ljava/io/File;
-Landroid/os/Environment;->getVendorDirectory()Ljava/io/File;
Landroid/os/Environment;->initForCurrentUser()V
Landroid/os/Environment;->maybeTranslateEmulatedPathToInternal(Ljava/io/File;)Ljava/io/File;
Landroid/os/Environment;->sCurrentUser:Landroid/os/Environment$UserEnvironment;
@@ -1001,8 +999,6 @@ Landroid/os/UserHandle;->AID_APP_START:I
Landroid/os/UserHandle;->AID_CACHE_GID_START:I
Landroid/os/UserHandle;->AID_ROOT:I
Landroid/os/UserHandle;->AID_SHARED_GID_START:I
-Landroid/os/UserHandle;->ALL:Landroid/os/UserHandle;
-Landroid/os/UserHandle;->CURRENT:Landroid/os/UserHandle;
Landroid/os/UserHandle;->CURRENT_OR_SELF:Landroid/os/UserHandle;
Landroid/os/UserHandle;->ERR_GID:I
Landroid/os/UserHandle;->formatUid(Ljava/io/PrintWriter;I)V
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 63c583f9264c..50e97c53fe83 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1436,12 +1436,6 @@ android.hardware.usb.UsbDevice$1
android.hardware.usb.UsbDeviceConnection
android.hardware.usb.UsbManager
android.hardware.usb.UsbRequest
-android.hidl.base.V1_0.DebugInfo
-android.hidl.base.V1_0.IBase
-android.hidl.manager.V1_0.IServiceManager
-android.hidl.manager.V1_0.IServiceManager$Proxy
-android.hidl.manager.V1_0.IServiceNotification
-android.hidl.manager.V1_0.IServiceNotification$Stub
android.icu.impl.BMPSet
android.icu.impl.CacheBase
android.icu.impl.CacheValue
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 446e6cc0769c..9a061b0eb79c 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -73,7 +73,7 @@ import java.util.List;
* follows the established service life cycle. Starting an accessibility service is triggered
* exclusively by the user explicitly turning the service on in device settings. After the system
* binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
- * be overriden by clients that want to perform post binding setup.
+ * be overridden by clients that want to perform post binding setup.
* </p>
* <p>
* An accessibility service stops either when the user turns it off in device settings or when
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7b8664658422..17de9976c89b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6385,11 +6385,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;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 912070144986..0e884d67d011 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2131,7 +2131,7 @@ public final class ActivityThread extends ClientTransactionHandler {
ai = getPackageManager().getApplicationInfo(packageName,
PackageManager.GET_SHARED_LIBRARY_FILES
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- userId);
+ (userId < 0) ? UserHandle.myUserId() : userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
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/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index cd4ace669b6c..62f6bac2a24f 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,11 +16,14 @@
package android.app;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
+
import android.app.NotificationManager.InterruptionFilter;
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.service.notification.ZenPolicy;
import java.util.Objects;
@@ -35,6 +38,7 @@ public final class AutomaticZenRule implements Parcelable {
private Uri conditionId;
private ComponentName owner;
private long creationTime;
+ private ZenPolicy mZenPolicy;
/**
* Creates an automatic zen rule.
@@ -58,7 +62,27 @@ public final class AutomaticZenRule implements Parcelable {
}
/**
- * @SystemApi
+ * Creates an automatic zen rule.
+ *
+ * @param name The name of the rule.
+ * @param owner The Condition Provider service that owns this rule.
+ * @param conditionId A representation of the state that should cause the Condition Provider
+ * service to apply the given interruption filter.
+ * @param policy The policy defines which notifications are allowed to interrupt the user
+ * while this rule is active
+ * @param enabled Whether the rule is enabled.
+ */
+ public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
+ boolean enabled) {
+ this.name = name;
+ this.owner = owner;
+ this.conditionId = conditionId;
+ this.interruptionFilter = INTERRUPTION_FILTER_PRIORITY;
+ this.enabled = enabled;
+ this.mZenPolicy = policy;
+ }
+
+ /**
* @hide
*/
public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
@@ -67,6 +91,15 @@ public final class AutomaticZenRule implements Parcelable {
this.creationTime = creationTime;
}
+ /**
+ * @hide
+ */
+ public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
+ boolean enabled, long creationTime) {
+ this(name, owner, conditionId, policy, enabled);
+ this.creationTime = creationTime;
+ }
+
public AutomaticZenRule(Parcel source) {
enabled = source.readInt() == 1;
if (source.readInt() == 1) {
@@ -76,6 +109,7 @@ public final class AutomaticZenRule implements Parcelable {
conditionId = source.readParcelable(null);
owner = source.readParcelable(null);
creationTime = source.readLong();
+ mZenPolicy = source.readParcelable(null);
}
/**
@@ -114,6 +148,13 @@ public final class AutomaticZenRule implements Parcelable {
}
/**
+ * Gets the zen policy.
+ */
+ public ZenPolicy getZenPolicy() {
+ return this.mZenPolicy.copy();
+ }
+
+ /**
* Returns the time this rule was created, represented as milliseconds since the epoch.
*/
public long getCreationTime() {
@@ -149,6 +190,13 @@ public final class AutomaticZenRule implements Parcelable {
this.enabled = enabled;
}
+ /**
+ * Sets the zen policy.
+ */
+ public void setZenPolicy(ZenPolicy zenPolicy) {
+ this.mZenPolicy = zenPolicy;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -167,6 +215,7 @@ public final class AutomaticZenRule implements Parcelable {
dest.writeParcelable(conditionId, 0);
dest.writeParcelable(owner, 0);
dest.writeLong(creationTime);
+ dest.writeParcelable(mZenPolicy, 0);
}
@Override
@@ -178,6 +227,7 @@ public final class AutomaticZenRule implements Parcelable {
.append(",conditionId=").append(conditionId)
.append(",owner=").append(owner)
.append(",creationTime=").append(creationTime)
+ .append(",mZenPolicy=").append(mZenPolicy)
.append(']').toString();
}
@@ -191,12 +241,14 @@ public final class AutomaticZenRule implements Parcelable {
&& other.interruptionFilter == interruptionFilter
&& Objects.equals(other.conditionId, conditionId)
&& Objects.equals(other.owner, owner)
- && other.creationTime == creationTime;
+ && other.creationTime == creationTime
+ && Objects.equals(other.mZenPolicy, mZenPolicy);
}
@Override
public int hashCode() {
- return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime);
+ return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime,
+ mZenPolicy);
}
public static final Parcelable.Creator<AutomaticZenRule> CREATOR
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 4f004d93e3bf..357420bd0217 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -112,6 +112,7 @@ interface INotificationManager
ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
ParceledListSlice getSnoozedNotificationsFromListener(in INotificationListener token, int trim);
+ void clearRequestedListenerHints(in INotificationListener token);
void requestHintsFromListener(in INotificationListener token, int hints);
int getHintsFromListener(in INotificationListener token);
void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9dca0614dc5f..491af6094d96 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3499,7 +3499,7 @@ public class Notification implements Parcelable
/**
* Set the small icon, which will be used to represent the notification in the
- * status bar and content view (unless overriden there by a
+ * status bar and content view (unless overridden there by a
* {@link #setLargeIcon(Bitmap) large icon}).
*
* @param icon An Icon object to use.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b96b39df9aa0..9f819b9739b8 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -841,9 +841,14 @@ public class NotificationManager {
List<ZenModeConfig.ZenRule> rules = service.getZenRules();
Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
for (ZenModeConfig.ZenRule rule : rules) {
- ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
- rule.conditionId, zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
- rule.creationTime));
+ if (rule.zenPolicy == null) {
+ ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+ rule.conditionId, zenModeToInterruptionFilter(rule.zenMode),
+ rule.enabled, rule.creationTime));
+ } else {
+ ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+ rule.conditionId, rule.zenPolicy, rule.enabled, rule.creationTime));
+ }
}
return ruleMap;
} catch (RemoteException e) {
diff --git a/core/java/android/content/ContentUris.java b/core/java/android/content/ContentUris.java
index dbe8a7c322ae..fd7b37210822 100644
--- a/core/java/android/content/ContentUris.java
+++ b/core/java/android/content/ContentUris.java
@@ -18,6 +18,8 @@ package android.content;
import android.net.Uri;
+import java.util.List;
+
/**
* Utility methods useful for working with {@link android.net.Uri} objects
* that use the &quot;content&quot; (content://) scheme.
@@ -109,4 +111,30 @@ public class ContentUris {
public static Uri withAppendedId(Uri contentUri, long id) {
return appendId(contentUri.buildUpon(), id).build();
}
+
+ /**
+ * Removes any ID from the end of the path.
+ *
+ * @param contentUri that ends with an ID
+ * @return a new URI with the ID removed from the end of the path
+ * @throws IllegalArgumentException when the given URI has no ID to remove
+ * from the end of the path
+ */
+ public static Uri removeId(Uri contentUri) {
+ // Verify that we have a valid ID to actually remove
+ final String last = contentUri.getLastPathSegment();
+ if (last == null) {
+ throw new IllegalArgumentException("No path segments to remove");
+ } else {
+ Long.parseLong(last);
+ }
+
+ final List<String> segments = contentUri.getPathSegments();
+ final Uri.Builder builder = contentUri.buildUpon();
+ builder.path(null);
+ for (int i = 0; i < segments.size() - 1; i++) {
+ builder.appendPath(segments.get(i));
+ }
+ return builder.build();
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ddd12a546650..3c1690a68689 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3407,7 +3407,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
@@ -4792,6 +4792,7 @@ public abstract class Context {
* @hide
*/
@SystemApi
+ @TestApi
public Context createPackageContextAsUser(
String packageName, @CreatePackageOptions int flags, UserHandle user)
throws PackageManager.NameNotFoundException {
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
new file mode 100644
index 000000000000..69cc94ffef55
--- /dev/null
+++ b/core/java/android/content/pm/AndroidHidlUpdater.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.PackageParser.Package;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
+ * and android.hidl.manager-V1.0-java libraries are included by default.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
+
+ @Override
+ public void updatePackage(Package pkg) {
+ // This was the default <= P and is maintained for backwards compatibility.
+ if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.P) {
+ prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
+ prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
index a16f81b11ae6..03eefedd2b30 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -53,6 +53,8 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
"android.content.pm.OrgApacheHttpLegacyUpdater",
RemoveUnnecessaryOrgApacheHttpLegacyLibrary::new);
+ packageUpdaters.add(new AndroidHidlUpdater());
+
// Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
// android.test.mock.
packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 83e86636424a..387d29e81dfc 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,6 +22,10 @@ package android.content.pm;
*/
public class SharedLibraryNames {
+ static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+
+ static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+
static final String ANDROID_TEST_BASE = "android.test.base";
static final String ANDROID_TEST_MOCK = "android.test.mock";
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 43e1612298fd..88b1c8803713 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1129,10 +1129,8 @@ public class Resources {
*
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist or is not a floating-point value.
- * @hide Pending API council approval.
*/
- @UnsupportedAppUsage
- public float getFloat(int id) {
+ public float getFloat(@DimenRes int id) {
final TypedValue value = obtainTempTypedValue();
try {
mResourcesImpl.getValue(id, value, true);
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 1377806cb213..19c6745ef8d4 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -49,7 +49,7 @@ import java.io.File;
* <p class="note"><strong>Note:</strong> this class assumes
* monotonically increasing version numbers for upgrades.</p>
*/
-public abstract class SQLiteOpenHelper {
+public abstract class SQLiteOpenHelper implements AutoCloseable {
private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
private final Context mContext;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 35584ae21869..46e66e0dbef5 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -188,6 +188,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
@UnsupportedAppUsage
private final CameraMetadataNative mProperties;
private List<CameraCharacteristics.Key<?>> mKeys;
+ private List<CameraCharacteristics.Key<?>> mKeysNeedingPermission;
private List<CaptureRequest.Key<?>> mAvailableRequestKeys;
private List<CaptureRequest.Key<?>> mAvailableSessionKeys;
private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys;
@@ -268,11 +269,50 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
}
mKeys = Collections.unmodifiableList(
- getKeys(getClass(), getKeyClass(), this, filterTags));
+ getKeys(getClass(), getKeyClass(), this, filterTags, true));
return mKeys;
}
/**
+ * <p>Returns a subset of the list returned by {@link #getKeys} with all keys that
+ * require camera clients to obtain the {@link android.Manifest.permission#CAMERA} permission.
+ * </p>
+ *
+ * <p>If an application calls {@link CameraManager#getCameraCharacteristics} without holding the
+ * {@link android.Manifest.permission#CAMERA} permission,
+ * all keys in this list will not be available, and calling {@link #get} will
+ * return null for those keys. If the application obtains the
+ * {@link android.Manifest.permission#CAMERA} permission, then the
+ * CameraCharacteristics from a call to a subsequent
+ * {@link CameraManager#getCameraCharacteristics} will have the keys available.</p>
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * @return List of camera characteristic keys that require the
+ * {@link android.Manifest.permission#CAMERA} permission. The list can be null in case
+ * there are no currently present keys that need additional permission.
+ */
+ public List<Key<?>> getKeysNeedingPermission() {
+ if (mKeysNeedingPermission == null) {
+ Object crKey = CameraCharacteristics.Key.class;
+ Class<CameraCharacteristics.Key<?>> crKeyTyped =
+ (Class<CameraCharacteristics.Key<?>>)crKey;
+
+ int[] filterTags = get(REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION);
+ if (filterTags == null) {
+ return null;
+ }
+ mKeysNeedingPermission =
+ getAvailableKeyList(CameraCharacteristics.class, crKeyTyped, filterTags,
+ /*includeSynthetic*/ false);
+ }
+ return mKeysNeedingPermission;
+ }
+
+ /**
* <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the
* camera device can pass as part of the capture session initialization.</p>
*
@@ -328,17 +368,18 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
return null;
}
mAvailableSessionKeys =
- getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+ getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+ /*includeSynthetic*/ false);
}
return mAvailableSessionKeys;
}
/**
* <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that can
- * be overriden for physical devices backing a logical multi-camera.</p>
+ * be overridden for physical devices backing a logical multi-camera.</p>
*
* <p>This is a subset of android.request.availableRequestKeys which contains a list
- * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+ * of keys that can be overridden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
* The respective value of such request key can be obtained by calling
* {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
* individual physical device requests must be built via
@@ -353,7 +394,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
*
* <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
*
- * @return List of keys that can be overriden in individual physical device requests.
+ * @return List of keys that can be overridden in individual physical device requests.
* In case the camera device doesn't support such keys the list can be null.
*/
@SuppressWarnings({"unchecked"})
@@ -367,7 +408,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
return null;
}
mAvailablePhysicalRequestKeys =
- getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+ getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+ /*includeSynthetic*/ false);
}
return mAvailablePhysicalRequestKeys;
}
@@ -399,7 +441,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
+ "in the characteristics");
}
mAvailableRequestKeys =
- getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+ getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+ /*includeSynthetic*/ true);
}
return mAvailableRequestKeys;
}
@@ -430,7 +473,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
throw new AssertionError("android.request.availableResultKeys must be non-null "
+ "in the characteristics");
}
- mAvailableResultKeys = getAvailableKeyList(CaptureResult.class, crKeyTyped, filterTags);
+ mAvailableResultKeys = getAvailableKeyList(CaptureResult.class, crKeyTyped, filterTags,
+ /*includeSynthetic*/ true);
}
return mAvailableResultKeys;
}
@@ -445,13 +489,16 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
*
* @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
* @param keyClass The class of the metadata key, e.g. CaptureRequest.Key.class
+ * @param filterTags An array of tags to be used for filtering
+ * @param includeSynthetic Include public syntethic tag by default.
*
* @return List of keys supported by this CameraDevice for metadataClass.
*
* @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
*/
private <TKey> List<TKey>
- getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags) {
+ getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags,
+ boolean includeSynthetic) {
if (metadataClass.equals(CameraMetadata.class)) {
throw new AssertionError(
@@ -462,7 +509,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
}
List<TKey> staticKeyList = getKeys(
- metadataClass, keyClass, /*instance*/null, filterTags);
+ metadataClass, keyClass, /*instance*/null, filterTags, includeSynthetic);
return Collections.unmodifiableList(staticKeyList);
}
@@ -474,6 +521,13 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability. If the camera device
* doesn't have the capability, the return value will be an empty set. </p>
*
+ * <p>Prior to API level 29, all returned IDs are guaranteed to be returned by {@link
+ * CameraManager#getCameraIdList}, and can be opened directly by
+ * {@link CameraManager#openCamera}. Starting from API level 29, for each of the returned ID,
+ * if it's also returned by {@link CameraManager#getCameraIdList}, it can be used as a
+ * standalone camera by {@link CameraManager#openCamera}. Otherwise, the camera ID can only be
+ * used as part of the current logical camera.</p>
+ *
* <p>The set returned is not modifiable, so any attempts to modify it will throw
* a {@code UnsupportedOperationException}.</p>
*
@@ -1103,6 +1157,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p><b>Limited capability</b> -
* Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -1124,6 +1179,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p><b>Limited capability</b> -
* Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -1238,6 +1294,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p><b>Units</b>:
* Quaternion coefficients</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*/
@PublicKey
public static final Key<float[]> LENS_POSE_ROTATION =
@@ -1273,6 +1330,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* with PRIMARY_CAMERA.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
@@ -1344,6 +1402,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
* coordinate system.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_POSE_ROTATION
@@ -1387,6 +1446,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p><b>Units</b>:
* Unitless coefficients.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @deprecated
@@ -1411,6 +1471,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
* </ul></p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
* @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA
@@ -1452,6 +1513,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p><b>Units</b>:
* Unitless coefficients.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @see CameraCharacteristics#LENS_RADIAL_DISTORTION
@@ -1860,10 +1922,10 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<int[]>("android.request.availableSessionKeys", int[].class);
/**
- * <p>A subset of the available request keys that can be overriden for
+ * <p>A subset of the available request keys that can be overridden for
* physical devices backing a logical multi-camera.</p>
* <p>This is a subset of android.request.availableRequestKeys which contains a list
- * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+ * of keys that can be overridden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
* The respective value of such request key can be obtained by calling
* {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
* individual physical device requests must be built via
@@ -1880,6 +1942,21 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<int[]>("android.request.availablePhysicalCameraRequestKeys", int[].class);
/**
+ * <p>A list of camera characteristics keys that are only available
+ * in case the camera client has camera permission.</p>
+ * <p>The entry contains a subset of
+ * {@link android.hardware.camera2.CameraCharacteristics#getKeys } that require camera clients
+ * to acquire the {@link android.Manifest.permission#CAMERA } permission before calling
+ * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }. If the
+ * permission is not held by the camera client, then the values of the repsective properties
+ * will not be present in {@link android.hardware.camera2.CameraCharacteristics }.</p>
+ * <p>This key is available on all devices.</p>
+ * @hide
+ */
+ public static final Key<int[]> REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION =
+ new Key<int[]>("android.request.characteristicKeysNeedingPermission", int[].class);
+
+ /**
* <p>The list of image formats that are supported by this
* camera device for output streams.</p>
* <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
@@ -2703,6 +2780,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN ISO_STUDIO_TUNGSTEN}</li>
* </ul></p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1
* @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM1
@@ -2744,6 +2822,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p><b>Range of valid values:</b><br>
* Any value listed in {@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1 android.sensor.referenceIlluminant1}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM2
* @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM2
@@ -2766,6 +2845,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* space under the first reference illuminant
* ({@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1 android.sensor.referenceIlluminant1}).</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
*/
@@ -2788,6 +2868,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>This matrix will only be present if the second reference
* illuminant is present.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
*/
@@ -2811,6 +2892,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* match the standard white point for the first reference illuminant
* (i.e. no chromatic adaptation will be applied by this transform).</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
*/
@@ -2836,6 +2918,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>This matrix will only be present if the second reference
* illuminant is present.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
*/
@@ -2857,6 +2940,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* illuminant in the reference sensor colorspace is mapped to D50 in the
* CIE XYZ colorspace.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
*/
@@ -2880,6 +2964,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>This matrix will only be present if the second reference
* illuminant is present.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
*/
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 7ebe0f9a8d8d..44d7364ce43c 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -34,7 +34,6 @@ import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -45,7 +44,6 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
-
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
@@ -97,6 +95,9 @@ public final class CameraManager {
* identifiers, while removable cameras have a unique identifier for each
* individual device, even if they are the same model.</p>
*
+ * <p>This list doesn't contain physical cameras that can only used as part of a logical
+ * multi-camera device.</p>
+ *
* @return The list of currently connected camera devices.
*/
@NonNull
@@ -234,7 +235,13 @@ public final class CameraManager {
* <p>Query the capabilities of a camera device. These capabilities are
* immutable for a given camera.</p>
*
- * @param cameraId The id of the camera device to query
+ * <p>From API level 29, this function can also be used to query the capabilities of physical
+ * cameras that can only be used as part of logical multi-camera. These cameras cannot not be
+ * opened directly via {@link #openCamera}</p>
+ *
+ * @param cameraId The id of the camera device to query. This could be either a standalone
+ * camera ID which can be directly opened by {@link #openCamera}, or a physical camera ID that
+ * can only used as part of a logical multi-camera.
* @return The properties of the given camera
*
* @throws IllegalArgumentException if the cameraId does not match any
@@ -262,7 +269,9 @@ public final class CameraManager {
"Camera service is currently unavailable");
}
try {
- if (!supportsCamera2ApiLocked(cameraId)) {
+ // First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
+ // exception in case cameraId is a hidden physical camera.
+ if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
// Legacy backwards compatibility path; build static info from the camera
// parameters
int id = Integer.parseInt(cameraId);
@@ -454,7 +463,7 @@ public final class CameraManager {
*
* @throws IllegalArgumentException if cameraId or the callback was null,
* or the cameraId does not match any currently or previously available
- * camera device.
+ * camera device returned by {@link #getCameraIdList}.
*
* @throws SecurityException if the application does not have permission to
* access the camera
@@ -778,6 +787,29 @@ public final class CameraManager {
}
/**
+ * Queries the camera service if a cameraId is a hidden physical camera that belongs to a
+ * logical camera device.
+ *
+ * A hidden physical camera is a camera that cannot be opened by the application. But it
+ * can be used as part of a logical camera.
+ *
+ * @param cameraId a non-{@code null} camera identifier
+ * @return {@code true} if cameraId is a hidden physical camera device
+ */
+ private boolean isHiddenPhysicalCamera(String cameraId) {
+ try {
+ ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+ // If no camera service, no support
+ if (cameraService == null) return false;
+
+ return cameraService.isHiddenPhysicalCamera(cameraId);
+ } catch (RemoteException e) {
+ // Camera service is now down, no support for any API level
+ }
+ return false;
+ }
+
+ /**
* A per-process global camera manager instance, to retain a connection to the camera service,
* and to distribute camera availability notices to API-registered callbacks
*/
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index caa99d5cb2a8..486b054e1c00 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -116,7 +116,8 @@ public abstract class CameraMetadata<TKey> {
public List<TKey> getKeys() {
Class<CameraMetadata<TKey>> thisClass = (Class<CameraMetadata<TKey>>) getClass();
return Collections.unmodifiableList(
- getKeys(thisClass, getKeyClass(), this, /*filterTags*/null));
+ getKeys(thisClass, getKeyClass(), this, /*filterTags*/null,
+ /*includeSynthetic*/ true));
}
/**
@@ -131,13 +132,14 @@ public abstract class CameraMetadata<TKey> {
* Optionally, if {@code filterTags} is not {@code null}, then filter out any keys
* whose native {@code tag} is not in {@code filterTags}. The {@code filterTags} array will be
* sorted as a side effect.
+ * {@code includeSynthetic} Includes public syntenthic fields by default.
* </p>
*/
/*package*/ @SuppressWarnings("unchecked")
<TKey> ArrayList<TKey> getKeys(
Class<?> type, Class<TKey> keyClass,
CameraMetadata<TKey> instance,
- int[] filterTags) {
+ int[] filterTags, boolean includeSynthetic) {
if (DEBUG) Log.v(TAG, "getKeysStatic for " + type);
@@ -168,7 +170,7 @@ public abstract class CameraMetadata<TKey> {
}
if (instance == null || instance.getProtected(key) != null) {
- if (shouldKeyBeAdded(key, field, filterTags)) {
+ if (shouldKeyBeAdded(key, field, filterTags, includeSynthetic)) {
keyList.add(key);
if (DEBUG) {
@@ -215,7 +217,8 @@ public abstract class CameraMetadata<TKey> {
}
@SuppressWarnings("rawtypes")
- private static <TKey> boolean shouldKeyBeAdded(TKey key, Field field, int[] filterTags) {
+ private static <TKey> boolean shouldKeyBeAdded(TKey key, Field field, int[] filterTags,
+ boolean includeSynthetic) {
if (key == null) {
throw new NullPointerException("key must not be null");
}
@@ -249,8 +252,7 @@ public abstract class CameraMetadata<TKey> {
if (field.getAnnotation(SyntheticKey.class) != null) {
// This key is synthetic, so calling #getTag will throw IAE
- // TODO: don't just assume all public+synthetic keys are always available
- return true;
+ return includeSynthetic;
}
/*
@@ -811,8 +813,14 @@ public abstract class CameraMetadata<TKey> {
public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10;
/**
- * <p>The camera device is a logical camera backed by two or more physical cameras that are
- * also exposed to the application.</p>
+ * <p>The camera device is a logical camera backed by two or more physical cameras. In
+ * API level 28, the physical cameras must also be exposed to the application via
+ * {@link android.hardware.camera2.CameraManager#getCameraIdList }. Starting from API
+ * level 29, some or all physical cameras may not be independently exposed to the
+ * application, in which case the physical camera IDs will not be available in
+ * {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the application
+ * can still query the physical cameras' characteristics by calling
+ * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }.</p>
* <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
* camera in the system. For an application that switches between front and back cameras,
* the recommendation is to switch between the first rear camera and the first front
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3c6c11d24c7c..a7e185c9853b 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2841,6 +2841,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p><b>Units</b>:
* Quaternion coefficients</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*/
@PublicKey
public static final Key<float[]> LENS_POSE_ROTATION =
@@ -2876,6 +2877,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* with PRIMARY_CAMERA.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
@@ -2947,6 +2949,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
* coordinate system.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_POSE_ROTATION
@@ -2990,6 +2993,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p><b>Units</b>:
* Unitless coefficients.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @deprecated
@@ -3036,6 +3040,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p><b>Units</b>:
* Unitless coefficients.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @see CameraCharacteristics#LENS_RADIAL_DISTORTION
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 010d72f3b17a..9c836c3382db 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -211,7 +211,7 @@ public class NetworkFactory extends Handler {
* Called for every request every time a new NetworkRequest is seen
* and whenever the filterScore or filterNetworkCapabilities change.
*
- * acceptRequest can be overriden to provide complex filter behavior
+ * acceptRequest can be overridden to provide complex filter behavior
* for the incoming requests
*
* For output, this class will call {@link #needNetworkFor} and
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index 9ce2a5bd1b54..be2f9551daff 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -35,7 +35,7 @@ public abstract class NetworkSpecifier {
public abstract boolean satisfiedBy(NetworkSpecifier other);
/**
- * Optional method which can be overriden by concrete implementations of NetworkSpecifier to
+ * Optional method which can be overridden by concrete implementations of NetworkSpecifier to
* check a self-reported UID. A concrete implementation may contain a UID which would be self-
* reported by the caller (since NetworkSpecifier implementations should be non-mutable). This
* function is called by ConnectivityService and is passed the actual UID of the caller -
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 347f60f6b9be..3c43fd189337 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
@@ -165,6 +166,7 @@ public class Environment {
*
* @hide
*/
+ @SystemApi
public static File getOemDirectory() {
return DIR_OEM_ROOT;
}
@@ -175,6 +177,7 @@ public class Environment {
*
* @hide
*/
+ @SystemApi
public static File getOdmDirectory() {
return DIR_ODM_ROOT;
}
@@ -184,6 +187,7 @@ public class Environment {
* software that should persist across simple reflashing of the "system" partition.
* @hide
*/
+ @SystemApi
public static File getVendorDirectory() {
return DIR_VENDOR_ROOT;
}
@@ -194,6 +198,7 @@ public class Environment {
*
* @hide
*/
+ @SystemApi
public static File getProductDirectory() {
return DIR_PRODUCT_ROOT;
}
@@ -204,6 +209,7 @@ public class Environment {
*
* @hide
*/
+ @SystemApi
public static File getProductServicesDirectory() {
return DIR_PRODUCT_SERVICES_ROOT;
}
@@ -1063,7 +1069,6 @@ public class Environment {
return cur;
}
-
/**
* If the given path exists on emulated external storage, return the
* translated backing path hosted on internal storage. This bypasses any
@@ -1074,8 +1079,10 @@ public class Environment {
* must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
* permission.
*
+ * @deprecated disabled now that FUSE has been replaced by sdcardfs
* @hide
*/
+ @Deprecated
public static File maybeTranslateEmulatedPathToInternal(File path) {
return StorageManager.maybeTranslateEmulatedPathToInternal(path);
}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1c8029caab70..a9cb0d9579c9 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,18 @@
package android.os;
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
import static android.system.OsConstants.SPLICE_F_MORE;
import static android.system.OsConstants.SPLICE_F_MOVE;
import static android.system.OsConstants.S_ISFIFO;
@@ -1061,8 +1073,13 @@ public class FileUtils {
mimeTypeFromExt = ContentResolver.MIME_TYPE_DEFAULT;
}
- final String extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(
- mimeType);
+ final String extFromMimeType;
+ if (ContentResolver.MIME_TYPE_DEFAULT.equals(mimeType)) {
+ extFromMimeType = null;
+ } else {
+ extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
+ }
+
if (Objects.equals(mimeType, mimeTypeFromExt) || Objects.equals(ext, extFromMimeType)) {
// Extension maps back to requested MIME type; allow it
} else {
@@ -1180,6 +1197,96 @@ public class FileUtils {
}
/** {@hide} */
+ public static int translateModeStringToPosix(String mode) {
+ int res = 0;
+ if (mode.startsWith("rw")) {
+ res |= O_RDWR | O_CREAT;
+ } else if (mode.startsWith("w")) {
+ res |= O_WRONLY | O_CREAT;
+ } else if (mode.startsWith("r")) {
+ res |= O_RDONLY;
+ } else {
+ throw new IllegalArgumentException("Bad mode: " + mode);
+ }
+ if (mode.indexOf('t') != -1) {
+ res |= O_TRUNC;
+ }
+ if (mode.indexOf('a') != -1) {
+ res |= O_APPEND;
+ }
+ return res;
+ }
+
+ /** {@hide} */
+ public static String translateModePosixToString(int mode) {
+ String res = "";
+ if ((mode & O_RDWR) == O_RDWR) {
+ res += "rw";
+ } else if ((mode & O_WRONLY) == O_WRONLY) {
+ res += "w";
+ } else if ((mode & O_RDONLY) == O_RDONLY) {
+ res += "r";
+ } else {
+ throw new IllegalArgumentException("Bad mode: " + mode);
+ }
+ if ((mode & O_TRUNC) == O_TRUNC) {
+ res += "t";
+ }
+ if ((mode & O_APPEND) == O_APPEND) {
+ res += "a";
+ }
+ return res;
+ }
+
+ /** {@hide} */
+ public static int translateModePosixToPfd(int mode) {
+ int res = 0;
+ if ((mode & O_RDWR) == O_RDWR) {
+ res |= MODE_READ_WRITE;
+ } else if ((mode & O_WRONLY) == O_WRONLY) {
+ res |= MODE_WRITE_ONLY;
+ } else if ((mode & O_RDONLY) == O_RDONLY) {
+ res |= MODE_READ_ONLY;
+ } else {
+ throw new IllegalArgumentException("Bad mode: " + mode);
+ }
+ if ((mode & O_CREAT) == O_CREAT) {
+ res |= MODE_CREATE;
+ }
+ if ((mode & O_TRUNC) == O_TRUNC) {
+ res |= MODE_TRUNCATE;
+ }
+ if ((mode & O_APPEND) == O_APPEND) {
+ res |= MODE_APPEND;
+ }
+ return res;
+ }
+
+ /** {@hide} */
+ public static int translateModePfdToPosix(int mode) {
+ int res = 0;
+ if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {
+ res |= O_RDWR;
+ } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {
+ res |= O_WRONLY;
+ } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {
+ res |= O_RDONLY;
+ } else {
+ throw new IllegalArgumentException("Bad mode: " + mode);
+ }
+ if ((mode & MODE_CREATE) == MODE_CREATE) {
+ res |= O_CREAT;
+ }
+ if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {
+ res |= O_TRUNC;
+ }
+ if ((mode & MODE_APPEND) == MODE_APPEND) {
+ res |= O_APPEND;
+ }
+ return res;
+ }
+
+ /** {@hide} */
@VisibleForTesting
public static class MemoryPipe extends Thread implements AutoCloseable {
private final FileDescriptor[] pipe;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index c9edc531d134..a54c589ab26f 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -559,28 +559,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
* @throws IllegalArgumentException if the given string does not match a known file mode.
*/
public static int parseMode(String mode) {
- final int modeBits;
- if ("r".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
- } else if ("w".equals(mode) || "wt".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
- | ParcelFileDescriptor.MODE_CREATE
- | ParcelFileDescriptor.MODE_TRUNCATE;
- } else if ("wa".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
- | ParcelFileDescriptor.MODE_CREATE
- | ParcelFileDescriptor.MODE_APPEND;
- } else if ("rw".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_WRITE
- | ParcelFileDescriptor.MODE_CREATE;
- } else if ("rwt".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_WRITE
- | ParcelFileDescriptor.MODE_CREATE
- | ParcelFileDescriptor.MODE_TRUNCATE;
- } else {
- throw new IllegalArgumentException("Bad mode '" + mode + "'");
- }
- return modeBits;
+ return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
}
/**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 995156a5a6c5..4fe2d58ff75f 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -38,12 +38,16 @@ public final class UserHandle implements Parcelable {
public static final @UserIdInt int USER_ALL = -1;
/** @hide A user handle to indicate all users on the device */
+ @SystemApi
+ @TestApi
public static final UserHandle ALL = new UserHandle(USER_ALL);
/** @hide A user id to indicate the currently active user */
public static final @UserIdInt int USER_CURRENT = -2;
/** @hide A user handle to indicate the current user of the device */
+ @SystemApi
+ @TestApi
public static final UserHandle CURRENT = new UserHandle(USER_CURRENT);
/** @hide A user id to indicate that we would like to send to the current
@@ -83,6 +87,7 @@ public final class UserHandle implements Parcelable {
public static final int USER_SERIAL_SYSTEM = 0;
/** @hide A user handle to indicate the "system" user of the device */
+ @SystemApi
@TestApi
public static final UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8d5017b4e176..50ca4abd6713 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1521,7 +1521,11 @@ public class StorageManager {
return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
}
- /** {@hide} */
+ /**
+ * @deprecated disabled now that FUSE has been replaced by sdcardfs
+ * @hide
+ */
+ @Deprecated
public static File maybeTranslateEmulatedPathToInternal(File path) {
// Disabled now that FUSE has been replaced by sdcardfs
return path;
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index b12d9cf37485..ee64ca2b8673 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1555,7 +1555,7 @@ public final class DocumentsContract {
*
* <p>Note, that due to internal limitations, if there is already a web link
* intent created for the specified document but with different options,
- * then it may be overriden.
+ * then it may be overridden.
*
* <p>Providers are required to show confirmation UI for all new permissions granted
* for the linked document.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 81b1921dd809..0e782d752815 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -771,7 +771,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #queryRoots(String[])
* @see #queryRecentDocuments(String, String[])
@@ -828,7 +828,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #getDocumentType(String)
*/
@@ -903,7 +903,7 @@ public abstract class DocumentsProvider extends ContentProvider {
/**
* Implementation is provided by the parent class. Throws by default, and
- * cannot be overriden.
+ * cannot be overridden.
*
* @see #createDocument(String, String, String)
*/
@@ -914,7 +914,7 @@ public abstract class DocumentsProvider extends ContentProvider {
/**
* Implementation is provided by the parent class. Throws by default, and
- * cannot be overriden.
+ * cannot be overridden.
*
* @see #deleteDocument(String)
*/
@@ -925,7 +925,7 @@ public abstract class DocumentsProvider extends ContentProvider {
/**
* Implementation is provided by the parent class. Throws by default, and
- * cannot be overriden.
+ * cannot be overridden.
*/
@Override
public final int update(
@@ -1165,7 +1165,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #openDocument(String, String, CancellationSignal)
*/
@@ -1176,7 +1176,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #openDocument(String, String, CancellationSignal)
*/
@@ -1188,7 +1188,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #openDocument(String, String, CancellationSignal)
*/
@@ -1202,7 +1202,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #openDocument(String, String, CancellationSignal)
*/
@@ -1216,7 +1216,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #openDocumentThumbnail(String, Point, CancellationSignal)
* @see #openTypedDocument(String, String, Bundle, CancellationSignal)
@@ -1229,7 +1229,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Cannot be overriden.
+ * Implementation is provided by the parent class. Cannot be overridden.
*
* @see #openDocumentThumbnail(String, Point, CancellationSignal)
* @see #openTypedDocument(String, String, Bundle, CancellationSignal)
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 138e77b69627..02a5e6fd157f 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -181,7 +181,7 @@ public abstract class SearchIndexablesProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+ * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
*/
@Override
public final Uri insert(Uri uri, ContentValues values) {
@@ -189,7 +189,7 @@ public abstract class SearchIndexablesProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+ * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
*/
@Override
public final int delete(Uri uri, String selection, String[] selectionArgs) {
@@ -197,7 +197,7 @@ public abstract class SearchIndexablesProvider extends ContentProvider {
}
/**
- * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+ * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
*/
@Override
public final int update(
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d9ed2aafc9cd..3319c9ecb605 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -989,6 +989,21 @@ public abstract class NotificationListenerService extends Service {
}
/**
+ * Clears listener hints set via {@link #getCurrentListenerHints()}.
+ *
+ * <p>The service should wait for the {@link #onListenerConnected()} event
+ * before performing this operation.
+ */
+ public final void clearRequestedListenerHints() {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().clearRequestedListenerHints(mWrapper);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Sets the desired {@link #getCurrentListenerHints() listener hints}.
*
* <p>
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index f90eb14c796b..f2fa45d59c1e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,7 @@
package android.service.notification;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
@@ -763,6 +764,145 @@ public class ZenModeConfig implements Parcelable {
}
};
+ /**
+ * @return notification policy based on manual and automatic rules
+ */
+ public Policy getConsolidatedNotificationPolicy() {
+ ZenPolicy policy = new ZenPolicy();
+
+ // assumption: manual rule always uses the default policy
+ for (ZenRule rule : automaticRules.values()) {
+ if (rule.isAutomaticActive()) {
+ if (rule.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+ policy.apply(rule.zenPolicy);
+ }
+ }
+ }
+
+ return toNotificationPolicy(policy);
+ }
+
+ /**
+ * Converts a zenPolicy to a notificationPolicy using this ZenModeConfig's values as its
+ * defaults for all unset values in zenPolicy
+ */
+ public Policy toNotificationPolicy(ZenPolicy zenPolicy) {
+ NotificationManager.Policy defaultPolicy = toNotificationPolicy();
+ int priorityCategories = 0;
+ int suppressedVisualEffects = 0;
+ int callSenders = defaultPolicy.priorityCallSenders;
+ int messageSenders = defaultPolicy.priorityMessageSenders;
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REMINDERS,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REMINDERS, defaultPolicy))) {
+ priorityCategories |= PRIORITY_CATEGORY_REMINDERS;
+ }
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_EVENTS,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_EVENTS, defaultPolicy))) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+ }
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MESSAGES,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MESSAGES, defaultPolicy))) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
+ messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityMessageSenders());
+ }
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS, defaultPolicy))) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
+ messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityCallSenders());
+ }
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS,
+ defaultPolicy))) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
+ }
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_ALARMS,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_ALARMS, defaultPolicy))) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+ }
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MEDIA,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MEDIA, defaultPolicy))) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA;
+ }
+
+ if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_SYSTEM,
+ isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_SYSTEM, defaultPolicy))) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_SYSTEM;
+ }
+
+ if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+ defaultPolicy))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ }
+
+ if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_LIGHTS,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_LIGHTS,
+ defaultPolicy))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+ }
+
+ if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_PEEK,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_PEEK,
+ defaultPolicy))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_PEEK;
+ }
+
+ if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_STATUS_BAR,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_STATUS_BAR,
+ defaultPolicy))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+ }
+
+ if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_BADGE,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_BADGE,
+ defaultPolicy))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+ }
+
+ if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_AMBIENT,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_AMBIENT,
+ defaultPolicy))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+ }
+
+ if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
+ defaultPolicy))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+ }
+
+ return new NotificationManager.Policy(priorityCategories, callSenders,
+ messageSenders, suppressedVisualEffects);
+ }
+
+ private boolean isPriorityCategoryEnabled(int categoryType, Policy policy) {
+ return (policy.priorityCategories & categoryType) != 0;
+ }
+
+ private boolean isVisualEffectAllowed(int visualEffect, Policy policy) {
+ return (policy.suppressedVisualEffects & visualEffect) == 0;
+ }
+
+ private int getNotificationPolicySenders(@ZenPolicy.PeopleType int senders) {
+ switch (senders) {
+ case ZenPolicy.PEOPLE_TYPE_ANYONE:
+ return Policy.PRIORITY_SENDERS_ANY;
+ case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+ return Policy.PRIORITY_SENDERS_CONTACTS;
+ case ZenPolicy.PEOPLE_TYPE_STARRED:
+ default:
+ return Policy.PRIORITY_SENDERS_STARRED;
+ }
+
+ }
+
public Policy toNotificationPolicy() {
int priorityCategories = 0;
int priorityCallSenders = Policy.PRIORITY_SENDERS_CONTACTS;
@@ -1315,6 +1455,7 @@ public class ZenModeConfig implements Parcelable {
@UnsupportedAppUsage
public long creationTime; // required for automatic
public String enabler; // package name, only used for manual rules.
+ public ZenPolicy zenPolicy;
public ZenRule() { }
@@ -1335,6 +1476,7 @@ public class ZenModeConfig implements Parcelable {
if (source.readInt() == 1) {
enabler = source.readString();
}
+ zenPolicy = source.readParcelable(null);
}
@Override
@@ -1369,6 +1511,7 @@ public class ZenModeConfig implements Parcelable {
} else {
dest.writeInt(0);
}
+ dest.writeParcelable(zenPolicy, 0);
}
@Override
@@ -1384,6 +1527,7 @@ public class ZenModeConfig implements Parcelable {
.append(",component=").append(component)
.append(",creationTime=").append(creationTime)
.append(",enabler=").append(enabler)
+ .append(",zenPolicy=").append(zenPolicy)
.append(']').toString();
}
@@ -1407,7 +1551,7 @@ public class ZenModeConfig implements Parcelable {
if (component != null) {
component.writeToProto(proto, ZenRuleProto.COMPONENT);
}
-
+ // TODO: write zenPolicy to proto (b/115370281)
proto.end(token);
}
@@ -1454,9 +1598,12 @@ public class ZenModeConfig implements Parcelable {
if (creationTime != to.creationTime) {
d.addLine(item, "creationTime", creationTime, to.creationTime);
}
- if (enabler != to.enabler) {
+ if (!Objects.equals(enabler, to.enabler)) {
d.addLine(item, "enabler", enabler, to.enabler);
}
+ if (!Objects.equals(zenPolicy, to.zenPolicy)) {
+ d.addLine(item, "zenPolicy", zenPolicy, to.zenPolicy);
+ }
}
@Override
@@ -1472,13 +1619,14 @@ public class ZenModeConfig implements Parcelable {
&& Objects.equals(other.condition, condition)
&& Objects.equals(other.component, component)
&& Objects.equals(other.id, id)
- && Objects.equals(other.enabler, enabler);
+ && Objects.equals(other.enabler, enabler)
+ && Objects.equals(other.zenPolicy, zenPolicy);
}
@Override
public int hashCode() {
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
- component, id, enabler);
+ component, id, enabler, zenPolicy);
}
public boolean isAutomaticActive() {
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
new file mode 100644
index 000000000000..88825f08967e
--- /dev/null
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -0,0 +1,868 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import android.annotation.IntDef;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+
+/**
+ * ZenPolicy determines whether to allow certain notifications and their corresponding sounds to
+ * play when a device is in Do Not Disturb mode.
+ * ZenPolicy also dictates the visual effects of notifications that are intercepted when
+ * a device is in Do Not Disturb mode.
+ */
+public final class ZenPolicy implements Parcelable {
+ private ArrayList<Integer> mPriorityCategories;
+ private ArrayList<Integer> mVisualEffects;
+ private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET;
+ private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET;
+
+ /** @hide */
+ @IntDef(prefix = { "PRIORITY_CATEGORY_" }, value = {
+ PRIORITY_CATEGORY_REMINDERS,
+ PRIORITY_CATEGORY_EVENTS,
+ PRIORITY_CATEGORY_MESSAGES,
+ PRIORITY_CATEGORY_CALLS,
+ PRIORITY_CATEGORY_REPEAT_CALLERS,
+ PRIORITY_CATEGORY_ALARMS,
+ PRIORITY_CATEGORY_MEDIA,
+ PRIORITY_CATEGORY_SYSTEM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PriorityCategory {}
+
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_REMINDERS = 0;
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_EVENTS = 1;
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_MESSAGES = 2;
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_CALLS = 3;
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 4;
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_ALARMS = 5;
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_MEDIA = 6;
+ /** @hide */
+ public static final int PRIORITY_CATEGORY_SYSTEM = 7;
+
+ /** @hide */
+ @IntDef(prefix = { "VISUAL_EFFECT_" }, value = {
+ VISUAL_EFFECT_FULL_SCREEN_INTENT,
+ VISUAL_EFFECT_LIGHTS,
+ VISUAL_EFFECT_PEEK,
+ VISUAL_EFFECT_STATUS_BAR,
+ VISUAL_EFFECT_BADGE,
+ VISUAL_EFFECT_AMBIENT,
+ VISUAL_EFFECT_NOTIFICATION_LIST,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VisualEffect {}
+
+ /** @hide */
+ public static final int VISUAL_EFFECT_FULL_SCREEN_INTENT = 0;
+ /** @hide */
+ public static final int VISUAL_EFFECT_LIGHTS = 1;
+ /** @hide */
+ public static final int VISUAL_EFFECT_PEEK = 2;
+ /** @hide */
+ public static final int VISUAL_EFFECT_STATUS_BAR = 3;
+ /** @hide */
+ public static final int VISUAL_EFFECT_BADGE = 4;
+ /** @hide */
+ public static final int VISUAL_EFFECT_AMBIENT = 5;
+ /** @hide */
+ public static final int VISUAL_EFFECT_NOTIFICATION_LIST = 6;
+
+ /** @hide */
+ @IntDef(prefix = { "PEOPLE_TYPE_" }, value = {
+ PEOPLE_TYPE_UNSET,
+ PEOPLE_TYPE_ANYONE,
+ PEOPLE_TYPE_CONTACTS,
+ PEOPLE_TYPE_STARRED,
+ PEOPLE_TYPE_NONE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PeopleType {}
+
+ /**
+ * Used to indicate no preference for the type of people that can bypass dnd for either
+ * calls or messages.
+ */
+ public static final int PEOPLE_TYPE_UNSET = 0;
+
+ /**
+ * Used to indicate all calls or messages can bypass dnd.
+ */
+ public static final int PEOPLE_TYPE_ANYONE = 1;
+
+ /**
+ * Used to indicate calls or messages from contacts can bypass dnd.
+ */
+ public static final int PEOPLE_TYPE_CONTACTS = 2;
+
+ /**
+ * Used to indicate calls or messages from starred contacts can bypass dnd.
+ */
+ public static final int PEOPLE_TYPE_STARRED = 3;
+
+ /**
+ * Used to indicate no calls or messages can bypass dnd.
+ */
+ public static final int PEOPLE_TYPE_NONE = 4;
+
+ /** @hide */
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_UNSET,
+ STATE_ALLOW,
+ STATE_DISALLOW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {}
+
+ /**
+ * Indicates no preference for whether a type of sound or visual effect is or isn't allowed
+ * to play/show when DND is active. Will default to the current set policy.
+ */
+ public static final int STATE_UNSET = 0;
+
+ /**
+ * Indicates a type of sound or visual effect is allowed to play/show when DND is active.
+ */
+ public static final int STATE_ALLOW = 1;
+
+ /**
+ * Indicates a type of sound or visual effect is not allowed to play/show when DND is active.
+ */
+ public static final int STATE_DISALLOW = 2;
+
+ /** @hide */
+ public ZenPolicy() {
+ mPriorityCategories = new ArrayList<>(Collections.nCopies(8, 0));
+ mVisualEffects = new ArrayList<>(Collections.nCopies(7, 0));
+ }
+
+ /**
+ * Message senders that can bypass DND.
+ * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
+ * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
+ */
+ public @PeopleType int getPriorityMessageSenders() {
+ return mPriorityMessages;
+ }
+
+ /**
+ * Callers that can bypass DND.
+ * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
+ * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
+ */
+ public @PeopleType int getPriorityCallSenders() {
+ return mPriorityCalls;
+ }
+
+ /**
+ * Whether this policy wants to allow notifications with category
+ * {@link Notification#CATEGORY_REMINDER} to play sounds and visually appear
+ * or to intercept them when DND is active.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategoryReminders() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_REMINDERS);
+ }
+
+ /**
+ * Whether this policy wants to allow notifications with category
+ * {@link Notification#CATEGORY_EVENT} to play sounds and visually appear
+ * or to intercept them when DND is active.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategoryEvents() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_EVENTS);
+ }
+
+ /**
+ * Whether this policy wants to allow notifications with category
+ * {@link Notification#CATEGORY_MESSAGE} to play sounds and visually appear
+ * or to intercept them when DND is active. Types of message senders that are allowed
+ * are specified by {@link #getPriorityMessageSenders}.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategoryMessages() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_MESSAGES);
+ }
+
+ /**
+ * Whether this policy wants to allow notifications with category
+ * {@link Notification#CATEGORY_CALL} to play sounds and visually appear
+ * or to intercept them when DND is active. Types of callers that are allowed
+ * are specified by {@link #getPriorityCallSenders()}.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategoryCalls() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_CALLS);
+ }
+
+ /**
+ * Whether this policy wants to allow repeat callers (notifications with category
+ * {@link Notification#CATEGORY_CALL} that have recently called) to play sounds and
+ * visually appear or to intercept them when DND is active.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategoryRepeatCallers() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_REPEAT_CALLERS);
+ }
+
+ /**
+ * Whether this policy wants to allow notifications with category
+ * {@link Notification#CATEGORY_ALARM} to play sounds and visually appear
+ * or to intercept them when DND is active.
+ * When alarms are {@link #STATE_DISALLOW disallowed}, the alarm stream will be muted when DND
+ * is active.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategoryAlarms() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_ALARMS);
+ }
+
+ /**
+ * Whether this policy wants to allow media notifications to play sounds and visually appear
+ * or to intercept them when DND is active.
+ * When media is {@link #STATE_DISALLOW disallowed}, the media stream will be muted when DND is
+ * active.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategoryMedia() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_MEDIA);
+ }
+
+ /**
+ * Whether this policy wants to allow system sounds when DND is active.
+ * When system is {@link #STATE_DISALLOW}, the system stream will be muted when DND is active.
+ * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+ */
+ public @State int getPriorityCategorySystem() {
+ return mPriorityCategories.get(PRIORITY_CATEGORY_SYSTEM);
+ }
+
+ /**
+ * Whether this policy allows {@link Notification#fullScreenIntent full screen intents} from
+ * notifications intercepted by DND.
+ */
+ public @State int getVisualEffectFullScreenIntent() {
+ return mVisualEffects.get(VISUAL_EFFECT_FULL_SCREEN_INTENT);
+ }
+
+ /**
+ * Whether this policy allows {@link NotificationChannel#shouldShowLights() notification
+ * lights} from notifications intercepted by DND.
+ */
+ public @State int getVisualEffectLights() {
+ return mVisualEffects.get(VISUAL_EFFECT_LIGHTS);
+ }
+
+ /**
+ * Whether this policy allows peeking from notifications intercepted by DND.
+ */
+ public @State int getVisualEffectPeek() {
+ return mVisualEffects.get(VISUAL_EFFECT_PEEK);
+ }
+
+ /**
+ * Whether this policy allows notifications intercepted by DND from appearing in the status bar
+ * on devices that support status bars.
+ */
+ public @State int getVisualEffectStatusBar() {
+ return mVisualEffects.get(VISUAL_EFFECT_STATUS_BAR);
+ }
+
+ /**
+ * Whether this policy allows {@link NotificationChannel#canShowBadge() badges} from
+ * notifications intercepted by DND on devices that support badging.
+ */
+ public @State int getVisualEffectBadge() {
+ return mVisualEffects.get(VISUAL_EFFECT_BADGE);
+ }
+
+ /**
+ * Whether this policy allows notifications intercepted by DND from appearing on ambient
+ * displays on devices that support ambient display.
+ */
+ public @State int getVisualEffectAmbient() {
+ return mVisualEffects.get(VISUAL_EFFECT_AMBIENT);
+ }
+
+ /**
+ * Whether this policy allows notifications intercepted by DND from appearing in notification
+ * list views like the notification shade or lockscreen on devices that support those
+ * views.
+ */
+ public @State int getVisualEffectNotificationList() {
+ return mVisualEffects.get(VISUAL_EFFECT_NOTIFICATION_LIST);
+ }
+
+ /**
+ * Builder class for {@link ZenPolicy} objects.
+ * Provides a convenient way to set the various fields of a {@link ZenPolicy}. If a field
+ * is not set, it is (@link STATE_UNSET} and will not change the current set policy.
+ */
+ public static class Builder {
+ private ZenPolicy mZenPolicy;
+
+ public Builder() {
+ mZenPolicy = new ZenPolicy();
+ }
+
+ /**
+ * Builds the current ZenPolicy.
+ */
+ public ZenPolicy build() {
+ return mZenPolicy.copy();
+ }
+
+ /**
+ * Allows all notifications to bypass DND and unmutes all streams.
+ */
+ public Builder allowAllSounds() {
+ for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
+ mZenPolicy.mPriorityCategories.set(i, STATE_ALLOW);
+ }
+ mZenPolicy.mPriorityMessages = PEOPLE_TYPE_ANYONE;
+ mZenPolicy.mPriorityCalls = PEOPLE_TYPE_ANYONE;
+ return this;
+ }
+
+ /**
+ * Intercepts all notifications and prevents them from playing sounds
+ * when DND is active. Also mutes alarm, system and media streams.
+ * Notification channels can still play sounds only if they
+ * {@link NotificationChannel#canBypassDnd can bypass DND}. If no channels can bypass DND,
+ * the ringer stream is also muted.
+ */
+ public Builder disallowAllSounds() {
+ for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
+ mZenPolicy.mPriorityCategories.set(i, STATE_DISALLOW);
+ }
+ mZenPolicy.mPriorityMessages = PEOPLE_TYPE_NONE;
+ mZenPolicy.mPriorityCalls = PEOPLE_TYPE_NONE;
+ return this;
+ }
+
+ /**
+ * Allows notifications intercepted by DND to show on all surfaces when DND is active.
+ */
+ public Builder showAllVisualEffects() {
+ for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
+ mZenPolicy.mVisualEffects.set(i, STATE_ALLOW);
+ }
+ return this;
+ }
+
+ /**
+ * Disallows notifications intercepted by DND from showing when DND is active.
+ */
+ public Builder hideAllVisualEffects() {
+ for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
+ mZenPolicy.mVisualEffects.set(i, STATE_DISALLOW);
+ }
+ return this;
+ }
+
+ /**
+ * Unsets a priority category, neither allowing or disallowing. When applying this policy,
+ * unset categories will default to the current applied policy.
+ * @hide
+ */
+ public Builder unsetPriorityCategory(@PriorityCategory int category) {
+ mZenPolicy.mPriorityCategories.set(category, STATE_UNSET);
+
+ if (category == PRIORITY_CATEGORY_MESSAGES) {
+ mZenPolicy.mPriorityMessages = STATE_UNSET;
+ } else if (category == PRIORITY_CATEGORY_CALLS) {
+ mZenPolicy.mPriorityCalls = STATE_UNSET;
+ }
+
+ return this;
+ }
+
+ /**
+ * Unsets a visual effect, neither allowing or disallowing. When applying this policy,
+ * unset effects will default to the current applied policy.
+ * @hide
+ */
+ public Builder unsetVisualEffect(@VisualEffect int effect) {
+ mZenPolicy.mVisualEffects.set(effect, STATE_UNSET);
+ return this;
+ }
+
+ /**
+ * Whether to allow notifications with category {@link Notification#CATEGORY_REMINDER}
+ * to play sounds and visually appear or to intercept them when DND is active.
+ */
+ public Builder allowReminders(boolean allow) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REMINDERS,
+ allow ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether to allow notifications with category {@link Notification#CATEGORY_EVENT}
+ * to play sounds and visually appear or to intercept them when DND is active.
+ */
+ public Builder allowEvents(boolean allow) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_EVENTS,
+ allow ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether to allow notifications with category {@link Notification#CATEGORY_MESSAGE}
+ * that match audienceType to play sounds and visually appear or to intercept
+ * them when DND is active.
+ * @param audienceType message senders that are allowed to bypass DND
+ */
+ public Builder allowMessages(@PeopleType int audienceType) {
+ if (audienceType == STATE_UNSET) {
+ return unsetPriorityCategory(PRIORITY_CATEGORY_MESSAGES);
+ }
+
+ if (audienceType == PEOPLE_TYPE_NONE) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_DISALLOW);
+ } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
+ || audienceType == PEOPLE_TYPE_STARRED) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_ALLOW);
+ } else {
+ return this;
+ }
+
+ mZenPolicy.mPriorityMessages = audienceType;
+ return this;
+ }
+
+ /**
+ * Whether to allow notifications with category {@link Notification#CATEGORY_CALL}
+ * that match audienceType to play sounds and visually appear or to intercept
+ * them when DND is active.
+ * @param audienceType callers that are allowed to bypass DND
+ */
+ public Builder allowCalls(@PeopleType int audienceType) {
+ if (audienceType == STATE_UNSET) {
+ return unsetPriorityCategory(PRIORITY_CATEGORY_CALLS);
+ }
+
+ if (audienceType == PEOPLE_TYPE_NONE) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_DISALLOW);
+ } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
+ || audienceType == PEOPLE_TYPE_STARRED) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_ALLOW);
+ } else {
+ return this;
+ }
+
+ mZenPolicy.mPriorityCalls = audienceType;
+ return this;
+ }
+
+ /**
+ * Whether to allow repeat callers (notifications with category
+ * {@link Notification#CATEGORY_CALL} that have recently called
+ * to play sounds and visually appear.
+ */
+ public Builder allowRepeatCallers(boolean allow) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REPEAT_CALLERS,
+ allow ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+
+ /**
+ * Whether to allow notifications with category {@link Notification#CATEGORY_ALARM}
+ * to play sounds and visually appear or to intercept them when DND is active.
+ * Disallowing alarms will mute the alarm stream when DND is active.
+ */
+ public Builder allowAlarms(boolean allow) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_ALARMS,
+ allow ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether to allow media notifications to play sounds and visually
+ * appear or to intercept them when DND is active.
+ * Disallowing media will mute the media stream when DND is active.
+ */
+ public Builder allowMedia(boolean allow) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MEDIA,
+ allow ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether to allow system sounds to play when DND is active.
+ * Disallowing system sounds will mute the system stream when DND is active.
+ */
+ public Builder allowSystem(boolean allow) {
+ mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_SYSTEM,
+ allow ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted
+ * by DND are shown.
+ */
+ public Builder showFullScreenIntent(boolean show) {
+ mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_FULL_SCREEN_INTENT,
+ show ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether {@link NotificationChannel#shouldShowLights() notification lights} from
+ * notifications intercepted by DND are blocked.
+ */
+ public Builder showLights(boolean show) {
+ mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_LIGHTS,
+ show ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether notifications intercepted by DND are prevented from peeking.
+ */
+ public Builder showPeeking(boolean show) {
+ mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_PEEK,
+ show ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether notifications intercepted by DND are prevented from appearing in the status bar
+ * on devices that support status bars.
+ */
+ public Builder showStatusBarIcons(boolean show) {
+ mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_STATUS_BAR,
+ show ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether {@link NotificationChannel#canShowBadge() badges} from
+ * notifications intercepted by DND are allowed on devices that support badging.
+ */
+ public Builder showBadges(boolean show) {
+ mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_BADGE,
+ show ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether notification intercepted by DND are prevented from appearing on ambient displays
+ * on devices that support ambient display.
+ */
+ public Builder showInAmbientDisplay(boolean show) {
+ mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_AMBIENT,
+ show ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+
+ /**
+ * Whether notification intercepted by DND are prevented from appearing in notification
+ * list views like the notification shade or lockscreen on devices that support those
+ * views.
+ */
+ public Builder showInNotificationList(boolean show) {
+ mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_NOTIFICATION_LIST,
+ show ? STATE_ALLOW : STATE_DISALLOW);
+ return this;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeList(mPriorityCategories);
+ dest.writeList(mVisualEffects);
+ dest.writeInt(mPriorityCalls);
+ dest.writeInt(mPriorityMessages);
+ }
+
+ public static final Parcelable.Creator<ZenPolicy> CREATOR =
+ new Parcelable.Creator<ZenPolicy>() {
+ @Override
+ public ZenPolicy createFromParcel(Parcel source) {
+ ZenPolicy policy = new ZenPolicy();
+ policy.mPriorityCategories = source.readArrayList(Integer.class.getClassLoader());
+ policy.mVisualEffects = source.readArrayList(Integer.class.getClassLoader());
+ policy.mPriorityCalls = source.readInt();
+ policy.mPriorityMessages = source.readInt();
+ return policy;
+ }
+
+ @Override
+ public ZenPolicy[] newArray(int size) {
+ return new ZenPolicy[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return new StringBuilder(ZenPolicy.class.getSimpleName())
+ .append('{')
+ .append("priorityCategories=[").append(priorityCategoriesToString())
+ .append("], visualEffects=[").append(visualEffectsToString())
+ .append(", priorityCalls=").append(stateToString(mPriorityCalls))
+ .append("], priorityMessages=").append(stateToString(mPriorityMessages))
+ .append('}')
+ .toString();
+ }
+
+
+ private String priorityCategoriesToString() {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < mPriorityCategories.size(); i++) {
+ if (mPriorityCategories.get(i) != STATE_UNSET) {
+ builder.append(indexToCategory(i))
+ .append("=")
+ .append(stateToString(mPriorityCategories.get(i)))
+ .append(" ");
+ }
+
+ }
+ return builder.toString();
+ }
+
+ private String visualEffectsToString() {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < mVisualEffects.size(); i++) {
+ if (mVisualEffects.get(i) != STATE_UNSET) {
+ builder.append(indexToVisualEffect(i))
+ .append("=")
+ .append(stateToString(mVisualEffects.get(i)))
+ .append(" ");
+ }
+
+ }
+ return builder.toString();
+ }
+
+ private String indexToVisualEffect(@VisualEffect int visualEffectIndex) {
+ switch (visualEffectIndex) {
+ case VISUAL_EFFECT_FULL_SCREEN_INTENT:
+ return "fullScreenIntent";
+ case VISUAL_EFFECT_LIGHTS:
+ return "lights";
+ case VISUAL_EFFECT_PEEK:
+ return "peek";
+ case VISUAL_EFFECT_STATUS_BAR:
+ return "statusBar";
+ case VISUAL_EFFECT_BADGE:
+ return "badge";
+ case VISUAL_EFFECT_AMBIENT:
+ return "ambient";
+ case VISUAL_EFFECT_NOTIFICATION_LIST:
+ return "notificationList";
+ }
+ return null;
+ }
+
+ private String indexToCategory(@PriorityCategory int categoryIndex) {
+ switch (categoryIndex) {
+ case PRIORITY_CATEGORY_REMINDERS:
+ return "reminders";
+ case PRIORITY_CATEGORY_EVENTS:
+ return "events";
+ case PRIORITY_CATEGORY_MESSAGES:
+ return "messages";
+ case PRIORITY_CATEGORY_CALLS:
+ return "calls";
+ case PRIORITY_CATEGORY_REPEAT_CALLERS:
+ return "repeatCallers";
+ case PRIORITY_CATEGORY_ALARMS:
+ return "alarms";
+ case PRIORITY_CATEGORY_MEDIA:
+ return "media";
+ case PRIORITY_CATEGORY_SYSTEM:
+ return "system";
+ }
+ return null;
+ }
+
+ private String stateToString(@State int state) {
+ switch (state) {
+ case STATE_UNSET:
+ return "unset";
+ case STATE_DISALLOW:
+ return "disallow";
+ case STATE_ALLOW:
+ return "allow";
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ZenPolicy)) return false;
+ if (o == this) return true;
+ final ZenPolicy other = (ZenPolicy) o;
+
+ return Objects.equals(other.mPriorityCategories, mPriorityCategories)
+ && Objects.equals(other.mVisualEffects, mVisualEffects)
+ && other.mPriorityCalls == mPriorityCalls
+ && other.mPriorityMessages == mPriorityMessages;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages);
+ }
+
+ private @ZenPolicy.State int getZenPolicyPriorityCategoryState(@PriorityCategory int
+ category) {
+ switch (category) {
+ case PRIORITY_CATEGORY_REMINDERS:
+ return getPriorityCategoryReminders();
+ case PRIORITY_CATEGORY_EVENTS:
+ return getPriorityCategoryEvents();
+ case PRIORITY_CATEGORY_MESSAGES:
+ return getPriorityCategoryMessages();
+ case PRIORITY_CATEGORY_CALLS:
+ return getPriorityCategoryCalls();
+ case PRIORITY_CATEGORY_REPEAT_CALLERS:
+ return getPriorityCategoryRepeatCallers();
+ case PRIORITY_CATEGORY_ALARMS:
+ return getPriorityCategoryAlarms();
+ case PRIORITY_CATEGORY_MEDIA:
+ return getPriorityCategoryMedia();
+ case PRIORITY_CATEGORY_SYSTEM:
+ return getPriorityCategorySystem();
+ }
+ return -1;
+ }
+
+ private @ZenPolicy.State int getZenPolicyVisualEffectState(@VisualEffect int effect) {
+ switch (effect) {
+ case VISUAL_EFFECT_FULL_SCREEN_INTENT:
+ return getVisualEffectFullScreenIntent();
+ case VISUAL_EFFECT_LIGHTS:
+ return getVisualEffectLights();
+ case VISUAL_EFFECT_PEEK:
+ return getVisualEffectPeek();
+ case VISUAL_EFFECT_STATUS_BAR:
+ return getVisualEffectStatusBar();
+ case VISUAL_EFFECT_BADGE:
+ return getVisualEffectBadge();
+ case VISUAL_EFFECT_AMBIENT:
+ return getVisualEffectAmbient();
+ case VISUAL_EFFECT_NOTIFICATION_LIST:
+ return getVisualEffectNotificationList();
+ }
+ return -1;
+ }
+
+ /** @hide */
+ public boolean isCategoryAllowed(@PriorityCategory int category, boolean defaultVal) {
+ switch (getZenPolicyPriorityCategoryState(category)) {
+ case ZenPolicy.STATE_ALLOW:
+ return true;
+ case ZenPolicy.STATE_DISALLOW:
+ return false;
+ default:
+ return defaultVal;
+ }
+ }
+
+ /** @hide */
+ public boolean isVisualEffectAllowed(@VisualEffect int effect, boolean defaultVal) {
+ switch (getZenPolicyVisualEffectState(effect)) {
+ case ZenPolicy.STATE_ALLOW:
+ return true;
+ case ZenPolicy.STATE_DISALLOW:
+ return false;
+ default:
+ return defaultVal;
+ }
+ }
+
+ /**
+ * Applies another policy on top of this policy
+ * @hide
+ */
+ public void apply(ZenPolicy policyToApply) {
+ // apply priority categories
+ for (int category = 0; category < mPriorityCategories.size(); category++) {
+ if (mPriorityCategories.get(category) == STATE_DISALLOW) {
+ // if a priority category is already disallowed by the policy, cannot allow
+ continue;
+ }
+
+ @State int newState = policyToApply.mPriorityCategories.get(category);
+ if (newState != STATE_UNSET) {
+ mPriorityCategories.set(category, newState);
+
+ if (category == PRIORITY_CATEGORY_MESSAGES
+ && mPriorityMessages < policyToApply.mPriorityMessages) {
+ mPriorityMessages = policyToApply.mPriorityMessages;
+ } else if (category == PRIORITY_CATEGORY_CALLS
+ && mPriorityCalls < policyToApply.mPriorityCalls) {
+ mPriorityCalls = policyToApply.mPriorityCalls;
+ }
+ }
+ }
+
+ // apply visual effects
+ for (int visualEffect = 0; visualEffect < mVisualEffects.size(); visualEffect++) {
+ if (mVisualEffects.get(visualEffect) == STATE_DISALLOW) {
+ // if a visual effect is already disallowed by the policy, cannot allow
+ continue;
+ }
+
+ if (policyToApply.mVisualEffects.get(visualEffect) != STATE_UNSET) {
+ mVisualEffects.set(visualEffect, policyToApply.mVisualEffects.get(visualEffect));
+ }
+ }
+ }
+
+ /**
+ * Makes deep copy of this ZenPolicy.
+ * @hide
+ */
+ public ZenPolicy copy() {
+ final Parcel parcel = Parcel.obtain();
+ try {
+ writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
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/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0119d2e6b8b0..1b3e62d64ef3 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -8116,7 +8116,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
* to be done so that the new margins are taken into account. Left and right margins may be
- * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
+ * overridden by {@link android.view.View#requestLayout()} depending on layout direction.
* Margin values should be positive.
*
* @param left the left margin size
@@ -8146,8 +8146,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
* needs to be done so that the new relative margins are taken into account. Left and right
- * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
- * direction. Margin values should be positive.
+ * margins may be overridden by {@link android.view.View#requestLayout()} depending on
+ * layout direction. Margin values should be positive.
*
* @param start the start margin size
* @param top the top margin size
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/AdapterView.java b/core/java/android/widget/AdapterView.java
index dd6c923e7f47..f3fe16e8a675 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -682,7 +682,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
/**
* Sets the currently selected item. To support accessibility subclasses that
- * override this method must invoke the overriden super method first.
+ * override this method must invoke the overridden super method first.
*
* @param position Index (starting at 0) of the data item to be selected.
*/
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 452e9036cc54..f2e478d0e072 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -653,7 +653,7 @@ public class LinearLayout extends ViewGroup {
}
/**
- * <p>Returns the view at the specified index. This method can be overriden
+ * <p>Returns the view at the specified index. This method can be overridden
* to take into account virtual children. Refer to
* {@link android.widget.TableLayout} and {@link android.widget.TableRow}
* for an example.</p>
@@ -1527,7 +1527,7 @@ public class LinearLayout extends ViewGroup {
/**
* <p>Measure the child according to the parent's measure specs. This
- * method should be overriden by subclasses to force the sizing of
+ * method should be overridden by subclasses to force the sizing of
* children. This method is called by {@link #measureVertical(int, int)} and
* {@link #measureHorizontal(int, int)}.</p>
*
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d9132736232a..a86e6f81f006 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3609,7 +3609,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Read the Text Appearance attributes from a given TypedArray and set its values to the given
* set. If the TypedArray contains a value that was already set in the given attributes, that
- * will be overriden.
+ * will be overridden.
*
* @param context The Context to be used
* @param appearance The TypedArray to read properties from
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 25059bea8bfd..ccbd02764d7e 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -72,7 +72,8 @@ message ListenersDisablingEffectsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 hint = 1;
- repeated ManagedServiceInfoProto listeners = 2;
+ reserved 2; // ManagedServiceInfoProto listeners
+ repeated android.content.ComponentNameProto listener_components = 3;
}
message ManagedServiceInfoProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9ab55d62839b..2bf16d3f99c9 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" />
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
new file mode 100644
index 000000000000..7218b3a286a2
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+import static android.content.pm.PackageBuilder.builder;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.os.Build;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidHidlUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+ private static final String OTHER_LIBRARY = "other.library";
+
+ @Test
+ public void targeted_at_O() {
+ PackageBuilder before = builder()
+ .targetSdkVersion(Build.VERSION_CODES.O);
+
+ // Should add both HIDL libraries
+ PackageBuilder after = builder()
+ .targetSdkVersion(Build.VERSION_CODES.O)
+ .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_not_empty_usesLibraries() {
+ PackageBuilder before = builder()
+ .targetSdkVersion(Build.VERSION_CODES.O)
+ .requiredLibraries(OTHER_LIBRARY);
+
+ // The hidl jars should be added at the start of the list because it
+ // is not on the bootclasspath and the package targets pre-P.
+ PackageBuilder after = builder()
+ .targetSdkVersion(Build.VERSION_CODES.O)
+ .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void targeted_at_O_in_usesLibraries() {
+ PackageBuilder before = builder()
+ .targetSdkVersion(Build.VERSION_CODES.O)
+ .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+ // No change is required because although the HIDL libraries has been removed from
+ // the bootclasspath the package explicitly requests it.
+ checkBackwardsCompatibility(before, before);
+ }
+
+ @Test
+ public void in_usesLibraries() {
+ PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE);
+
+ // No change is required because the package explicitly requests the HIDL libraries
+ // and is targeted at the current version so does not need backwards compatibility.
+ checkBackwardsCompatibility(before, before);
+ }
+
+ @Test
+ public void in_usesOptionalLibraries() {
+ PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE);
+
+ // No change is required because the package explicitly requests the HIDL libraries
+ // and is targeted at the current version so does not need backwards compatibility.
+ checkBackwardsCompatibility(before, before);
+ }
+
+ private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
+ checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
+ }
+}
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/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 9c9f11b76ab4..20fe16251854 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -17,6 +17,22 @@
package android.os;
import static android.os.FileUtils.roundStorageSize;
+import static android.os.FileUtils.translateModePfdToPosix;
+import static android.os.FileUtils.translateModePosixToPfd;
+import static android.os.FileUtils.translateModePosixToString;
+import static android.os.FileUtils.translateModeStringToPosix;
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
@@ -476,6 +492,32 @@ public class FileUtilsTest {
assertEquals(G64, roundStorageSize(G32 + 1));
}
+ @Test
+ public void testTranslateMode() throws Exception {
+ assertTranslate("r", O_RDONLY, MODE_READ_ONLY);
+
+ assertTranslate("rw", O_RDWR | O_CREAT,
+ MODE_READ_WRITE | MODE_CREATE);
+ assertTranslate("rwt", O_RDWR | O_CREAT | O_TRUNC,
+ MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+ assertTranslate("rwa", O_RDWR | O_CREAT | O_APPEND,
+ MODE_READ_WRITE | MODE_CREATE | MODE_APPEND);
+
+ assertTranslate("w", O_WRONLY | O_CREAT,
+ MODE_WRITE_ONLY | MODE_CREATE | MODE_CREATE);
+ assertTranslate("wt", O_WRONLY | O_CREAT | O_TRUNC,
+ MODE_WRITE_ONLY | MODE_CREATE | MODE_TRUNCATE);
+ assertTranslate("wa", O_WRONLY | O_CREAT | O_APPEND,
+ MODE_WRITE_ONLY | MODE_CREATE | MODE_APPEND);
+ }
+
+ private static void assertTranslate(String string, int posix, int pfd) {
+ assertEquals(posix, translateModeStringToPosix(string));
+ assertEquals(string, translateModePosixToString(posix));
+ assertEquals(pfd, translateModePosixToPfd(posix));
+ assertEquals(posix, translateModePfdToPosix(pfd));
+ }
+
private static void assertNameEquals(String expected, File actual) {
assertEquals(expected, actual.getName());
}
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/data/etc/platform.xml b/data/etc/platform.xml
index 6f52fbd1b4f5..c4017d15268f 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -188,6 +188,12 @@
<library name="android.test.runner"
file="/system/framework/android.test.runner.impl.jar" />
+ <!-- In BOOT_JARS historically, and now added to legacy applications. -->
+ <library name="android.hidl.base-V1.0-java"
+ file="/system/framework/android.hidl.base-V1.0-java.jar" />
+ <library name="android.hidl.manager-V1.0-java"
+ file="/system/framework/android.hidl.manager-V1.0-java.jar" />
+
<!-- These are the standard packages that are white-listed to always have internet
access while in power save mode, even if they aren't in the foreground. -->
<allow-in-power-save package="com.android.providers.downloads" />
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/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/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..26f01cecf802 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -62,21 +62,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 +91,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 +148,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 +168,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..8e44d633f505 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"
@@ -75,6 +76,7 @@ static struct {
bool pixelFormatFloat = false;
bool glColorSpace = false;
bool scRGB = false;
+ bool displayP3 = false;
bool contextPriority = false;
bool surfacelessContext = false;
} EglExtensions;
@@ -125,6 +127,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 +161,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 +174,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 +273,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 +288,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 +298,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 +310,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/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/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/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 0734e0dae790..4fbc22663675 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -20,6 +20,7 @@ import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MatrixCursor.RowBuilder;
import android.net.Uri;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -68,6 +69,18 @@ public class BugreportStorageProvider extends FileSystemProvider {
}
@Override
+ public Cursor queryChildDocuments(
+ String parentDocumentId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+ final Cursor c = super.queryChildDocuments(parentDocumentId, projection, sortOrder);
+ final Bundle extras = new Bundle();
+ extras.putCharSequence(DocumentsContract.EXTRA_INFO,
+ getContext().getText(R.string.bugreport_confirm));
+ c.setExtras(extras);
+ return c;
+ }
+
+ @Override
public Cursor queryDocument(String documentId, String[] projection)
throws FileNotFoundException {
if (DOC_ID_ROOT.equals(documentId)) {
diff --git a/packages/SystemUI/res/layout/operator_name.xml b/packages/SystemUI/res/layout/operator_name.xml
index c4f75e927604..015e30a5d050 100644
--- a/packages/SystemUI/res/layout/operator_name.xml
+++ b/packages/SystemUI/res/layout/operator_name.xml
@@ -27,5 +27,6 @@
android:maxLength="20"
android:gravity="center_vertical|start"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:singleLine="true" />
+ android:singleLine="true"
+ android:paddingEnd="5dp" />
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
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/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/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/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/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index d16c2776dc3b..a8f7259050c1 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -68,6 +68,7 @@ import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
+import android.net.ip.IpServer;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -112,10 +113,8 @@ import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.LocalServices;
-import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadController;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
@@ -149,7 +148,7 @@ public class Tethering extends BaseNetworkObserver {
protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
private static final Class[] messageClasses = {
- Tethering.class, TetherMasterSM.class, TetherInterfaceStateMachine.class
+ Tethering.class, TetherMasterSM.class, IpServer.class
};
private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(messageClasses);
@@ -159,21 +158,21 @@ public class Tethering extends BaseNetworkObserver {
.getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
private static class TetherState {
- public final TetherInterfaceStateMachine stateMachine;
+ public final IpServer ipServer;
public int lastState;
public int lastError;
- public TetherState(TetherInterfaceStateMachine sm) {
- stateMachine = sm;
+ public TetherState(IpServer ipServer) {
+ this.ipServer = ipServer;
// Assume all state machines start out available and with no errors.
- lastState = IControlsTethering.STATE_AVAILABLE;
+ lastState = IpServer.STATE_AVAILABLE;
lastError = TETHER_ERROR_NO_ERROR;
}
public boolean isCurrentlyServing() {
switch (lastState) {
- case IControlsTethering.STATE_TETHERED:
- case IControlsTethering.STATE_LOCAL_ONLY:
+ case IpServer.STATE_TETHERED:
+ case IpServer.STATE_LOCAL_ONLY:
return true;
default:
return false;
@@ -198,7 +197,7 @@ public class Tethering extends BaseNetworkObserver {
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
// TODO: Figure out how to merge this and other downstream-tracking objects
// into a single coherent structure.
- private final HashSet<TetherInterfaceStateMachine> mForwardedDownstreams;
+ private final HashSet<IpServer> mForwardedDownstreams;
private final VersionedBroadcastListener mCarrierConfigChange;
private final TetheringDependencies mDeps;
@@ -604,7 +603,7 @@ public class Tethering extends BaseNetworkObserver {
}
public int tether(String iface) {
- return tether(iface, IControlsTethering.STATE_TETHERED);
+ return tether(iface, IpServer.STATE_TETHERED);
}
private int tether(String iface, int requestedState) {
@@ -617,7 +616,7 @@ public class Tethering extends BaseNetworkObserver {
}
// Ignore the error status of the interface. If the interface is available,
// the errors are referring to past tethering attempts anyway.
- if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) {
+ if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
return TETHER_ERROR_UNAVAIL_IFACE;
}
@@ -626,8 +625,7 @@ public class Tethering extends BaseNetworkObserver {
// return an error.
//
// TODO: reexamine the threading and messaging model.
- tetherState.stateMachine.sendMessage(
- TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
+ tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
return TETHER_ERROR_NO_ERROR;
}
}
@@ -644,8 +642,7 @@ public class Tethering extends BaseNetworkObserver {
Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
return TETHER_ERROR_UNAVAIL_IFACE;
}
- tetherState.stateMachine.sendMessage(
- TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+ tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
return TETHER_ERROR_NO_ERROR;
}
}
@@ -689,11 +686,11 @@ public class Tethering extends BaseNetworkObserver {
String iface = mTetherStates.keyAt(i);
if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
erroredList.add(iface);
- } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+ } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
availableList.add(iface);
- } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_ONLY) {
+ } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
localOnlyList.add(iface);
- } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+ } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
if (cfg.isUsb(iface)) {
usbTethered = true;
} else if (cfg.isWifi(iface)) {
@@ -882,10 +879,10 @@ public class Tethering extends BaseNetworkObserver {
synchronized (Tethering.this.mPublicSync) {
if (!usbConnected && mRndisEnabled) {
// Turn off tethering if it was enabled and there is a disconnect.
- tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB);
+ tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
} else if (usbConfigured && rndisEnabled) {
// Tether if rndis is enabled and usb is configured.
- tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB);
+ tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
}
mRndisEnabled = usbConfigured && rndisEnabled;
}
@@ -959,15 +956,15 @@ public class Tethering extends BaseNetworkObserver {
if (!TextUtils.isEmpty(ifname)) {
final TetherState ts = mTetherStates.get(ifname);
if (ts != null) {
- ts.stateMachine.unwanted();
+ ts.ipServer.unwanted();
return;
}
}
for (int i = 0; i < mTetherStates.size(); i++) {
- TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
- if (tism.interfaceType() == TETHERING_WIFI) {
- tism.unwanted();
+ final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
+ if (ipServer.interfaceType() == TETHERING_WIFI) {
+ ipServer.unwanted();
return;
}
}
@@ -978,15 +975,15 @@ public class Tethering extends BaseNetworkObserver {
}
private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
- // Map wifiIpMode values to IControlsTethering serving states, inferring
+ // Map wifiIpMode values to IpServer.Callback serving states, inferring
// from mWifiTetherRequested as a final "best guess".
final int ipServingMode;
switch (wifiIpMode) {
case IFACE_IP_MODE_TETHERED:
- ipServingMode = IControlsTethering.STATE_TETHERED;
+ ipServingMode = IpServer.STATE_TETHERED;
break;
case IFACE_IP_MODE_LOCAL_ONLY:
- ipServingMode = IControlsTethering.STATE_LOCAL_ONLY;
+ ipServingMode = IpServer.STATE_LOCAL_ONLY;
break;
default:
mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
@@ -1041,12 +1038,12 @@ public class Tethering extends BaseNetworkObserver {
private void changeInterfaceState(String ifname, int requestedState) {
final int result;
switch (requestedState) {
- case IControlsTethering.STATE_UNAVAILABLE:
- case IControlsTethering.STATE_AVAILABLE:
+ case IpServer.STATE_UNAVAILABLE:
+ case IpServer.STATE_AVAILABLE:
result = untether(ifname);
break;
- case IControlsTethering.STATE_TETHERED:
- case IControlsTethering.STATE_LOCAL_ONLY:
+ case IpServer.STATE_TETHERED:
+ case IpServer.STATE_LOCAL_ONLY:
result = tether(ifname, requestedState);
break;
default:
@@ -1104,7 +1101,7 @@ public class Tethering extends BaseNetworkObserver {
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+ if (tetherState.lastState == IpServer.STATE_TETHERED) {
list.add(mTetherStates.keyAt(i));
}
}
@@ -1117,7 +1114,7 @@ public class Tethering extends BaseNetworkObserver {
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+ if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
list.add(mTetherStates.keyAt(i));
}
}
@@ -1177,7 +1174,7 @@ public class Tethering extends BaseNetworkObserver {
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastState != IControlsTethering.STATE_TETHERED) {
+ if (tetherState.lastState != IpServer.STATE_TETHERED) {
continue; // Skip interfaces that aren't tethered.
}
String iface = mTetherStates.keyAt(i);
@@ -1231,7 +1228,7 @@ public class Tethering extends BaseNetworkObserver {
// Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
// so that the garbage collector does not clean up the state machine before it has a chance
// to tear itself down.
- private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+ private final ArrayList<IpServer> mNotifyList;
private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
private final OffloadWrapper mOffload;
@@ -1268,17 +1265,19 @@ public class Tethering extends BaseNetworkObserver {
public boolean processMessage(Message message) {
logMessage(this, message.what);
switch (message.what) {
- case EVENT_IFACE_SERVING_STATE_ACTIVE:
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+ case EVENT_IFACE_SERVING_STATE_ACTIVE: {
+ final IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who);
transitionTo(mTetherModeAliveState);
break;
- case EVENT_IFACE_SERVING_STATE_INACTIVE:
- who = (TetherInterfaceStateMachine) message.obj;
+ }
+ case EVENT_IFACE_SERVING_STATE_INACTIVE: {
+ final IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who);
break;
+ }
case EVENT_IFACE_UPDATE_LINKPROPERTIES:
// Silently ignore these for now.
break;
@@ -1410,8 +1409,8 @@ public class Tethering extends BaseNetworkObserver {
protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
mCurrentUpstreamIfaceSet = ifaces;
- for (TetherInterfaceStateMachine sm : mNotifyList) {
- sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, ifaces);
+ for (IpServer ipServer : mNotifyList) {
+ ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
}
}
@@ -1420,13 +1419,13 @@ public class Tethering extends BaseNetworkObserver {
mOffload.updateUpstreamNetworkState(ns);
}
- private void handleInterfaceServingStateActive(int mode, TetherInterfaceStateMachine who) {
+ private void handleInterfaceServingStateActive(int mode, IpServer who) {
if (mNotifyList.indexOf(who) < 0) {
mNotifyList.add(who);
mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
}
- if (mode == IControlsTethering.STATE_TETHERED) {
+ if (mode == IpServer.STATE_TETHERED) {
// No need to notify OffloadController just yet as there are no
// "offload-able" prefixes to pass along. This will handled
// when the TISM informs Tethering of its LinkProperties.
@@ -1441,10 +1440,10 @@ public class Tethering extends BaseNetworkObserver {
final WifiManager mgr = getWifiManager();
final String iface = who.interfaceName();
switch (mode) {
- case IControlsTethering.STATE_TETHERED:
+ case IpServer.STATE_TETHERED:
mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
break;
- case IControlsTethering.STATE_LOCAL_ONLY:
+ case IpServer.STATE_LOCAL_ONLY:
mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
break;
default:
@@ -1454,7 +1453,7 @@ public class Tethering extends BaseNetworkObserver {
}
}
- private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
+ private void handleInterfaceServingStateInactive(IpServer who) {
mNotifyList.remove(who);
mIPv6TetheringCoordinator.removeActiveDownstream(who);
mOffload.excludeDownstreamInterface(who.interfaceName());
@@ -1563,10 +1562,10 @@ public class Tethering extends BaseNetworkObserver {
boolean retValue = true;
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE: {
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+ IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who);
- who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+ who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
mCurrentUpstreamIfaceSet);
// If there has been a change and an upstream is now
// desired, kick off the selection process.
@@ -1577,7 +1576,7 @@ public class Tethering extends BaseNetworkObserver {
break;
}
case EVENT_IFACE_SERVING_STATE_INACTIVE: {
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+ IpServer who = (IpServer) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who);
@@ -1591,7 +1590,7 @@ public class Tethering extends BaseNetworkObserver {
if (DBG) {
Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
" live requests:");
- for (TetherInterfaceStateMachine o : mNotifyList) {
+ for (IpServer o : mNotifyList) {
Log.d(TAG, " " + o);
}
}
@@ -1605,7 +1604,7 @@ public class Tethering extends BaseNetworkObserver {
}
case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
final LinkProperties newLp = (LinkProperties) message.obj;
- if (message.arg1 == IControlsTethering.STATE_TETHERED) {
+ if (message.arg1 == IpServer.STATE_TETHERED) {
mOffload.updateDownstreamLinkProperties(newLp);
} else {
mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
@@ -1650,7 +1649,7 @@ public class Tethering extends BaseNetworkObserver {
boolean retValue = true;
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE:
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+ IpServer who = (IpServer) message.obj;
who.sendMessage(mErrorNotification);
break;
case CMD_CLEAR_ERROR:
@@ -1665,8 +1664,8 @@ public class Tethering extends BaseNetworkObserver {
void notify(int msgType) {
mErrorNotification = msgType;
- for (TetherInterfaceStateMachine sm : mNotifyList) {
- sm.sendMessage(msgType);
+ for (IpServer ipServer : mNotifyList) {
+ ipServer.sendMessage(msgType);
}
}
@@ -1676,7 +1675,7 @@ public class Tethering extends BaseNetworkObserver {
@Override
public void enter() {
Log.e(TAG, "Error in setIpForwardingEnabled");
- notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR);
+ notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
}
}
@@ -1684,7 +1683,7 @@ public class Tethering extends BaseNetworkObserver {
@Override
public void enter() {
Log.e(TAG, "Error in setIpForwardingDisabled");
- notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR);
+ notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
}
}
@@ -1692,7 +1691,7 @@ public class Tethering extends BaseNetworkObserver {
@Override
public void enter() {
Log.e(TAG, "Error in startTethering");
- notify(TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR);
+ notify(IpServer.CMD_START_TETHERING_ERROR);
try {
mNMService.setIpForwardingEnabled(false);
} catch (Exception e) {}
@@ -1703,7 +1702,7 @@ public class Tethering extends BaseNetworkObserver {
@Override
public void enter() {
Log.e(TAG, "Error in stopTethering");
- notify(TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR);
+ notify(IpServer.CMD_STOP_TETHERING_ERROR);
try {
mNMService.setIpForwardingEnabled(false);
} catch (Exception e) {}
@@ -1714,7 +1713,7 @@ public class Tethering extends BaseNetworkObserver {
@Override
public void enter() {
Log.e(TAG, "Error in setDnsForwarders");
- notify(TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR);
+ notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
try {
mNMService.stopTethering();
} catch (Exception e) {}
@@ -1771,15 +1770,15 @@ public class Tethering extends BaseNetworkObserver {
// Maybe add prefixes or addresses for downstreams, depending on
// the IP serving mode of each.
- for (TetherInterfaceStateMachine tism : mNotifyList) {
- final LinkProperties lp = tism.linkProperties();
+ for (IpServer ipServer : mNotifyList) {
+ final LinkProperties lp = ipServer.linkProperties();
- switch (tism.servingMode()) {
- case IControlsTethering.STATE_UNAVAILABLE:
- case IControlsTethering.STATE_AVAILABLE:
+ switch (ipServer.servingMode()) {
+ case IpServer.STATE_UNAVAILABLE:
+ case IpServer.STATE_AVAILABLE:
// No usable LinkProperties in these states.
continue;
- case IControlsTethering.STATE_TETHERED:
+ case IpServer.STATE_TETHERED:
// Only add IPv4 /32 and IPv6 /128 prefixes. The
// directly-connected prefixes will be sent as
// downstream "offload-able" prefixes.
@@ -1789,7 +1788,7 @@ public class Tethering extends BaseNetworkObserver {
localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
}
break;
- case IControlsTethering.STATE_LOCAL_ONLY:
+ case IpServer.STATE_LOCAL_ONLY:
// Add prefixes covering all local IPs.
localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
break;
@@ -1826,16 +1825,16 @@ public class Tethering extends BaseNetworkObserver {
pw.print(iface + " - ");
switch (tetherState.lastState) {
- case IControlsTethering.STATE_UNAVAILABLE:
+ case IpServer.STATE_UNAVAILABLE:
pw.print("UnavailableState");
break;
- case IControlsTethering.STATE_AVAILABLE:
+ case IpServer.STATE_AVAILABLE:
pw.print("AvailableState");
break;
- case IControlsTethering.STATE_TETHERED:
+ case IpServer.STATE_TETHERED:
pw.print("TetheredState");
break;
- case IControlsTethering.STATE_LOCAL_ONLY:
+ case IpServer.STATE_LOCAL_ONLY:
pw.print("LocalHotspotState");
break;
default:
@@ -1873,28 +1872,26 @@ public class Tethering extends BaseNetworkObserver {
return false;
}
- private IControlsTethering makeControlCallback(String ifname) {
- return new IControlsTethering() {
+ private IpServer.Callback makeControlCallback() {
+ return new IpServer.Callback() {
@Override
- public void updateInterfaceState(
- TetherInterfaceStateMachine who, int state, int lastError) {
- notifyInterfaceStateChange(ifname, who, state, lastError);
+ public void updateInterfaceState(IpServer who, int state, int lastError) {
+ notifyInterfaceStateChange(who, state, lastError);
}
@Override
- public void updateLinkProperties(
- TetherInterfaceStateMachine who, LinkProperties newLp) {
- notifyLinkPropertiesChanged(ifname, who, newLp);
+ public void updateLinkProperties(IpServer who, LinkProperties newLp) {
+ notifyLinkPropertiesChanged(who, newLp);
}
};
}
// TODO: Move into TetherMasterSM.
- private void notifyInterfaceStateChange(
- String iface, TetherInterfaceStateMachine who, int state, int error) {
+ private void notifyInterfaceStateChange(IpServer who, int state, int error) {
+ final String iface = who.interfaceName();
synchronized (mPublicSync) {
final TetherState tetherState = mTetherStates.get(iface);
- if (tetherState != null && tetherState.stateMachine.equals(who)) {
+ if (tetherState != null && tetherState.ipServer.equals(who)) {
tetherState.lastState = state;
tetherState.lastError = error;
} else {
@@ -1908,7 +1905,7 @@ public class Tethering extends BaseNetworkObserver {
// Notify that we're tethering (or not) this interface.
// This is how data saver for instance knows if the user explicitly
// turned on tethering (thus keeping us from being in data saver mode).
- mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
+ mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
} catch (RemoteException e) {
// Not really very much we can do here.
}
@@ -1921,12 +1918,12 @@ public class Tethering extends BaseNetworkObserver {
}
int which;
switch (state) {
- case IControlsTethering.STATE_UNAVAILABLE:
- case IControlsTethering.STATE_AVAILABLE:
+ case IpServer.STATE_UNAVAILABLE:
+ case IpServer.STATE_AVAILABLE:
which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
break;
- case IControlsTethering.STATE_TETHERED:
- case IControlsTethering.STATE_LOCAL_ONLY:
+ case IpServer.STATE_TETHERED:
+ case IpServer.STATE_LOCAL_ONLY:
which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
break;
default:
@@ -1937,12 +1934,12 @@ public class Tethering extends BaseNetworkObserver {
sendTetherStateChangedBroadcast();
}
- private void notifyLinkPropertiesChanged(String iface, TetherInterfaceStateMachine who,
- LinkProperties newLp) {
+ private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
+ final String iface = who.interfaceName();
final int state;
synchronized (mPublicSync) {
final TetherState tetherState = mTetherStates.get(iface);
- if (tetherState != null && tetherState.stateMachine.equals(who)) {
+ if (tetherState != null && tetherState.ipServer.equals(who)) {
state = tetherState.lastState;
} else {
mLog.log("got notification from stale iface " + iface);
@@ -1952,7 +1949,7 @@ public class Tethering extends BaseNetworkObserver {
mLog.log(String.format(
"OBSERVED LinkProperties update iface=%s state=%s lp=%s",
- iface, IControlsTethering.getStateString(state), newLp));
+ iface, IpServer.getStateString(state), newLp));
final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
mTetherMasterSM.sendMessage(which, state, 0, newLp);
}
@@ -1976,11 +1973,11 @@ public class Tethering extends BaseNetworkObserver {
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState(
- new TetherInterfaceStateMachine(
- iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
- makeControlCallback(iface), mConfig.enableLegacyDhcpServer, mDeps));
+ new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
+ makeControlCallback(), mConfig.enableLegacyDhcpServer,
+ mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
- tetherState.stateMachine.start();
+ tetherState.ipServer.start();
}
private void stopTrackingInterfaceLocked(final String iface) {
@@ -1989,36 +1986,11 @@ public class Tethering extends BaseNetworkObserver {
mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
return;
}
- tetherState.stateMachine.stop();
+ tetherState.ipServer.stop();
mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
mTetherStates.remove(iface);
}
- private static String getIPv4DefaultRouteInterface(NetworkState ns) {
- if (ns == null) return null;
- return getInterfaceForDestination(ns.linkProperties, Inet4Address.ANY);
- }
-
- private static String getIPv6DefaultRouteInterface(NetworkState ns) {
- if (ns == null) return null;
- // An upstream network's IPv6 capability is currently only useful if it
- // can be 64share'd downstream (RFC 7278). For now, that means mobile
- // upstream networks only.
- if (ns.networkCapabilities == null ||
- !ns.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
- return null;
- }
-
- return getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY);
- }
-
- private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
- final RouteInfo ri = (lp != null)
- ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
- : null;
- return (ri != null) ? ri.getInterface() : null;
- }
-
private static String[] copy(String[] strarray) {
return Arrays.copyOf(strarray, strarray.length);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
deleted file mode 100644
index 2b813475222f..000000000000
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity.tethering;
-
-import android.net.LinkProperties;
-
-/**
- * @hide
- *
- * Interface with methods necessary to notify that a given interface is ready for tethering.
- *
- * Rename to something more representative, e.g. IpServingControlCallback.
- *
- * All methods MUST be called on the TetherMasterSM main Looper's thread.
- */
-public class IControlsTethering {
- public static final int STATE_UNAVAILABLE = 0;
- public static final int STATE_AVAILABLE = 1;
- public static final int STATE_TETHERED = 2;
- public static final int STATE_LOCAL_ONLY = 3;
-
- public static String getStateString(int state) {
- switch (state) {
- case STATE_UNAVAILABLE: return "UNAVAILABLE";
- case STATE_AVAILABLE: return "AVAILABLE";
- case STATE_TETHERED: return "TETHERED";
- case STATE_LOCAL_ONLY: return "LOCAL_ONLY";
- }
- return "UNKNOWN: " + state;
- }
-
- /**
- * Notify that |who| has changed its tethering state.
- *
- * TODO: Remove the need for the |who| argument.
- *
- * @param who corresponding instance of a TetherInterfaceStateMachine
- * @param state one of IControlsTethering.STATE_*
- * @param lastError one of ConnectivityManager.TETHER_ERROR_*
- */
- public void updateInterfaceState(TetherInterfaceStateMachine who, int state, int lastError) {}
-
- /**
- * Notify that |who| has new LinkProperties.
- *
- * TODO: Remove the need for the |who| argument.
- *
- * @param who corresponding instance of a TetherInterfaceStateMachine
- * @param newLp the new LinkProperties to report
- */
- public void updateLinkProperties(TetherInterfaceStateMachine who, LinkProperties newLp) {}
-}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index ba67c94d1cd4..100014898127 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity.tethering;
import android.net.ConnectivityManager;
+import android.net.ip.IpServer;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -50,19 +51,19 @@ public class IPv6TetheringCoordinator {
private static final boolean VDBG = false;
private static class Downstream {
- public final TetherInterfaceStateMachine tism;
- public final int mode; // IControlsTethering.STATE_*
+ public final IpServer ipServer;
+ public final int mode; // IpServer.STATE_*
// Used to append to a ULA /48, constructing a ULA /64 for local use.
public final short subnetId;
- Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId) {
- this.tism = tism;
+ Downstream(IpServer ipServer, int mode, short subnetId) {
+ this.ipServer = ipServer;
this.mode = mode;
this.subnetId = subnetId;
}
}
- private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+ private final ArrayList<IpServer> mNotifyList;
private final SharedLog mLog;
// NOTE: mActiveDownstreams is a list and not a hash data structure because
// we keep active downstreams in arrival order. This is done so /64s can
@@ -74,8 +75,7 @@ public class IPv6TetheringCoordinator {
private short mNextSubnetId;
private NetworkState mUpstreamNetworkState;
- public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
- SharedLog log) {
+ public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
mNotifyList = notifyList;
mLog = log.forSubComponent(TAG);
mActiveDownstreams = new LinkedList<>();
@@ -83,7 +83,7 @@ public class IPv6TetheringCoordinator {
mNextSubnetId = 0;
}
- public void addActiveDownstream(TetherInterfaceStateMachine downstream, int mode) {
+ public void addActiveDownstream(IpServer downstream, int mode) {
if (findDownstream(downstream) == null) {
// Adding a new downstream appends it to the list. Adding a
// downstream a second time without first removing it has no effect.
@@ -98,7 +98,7 @@ public class IPv6TetheringCoordinator {
}
}
- public void removeActiveDownstream(TetherInterfaceStateMachine downstream) {
+ public void removeActiveDownstream(IpServer downstream) {
stopIPv6TetheringOn(downstream);
if (mActiveDownstreams.remove(findDownstream(downstream))) {
updateIPv6TetheringInterfaces();
@@ -133,8 +133,8 @@ public class IPv6TetheringCoordinator {
}
private void stopIPv6TetheringOnAllInterfaces() {
- for (TetherInterfaceStateMachine sm : mNotifyList) {
- stopIPv6TetheringOn(sm);
+ for (IpServer ipServer : mNotifyList) {
+ stopIPv6TetheringOn(ipServer);
}
}
@@ -156,28 +156,28 @@ public class IPv6TetheringCoordinator {
}
private void updateIPv6TetheringInterfaces() {
- for (TetherInterfaceStateMachine sm : mNotifyList) {
- final LinkProperties lp = getInterfaceIPv6LinkProperties(sm);
- sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
+ for (IpServer ipServer : mNotifyList) {
+ final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
+ ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
break;
}
}
- private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) {
- if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
+ private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
+ if (ipServer.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
// TODO: Figure out IPv6 support on PAN interfaces.
return null;
}
- final Downstream ds = findDownstream(sm);
+ final Downstream ds = findDownstream(ipServer);
if (ds == null) return null;
- if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) {
+ if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
// Build a Unique Locally-assigned Prefix configuration.
return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
}
- // This downstream is in IControlsTethering.STATE_TETHERED mode.
+ // This downstream is in IpServer.STATE_TETHERED mode.
if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
return null;
}
@@ -188,7 +188,7 @@ public class IPv6TetheringCoordinator {
// IPv6 toward the oldest (first requested) active downstream.
final Downstream currentActive = mActiveDownstreams.peek();
- if (currentActive != null && currentActive.tism == sm) {
+ if (currentActive != null && currentActive.ipServer == ipServer) {
final LinkProperties lp = getIPv6OnlyLinkProperties(
mUpstreamNetworkState.linkProperties);
if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
@@ -199,9 +199,9 @@ public class IPv6TetheringCoordinator {
return null;
}
- Downstream findDownstream(TetherInterfaceStateMachine tism) {
+ Downstream findDownstream(IpServer ipServer) {
for (Downstream ds : mActiveDownstreams) {
- if (ds.tism == tism) return ds;
+ if (ds.ipServer == ipServer) return ds;
}
return null;
}
@@ -304,7 +304,7 @@ public class IPv6TetheringCoordinator {
ns.linkProperties);
}
- private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) {
- sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+ private static void stopIPv6TetheringOn(IpServer ipServer) {
+ ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index caa867c616b8..8b4006916736 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,6 +21,7 @@ import android.net.INetd;
import android.net.NetworkRequest;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
+import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams;
import android.net.util.NetdService;
@@ -49,20 +50,12 @@ public class TetheringDependencies {
}
public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
- ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+ ArrayList<IpServer> notifyList, SharedLog log) {
return new IPv6TetheringCoordinator(notifyList, log);
}
- public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
- return new RouterAdvertisementDaemon(ifParams);
- }
-
- public InterfaceParams getInterfaceParams(String ifName) {
- return InterfaceParams.getByName(ifName);
- }
-
- public INetd getNetdService() {
- return NetdService.getInstance();
+ public IpServer.Dependencies getIpServerDependencies() {
+ return new IpServer.Dependencies();
}
public boolean isTetheringSupported() {
@@ -72,9 +65,4 @@ public class TetheringDependencies {
public NetworkRequest getDefaultNetworkRequest() {
return null;
}
-
- public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface, DhcpServingParams params,
- SharedLog log) {
- return new DhcpServer(looper, iface, params, log);
- }
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 03b7652e32ec..6e4d9e03f28f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -345,7 +345,7 @@ public class NotificationManagerService extends SystemService {
private String mSoundNotificationKey;
private String mVibrateNotificationKey;
- private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
+ private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
new SparseArray<>();
private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
private int mListenerHints; // right now, all hints are global
@@ -1784,10 +1784,10 @@ public class NotificationManagerService extends SystemService {
private ArrayList<ComponentName> getSuppressors() {
ArrayList<ComponentName> names = new ArrayList<ComponentName>();
for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
- ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+ ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
- for (ManagedServiceInfo info : serviceInfoList) {
- names.add(info.component);
+ for (ComponentName info : serviceInfoList) {
+ names.add(info);
}
}
@@ -1803,11 +1803,10 @@ public class NotificationManagerService extends SystemService {
for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
final int hint = mListenersDisablingEffects.keyAt(i);
- final ArraySet<ManagedServiceInfo> listeners =
- mListenersDisablingEffects.valueAt(i);
+ final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
if (hints == 0 || (hint & hints) == hint) {
- removed = removed || listeners.remove(info);
+ removed |= listeners.remove(info.component);
}
}
@@ -1830,18 +1829,18 @@ public class NotificationManagerService extends SystemService {
private void addDisabledHint(ManagedServiceInfo info, int hint) {
if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
- mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
+ mListenersDisablingEffects.put(hint, new ArraySet<>());
}
- ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
- hintListeners.add(info);
+ ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
+ hintListeners.add(info.component);
}
private int calculateHints() {
int hints = 0;
for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
int hint = mListenersDisablingEffects.keyAt(i);
- ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+ ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
if (!serviceInfoList.isEmpty()) {
hints |= hint;
@@ -2955,6 +2954,21 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void clearRequestedListenerHints(INotificationListener token) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mNotificationLock) {
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ removeDisabledHints(info);
+ updateListenerHintsLocked();
+ updateEffectsSuppressorLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void requestHintsFromListener(INotificationListener token, int hints) {
final long identity = Binder.clearCallingIdentity();
try {
@@ -3860,11 +3874,12 @@ public class NotificationManagerService extends SystemService {
proto.write(
ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
- final ArraySet<ManagedServiceInfo> listeners =
+ final ArraySet<ComponentName> listeners =
mListenersDisablingEffects.valueAt(i);
for (int j = 0; j < listeners.size(); j++) {
- final ManagedServiceInfo listener = listeners.valueAt(i);
- listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
+ final ComponentName componentName = listeners.valueAt(i);
+ componentName.writeToProto(proto,
+ ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
}
proto.end(effectsToken);
@@ -4003,15 +4018,14 @@ public class NotificationManagerService extends SystemService {
if (i > 0) pw.print(';');
pw.print("hint[" + hint + "]:");
- final ArraySet<ManagedServiceInfo> listeners =
- mListenersDisablingEffects.valueAt(i);
+ final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
final int listenerSize = listeners.size();
for (int j = 0; j < listenerSize; j++) {
if (i > 0) pw.print(',');
- final ManagedServiceInfo listener = listeners.valueAt(i);
+ final ComponentName listener = listeners.valueAt(i);
if (listener != null) {
- pw.print(listener.component);
+ pw.print(listener);
}
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6ac72d3ae167..4dd2bf25ed67 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -501,9 +501,14 @@ public class ZenModeHelper {
}
protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
- return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
- NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
- rule.creationTime);
+ if (rule.zenPolicy != null) {
+ return new AutomaticZenRule(rule.name, rule.component, rule.conditionId, rule.zenPolicy,
+ rule.enabled, rule.creationTime);
+ } else {
+ return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
+ NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
+ rule.creationTime);
+ }
}
public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
@@ -667,6 +672,9 @@ public class ZenModeHelper {
}
}
+ /**
+ * @return user-specified default notification policy for priority only do not disturb
+ */
public Policy getNotificationPolicy() {
return getNotificationPolicy(mConfig);
}
@@ -675,6 +683,9 @@ public class ZenModeHelper {
return config == null ? null : config.toNotificationPolicy();
}
+ /**
+ * Sets the global notification policy used for priority only do not disturb
+ */
public void setNotificationPolicy(Policy policy) {
if (policy == null || mConfig == null) return;
synchronized (mConfig) {
@@ -770,9 +781,7 @@ public class ZenModeHelper {
ComponentName triggeringComponent, boolean setRingerMode) {
final String val = Integer.toString(config.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
- if (!evaluateZenMode(reason, setRingerMode)) {
- applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
- }
+ evaluateZenMode(reason, setRingerMode);
mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
}
@@ -798,7 +807,7 @@ public class ZenModeHelper {
}
@VisibleForTesting
- protected boolean evaluateZenMode(String reason, boolean setRingerMode) {
+ protected void evaluateZenMode(String reason, boolean setRingerMode) {
if (DEBUG) Log.d(TAG, "evaluateZenMode");
final int zenBefore = mZenMode;
final int zen = computeZenMode();
@@ -813,7 +822,6 @@ public class ZenModeHelper {
if (zen != zenBefore) {
mHandler.postDispatchOnZenModeChanged();
}
- return true;
}
private void updateRingerModeAffectedStreams() {
@@ -822,7 +830,9 @@ public class ZenModeHelper {
}
}
+
private int computeZenMode() {
+ // TODO: use mConfig.zenPolicy
if (mConfig == null) return Global.ZEN_MODE_OFF;
synchronized (mConfig) {
if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 6f9d8033cd88..9f09c817e067 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
@@ -1456,4 +1479,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/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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c80b9d84ce61..bb08345b2fe1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -785,6 +785,8 @@ public final class SystemServer {
boolean disableSystemTextClassifier = SystemProperties.getBoolean(
"config.disable_systemtextclassifier", false);
+ boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime",
+ false);
boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
false);
boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false);
@@ -1459,7 +1461,7 @@ public final class SystemServer {
traceEnd();
}
- if (!isWatch) {
+ if (!isWatch && !disableNetworkTime) {
traceBeginAndSlog("StartNetworkTimeUpdateService");
try {
if (useNewTimeServices) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/net/java/android/net/ip/IpServer.java
index 5accb452d10a..33010a19d810 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.connectivity.tethering;
+package android.net.ip;
import static android.net.NetworkUtils.numericToInetAddress;
import static android.net.util.NetworkConstants.asByte;
@@ -31,11 +31,10 @@ import android.net.LinkProperties;
import android.net.RouteInfo;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
-import android.net.ip.InterfaceController;
-import android.net.ip.RouterAdvertisementDaemon;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
+import android.net.util.NetdService;
import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.Looper;
@@ -67,7 +66,22 @@ import java.util.Set;
*
* @hide
*/
-public class TetherInterfaceStateMachine extends StateMachine {
+public class IpServer extends StateMachine {
+ public static final int STATE_UNAVAILABLE = 0;
+ public static final int STATE_AVAILABLE = 1;
+ public static final int STATE_TETHERED = 2;
+ public static final int STATE_LOCAL_ONLY = 3;
+
+ public static String getStateString(int state) {
+ switch (state) {
+ case STATE_UNAVAILABLE: return "UNAVAILABLE";
+ case STATE_AVAILABLE: return "AVAILABLE";
+ case STATE_TETHERED: return "TETHERED";
+ case STATE_LOCAL_ONLY: return "LOCAL_ONLY";
+ }
+ return "UNKNOWN: " + state;
+ }
+
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
private static final byte DOUG_ADAMS = (byte) 42;
@@ -83,15 +97,53 @@ public class TetherInterfaceStateMachine extends StateMachine {
// TODO: have this configurable
private static final int DHCP_LEASE_TIME_SECS = 3600;
- private final static String TAG = "TetherInterfaceSM";
+ private final static String TAG = "IpServer";
private final static boolean DBG = false;
private final static boolean VDBG = false;
private static final Class[] messageClasses = {
- TetherInterfaceStateMachine.class
+ IpServer.class
};
private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(messageClasses);
+ public static class Callback {
+ /**
+ * Notify that |who| has changed its tethering state.
+ *
+ * @param who the calling instance of IpServer
+ * @param state one of STATE_*
+ * @param lastError one of ConnectivityManager.TETHER_ERROR_*
+ */
+ public void updateInterfaceState(IpServer who, int state, int lastError) {}
+
+ /**
+ * Notify that |who| has new LinkProperties.
+ *
+ * @param who the calling instance of IpServer
+ * @param newLp the new LinkProperties to report
+ */
+ public void updateLinkProperties(IpServer who, LinkProperties newLp) {}
+ }
+
+ public static class Dependencies {
+ public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+ return new RouterAdvertisementDaemon(ifParams);
+ }
+
+ public InterfaceParams getInterfaceParams(String ifName) {
+ return InterfaceParams.getByName(ifName);
+ }
+
+ public INetd getNetdService() {
+ return NetdService.getInstance();
+ }
+
+ public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+ DhcpServingParams params, SharedLog log) {
+ return new DhcpServer(looper, iface, params, log);
+ }
+ }
+
private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100;
// request from the user that it wants to tether
public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2;
@@ -123,7 +175,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
private final INetworkManagementService mNMService;
private final INetd mNetd;
private final INetworkStatsService mStatsService;
- private final IControlsTethering mTetherController;
+ private final Callback mCallback;
private final InterfaceController mInterfaceCtrl;
private final String mIfaceName;
@@ -131,7 +183,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
private final LinkProperties mLinkProperties;
private final boolean mUsingLegacyDhcp;
- private final TetheringDependencies mDeps;
+ private final Dependencies mDeps;
private int mLastError;
private int mServingMode;
@@ -148,17 +200,16 @@ public class TetherInterfaceStateMachine extends StateMachine {
private DhcpServer mDhcpServer;
private RaParams mLastRaParams;
- public TetherInterfaceStateMachine(
+ public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
INetworkManagementService nMService, INetworkStatsService statsService,
- IControlsTethering tetherController, boolean usingLegacyDhcp,
- TetheringDependencies deps) {
+ Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
mNMService = nMService;
mNetd = deps.getNetdService();
mStatsService = statsService;
- mTetherController = tetherController;
+ mCallback = callback;
mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
mIfaceName = ifaceName;
mInterfaceType = interfaceType;
@@ -167,7 +218,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
mDeps = deps;
resetLinkProperties();
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
- mServingMode = IControlsTethering.STATE_AVAILABLE;
+ mServingMode = STATE_AVAILABLE;
mInitialState = new InitialState();
mLocalHotspotState = new LocalHotspotState();
@@ -521,14 +572,12 @@ public class TetherInterfaceStateMachine extends StateMachine {
private void sendInterfaceState(int newInterfaceState) {
mServingMode = newInterfaceState;
- mTetherController.updateInterfaceState(
- TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
+ mCallback.updateInterfaceState(this, newInterfaceState, mLastError);
sendLinkProperties();
}
private void sendLinkProperties() {
- mTetherController.updateLinkProperties(
- TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
+ mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties));
}
private void resetLinkProperties() {
@@ -539,7 +588,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
class InitialState extends State {
@Override
public void enter() {
- sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
+ sendInterfaceState(STATE_AVAILABLE);
}
@Override
@@ -549,10 +598,10 @@ public class TetherInterfaceStateMachine extends StateMachine {
case CMD_TETHER_REQUESTED:
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
switch (message.arg1) {
- case IControlsTethering.STATE_LOCAL_ONLY:
+ case STATE_LOCAL_ONLY:
transitionTo(mLocalHotspotState);
break;
- case IControlsTethering.STATE_TETHERED:
+ case STATE_TETHERED:
transitionTo(mTetheredState);
break;
default:
@@ -649,7 +698,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
// problematic because transitioning during a multi-state jump yields
// a Log.wtf(). Ultimately, there should be only one ServingState,
// and forwarding and NAT rules should be handled by a coordinating
- // functional element outside of TetherInterfaceStateMachine.
+ // functional element outside of IpServer.
class LocalHotspotState extends BaseServingState {
@Override
public void enter() {
@@ -659,7 +708,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
}
if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
- sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
+ sendInterfaceState(STATE_LOCAL_ONLY);
}
@Override
@@ -685,7 +734,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
// problematic because transitioning during a multi-state jump yields
// a Log.wtf(). Ultimately, there should be only one ServingState,
// and forwarding and NAT rules should be handled by a coordinating
- // functional element outside of TetherInterfaceStateMachine.
+ // functional element outside of IpServer.
class TetheredState extends BaseServingState {
@Override
public void enter() {
@@ -695,7 +744,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
}
if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
- sendInterfaceState(IControlsTethering.STATE_TETHERED);
+ sendInterfaceState(STATE_TETHERED);
}
@Override
@@ -817,7 +866,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
@Override
public void enter() {
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
- sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
+ sendInterfaceState(STATE_UNAVAILABLE);
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
new file mode 100644
index 000000000000..100f9c610efc
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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 distriZenbuted 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.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.app.NotificationManager.Policy;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenPolicy;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZenModeConfigTest extends UiServiceTestCase {
+
+ @Test
+ public void testPriorityOnlyMutingAllNotifications() {
+ ZenModeConfig config = getMutedNotificationsConfig();
+ assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+
+ config.allowReminders = true;
+ assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ config.allowReminders = false;
+
+ config.areChannelsBypassingDnd = true;
+ assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ config.areChannelsBypassingDnd = false;
+
+ assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ }
+
+ @Test
+ public void testZenPolicyNothingSetToNotificationPolicy() {
+ ZenModeConfig config = getMutedAllConfig();
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().build();
+ assertEquals(config.toNotificationPolicy(), config.toNotificationPolicy(zenPolicy));
+ }
+
+ @Test
+ public void testZenPolicyToNotificationPolicy() {
+ ZenModeConfig config = getMutedAllConfig();
+ config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+
+ ZenPolicy zenPolicy = new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .allowReminders(true)
+ .allowEvents(true)
+ .showLights(false)
+ .showInAmbientDisplay(false)
+ .build();
+
+ Policy originalPolicy = config.toNotificationPolicy();
+ int priorityCategories = originalPolicy.priorityCategories;
+ int priorityCallSenders = originalPolicy.priorityCallSenders;
+ int priorityMessageSenders = originalPolicy.priorityMessageSenders;
+ int suppressedVisualEffects = originalPolicy.suppressedVisualEffects;
+ priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+ priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
+ priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+
+ Policy expectedPolicy = new Policy(priorityCategories, priorityCallSenders,
+ priorityMessageSenders, suppressedVisualEffects);
+
+ assertEquals(expectedPolicy, config.toNotificationPolicy(zenPolicy));
+ }
+
+ @Test
+ public void testPriorityOnlyMutingAll() {
+ ZenModeConfig config = getMutedAllConfig();
+ assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+
+ config.allowReminders = true;
+ assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+ config.allowReminders = false;
+
+ config.areChannelsBypassingDnd = true;
+ assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+ config.areChannelsBypassingDnd = false;
+
+ config.allowAlarms = true;
+ assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+ config.allowAlarms = false;
+
+ assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+ assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+ }
+
+ private ZenModeConfig getMutedNotificationsConfig() {
+ ZenModeConfig config = new ZenModeConfig();
+ // Allow alarms, media, and system
+ config.allowAlarms = true;
+ config.allowMedia = true;
+ config.allowSystem = true;
+
+ // All notification sounds are not allowed
+ config.allowCalls = false;
+ config.allowRepeatCallers = false;
+ config.allowMessages = false;
+ config.allowReminders = false;
+ config.allowEvents = false;
+ config.areChannelsBypassingDnd = false;
+
+ config.suppressedVisualEffects = 0;
+
+ return config;
+ }
+
+ private ZenModeConfig getMutedAllConfig() {
+ ZenModeConfig config = new ZenModeConfig();
+ // No sounds allowed
+ config.allowAlarms = false;
+ config.allowMedia = false;
+ config.allowSystem = false;
+ config.allowCalls = false;
+ config.allowRepeatCallers = false;
+ config.allowMessages = false;
+ config.allowReminders = false;
+ config.allowEvents = false;
+ config.areChannelsBypassingDnd = false;
+
+ config.suppressedVisualEffects = 0;
+ return config;
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
new file mode 100644
index 000000000000..7c6b1c15177e
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -0,0 +1,456 @@
+/*
+ * 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 distriZenbuted 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.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.service.notification.ZenPolicy;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZenPolicyTest extends UiServiceTestCase {
+
+ @Test
+ public void testZenPolicyApplyAllowedToDisallowed() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // reminders are disallowed
+ builder.allowReminders(false);
+ ZenPolicy remindersDisallowed = builder.build();
+ assertEquals(ZenPolicy.STATE_DISALLOW,
+ remindersDisallowed.getPriorityCategoryReminders());
+
+ // reminders are allowed
+ builder.allowReminders(true);
+ ZenPolicy remindersAllowed = builder.build();
+ assertEquals(ZenPolicy.STATE_ALLOW,
+ remindersAllowed.getPriorityCategoryReminders());
+ assertEquals(ZenPolicy.STATE_DISALLOW,
+ remindersDisallowed.getPriorityCategoryReminders());
+
+ // we apply reminders allowed to reminders disallowed
+ // -> reminders should remain disallowed
+ remindersDisallowed.apply(remindersAllowed);
+ assertEquals(ZenPolicy.STATE_DISALLOW,
+ remindersDisallowed.getPriorityCategoryReminders());
+ }
+
+ @Test
+ public void testZenPolicyApplyAllowedToUnset() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // reminders are unset
+ ZenPolicy remindersUnset = builder.build();
+
+ // reminders are allowed
+ builder.allowReminders(true);
+ ZenPolicy remindersAllowed = builder.build();
+
+ // we apply reminders allowed to reminders unset
+ // -> reminders should be allowed
+ remindersUnset.apply(remindersAllowed);
+ assertEquals(ZenPolicy.STATE_ALLOW, remindersUnset.getPriorityCategoryReminders());
+ }
+
+ @Test
+ public void testZenPolicyApplyDisallowedToUnset() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // reminders are unset
+ ZenPolicy remindersUnset = builder.build();
+
+ // reminders are disallowed
+ builder.allowReminders(false);
+ ZenPolicy remindersDisallowed = builder.build();
+
+ // we apply reminders disallowed to reminders unset
+ // -> reminders should remain disallowed
+ remindersUnset.apply(remindersDisallowed);
+ assertEquals(ZenPolicy.STATE_DISALLOW,
+ remindersUnset.getPriorityCategoryReminders());
+ }
+
+ @Test
+ public void testZenPolicyApplyDisallowedToAllowed() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // reminders are allowed
+ builder.allowReminders(true);
+ ZenPolicy remindersAllowed = builder.build();
+
+ // reminders are disallowed
+ builder.allowReminders(false);
+ ZenPolicy remindersDisallowed = builder.build();
+
+ // we apply reminders allowed to reminders disallowed
+ // -> reminders should change to disallowed
+ remindersAllowed.apply(remindersDisallowed);
+ assertEquals(ZenPolicy.STATE_DISALLOW, remindersAllowed.getPriorityCategoryReminders());
+ }
+
+ @Test
+ public void testZenPolicyApplyUnsetToAllowed() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // reminders are allowed
+ builder.allowReminders(true);
+ ZenPolicy remindersAllowed = builder.build();
+
+ // reminders are unset
+ ZenPolicy.Builder builder2 = new ZenPolicy.Builder();
+ ZenPolicy remindersUnset = builder2.build();
+
+ // we apply reminders allowed to reminders unset
+ // -> reminders should remain allowed
+ remindersAllowed.apply(remindersUnset);
+ assertEquals(ZenPolicy.STATE_ALLOW, remindersAllowed.getPriorityCategoryReminders());
+ }
+
+ @Test
+ public void testZenPolicyApplyMoreSevereCallSenders() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // calls from contacts allowed
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+ ZenPolicy contactsAllowed = builder.build();
+
+ // calls from starred contacts allowed
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
+ ZenPolicy starredAllowed = builder.build();
+
+ // we apply starredAllowed to contactsAllowed -> starred contacts allowed (more restrictive)
+ contactsAllowed.apply(starredAllowed);
+ assertEquals(ZenPolicy.STATE_ALLOW, contactsAllowed.getPriorityCategoryCalls());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, contactsAllowed.getPriorityCallSenders());
+ }
+
+ @Test
+ public void testZenPolicyApplyLessSevereCallSenders() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // calls from contacts allowed
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+ ZenPolicy contactsAllowed = builder.build();
+
+ // calls from anyone allowed
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+ ZenPolicy anyoneAllowed = builder.build();
+
+ // we apply anyoneAllowed to contactsAllowed -> contactsAllowed (more restrictive)
+ contactsAllowed.apply(anyoneAllowed);
+ assertEquals(ZenPolicy.STATE_ALLOW, contactsAllowed.getPriorityCategoryCalls());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, contactsAllowed.getPriorityCallSenders());
+ }
+
+ @Test
+ public void testZenPolicyApplyMoreSevereMessageSenders() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ // messsages from contacts allowed
+ builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+ ZenPolicy contactsAllowed = builder.build();
+
+ // messsages from no one allowed
+ builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
+ ZenPolicy noneAllowed = builder.build();
+
+ // noneAllowed to contactsAllowed -> no messages allowed (more restrictive)
+ contactsAllowed.apply(noneAllowed);
+ assertEquals(ZenPolicy.STATE_DISALLOW, contactsAllowed.getPriorityCategoryMessages());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, contactsAllowed.getPriorityMessageSenders());
+ }
+
+ @Test
+ public void testZenPolicyMessagesInvalid() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowMessages(20); // invalid #, won't change policy
+ ZenPolicy policy = builder.build();
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_UNSET, policy.getPriorityMessageSenders());
+ }
+
+ @Test
+ public void testZenPolicyCallsInvalid() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+ builder.allowCalls(20); // invalid #, won't change policy
+ ZenPolicy policy = builder.build();
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+ }
+
+ @Test
+ public void testEmptyZenPolicy() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, -1);
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowReminders() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowReminders(true);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryReminders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowReminders(false);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryReminders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowEvents() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowEvents(true);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryEvents());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowEvents(false);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryEvents());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowMessages() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowMessages(ZenPolicy.PEOPLE_TYPE_ANYONE);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityMessageSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityMessageSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityMessageSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMessages());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityMessageSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowMessages(ZenPolicy.PEOPLE_TYPE_UNSET);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, -1);
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowCalls() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityCallSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityCallSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_NONE);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryCalls());
+ assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityCallSenders());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_UNSET);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, -1);
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowRepeatCallers() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowRepeatCallers(true);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryRepeatCallers());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowRepeatCallers(false);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryRepeatCallers());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowAlarms() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowAlarms(true);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryAlarms());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowAlarms(false);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryAlarms());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowMedia() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowMedia(true);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMedia());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowMedia(false);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMedia());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ @Test
+ public void testAllowSystem() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.allowSystem(true);
+ ZenPolicy policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
+ assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategorySystem());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+
+ builder.allowSystem(false);
+ policy = builder.build();
+ assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
+ assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategorySystem());
+ assertAllVisualEffectsUnsetExcept(policy, -1);
+ }
+
+ private void assertAllPriorityCategoriesUnsetExcept(ZenPolicy policy, int except) {
+ if (except != ZenPolicy.PRIORITY_CATEGORY_REMINDERS) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryReminders());
+ }
+
+ if (except != ZenPolicy.PRIORITY_CATEGORY_EVENTS) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryEvents());
+ }
+
+ if (except != ZenPolicy.PRIORITY_CATEGORY_MESSAGES) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
+ }
+
+ if (except != ZenPolicy.PRIORITY_CATEGORY_CALLS) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryCalls());
+ }
+
+ if (except != ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryRepeatCallers());
+ }
+
+ if (except != ZenPolicy.PRIORITY_CATEGORY_ALARMS) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryAlarms());
+ }
+
+ if (except != ZenPolicy.PRIORITY_CATEGORY_MEDIA) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMedia());
+ }
+
+ if (except != ZenPolicy.PRIORITY_CATEGORY_SYSTEM) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategorySystem());
+ }
+ }
+
+ private void assertAllVisualEffectsUnsetExcept(ZenPolicy policy, int except) {
+ if (except != ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectFullScreenIntent());
+ }
+
+ if (except != ZenPolicy.VISUAL_EFFECT_LIGHTS) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectLights());
+ }
+
+ if (except != ZenPolicy.VISUAL_EFFECT_PEEK) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectPeek());
+ }
+
+ if (except != ZenPolicy.VISUAL_EFFECT_STATUS_BAR) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectStatusBar());
+ }
+
+ if (except != ZenPolicy.VISUAL_EFFECT_BADGE) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectBadge());
+ }
+
+ if (except != ZenPolicy.VISUAL_EFFECT_AMBIENT) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectAmbient());
+ }
+
+ if (except != ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST) {
+ assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectNotificationList());
+ }
+ }
+}
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/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
index 0fabc2ff6b86..541ca8d1e5c0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
@@ -118,71 +118,103 @@ public class SmsCbConstants {
public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE
= 0x111E; // 4382
- /** CMAS Message Identifier for Presidential Level alerts for additional languages
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Presidential Level alerts for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE
= 0x111F; // 4383
- /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE
= 0x1120; // 4384
- /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE
= 0x1121; // 4385
- /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE
= 0x1122; // 4386
- /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE
= 0x1123; // 4387
- /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE
= 0x1124; // 4388
- /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
- * for additional languages.*/
+ /**
+ * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE
= 0x1125; // 4389
- /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE
= 0x1126; // 4390
- /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
- * for additional languages.*/
+ /**
+ * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE
= 0x1127; // 4391
- /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
- * for additional languages. */
+ /**
+ * CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
+ * for additional languages.
+ */
public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE
= 0x1128; // 4392
- /** CMAS Message Identifier for the Required Monthly Test
- * for additional languages. */
+ /** CMAS Message Identifier for the Required Monthly Test for additional languages. */
public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE
= 0x1129; // 4393
- /** CMAS Message Identifier for CMAS Exercise
- * for additional languages. */
+ /** CMAS Message Identifier for CMAS Exercise for additional languages. */
public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE
= 0x112A; // 4394
- /** CMAS Message Identifier for operator defined use
- * for additional languages. */
+ /** CMAS Message Identifier for operator defined use for additional languages. */
public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE
= 0x112B; // 4395
+ /** CMAS Message Identifier for CMAS Public Safety Alerts. */
+ public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY
+ = 0x112C; // 4396
+
+ /** CMAS Message Identifier for CMAS Public Safety Alerts for additional languages. */
+ public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY_LANGUAGE
+ = 0x112D; // 4397
+
+ /** CMAS Message Identifier for CMAS State/Local Test. */
+ public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST
+ = 0x112E; // 4398
+
+ /** CMAS Message Identifier for CMAS State/Local Test for additional languages. */
+ public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST_LANGUAGE
+ = 0x112F; // 4399
+
/** End of CMAS Message Identifier range (including future extensions). */
public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER
= 0x112F; // 4399
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/android/net/ip/IpServerTest.java
index 593465380263..cff0b5469d47 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.connectivity.tethering;
+package android.net.ip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -37,9 +37,9 @@ import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
+import static android.net.ip.IpServer.STATE_AVAILABLE;
+import static android.net.ip.IpServer.STATE_TETHERED;
+import static android.net.ip.IpServer.STATE_UNAVAILABLE;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
@@ -50,7 +50,6 @@ import android.net.MacAddress;
import android.net.RouteInfo;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
-import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
import android.net.util.SharedLog;
@@ -74,7 +73,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class TetherInterfaceStateMachineTest {
+public class IpServerTest {
private static final String IFACE_NAME = "testnet1";
private static final String UPSTREAM_IFACE = "upstream0";
private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -85,39 +84,38 @@ public class TetherInterfaceStateMachineTest {
@Mock private INetworkManagementService mNMService;
@Mock private INetworkStatsService mStatsService;
- @Mock private IControlsTethering mTetherHelper;
+ @Mock private IpServer.Callback mCallback;
@Mock private InterfaceConfiguration mInterfaceConfiguration;
@Mock private SharedLog mSharedLog;
@Mock private DhcpServer mDhcpServer;
@Mock private RouterAdvertisementDaemon mRaDaemon;
- @Mock private TetheringDependencies mTetheringDependencies;
+ @Mock private IpServer.Dependencies mDependencies;
@Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor;
private final TestLooper mLooper = new TestLooper();
private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
- private TetherInterfaceStateMachine mTestedSm;
+ private IpServer mIpServer;
private void initStateMachine(int interfaceType) throws Exception {
initStateMachine(interfaceType, false /* usingLegacyDhcp */);
}
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
- mTestedSm = new TetherInterfaceStateMachine(
+ mIpServer = new IpServer(
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
- mNMService, mStatsService, mTetherHelper, usingLegacyDhcp,
- mTetheringDependencies);
- mTestedSm.start();
+ mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
+ mIpServer.start();
// Starting the state machine always puts us in a consistent state and notifies
// the rest of the world that we've changed from an unknown to available state.
mLooper.dispatchAll();
- reset(mNMService, mStatsService, mTetherHelper);
+ reset(mNMService, mStatsService, mCallback);
when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
- when(mTetheringDependencies.makeDhcpServer(
+ when(mDependencies.makeDhcpServer(
any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer);
- when(mTetheringDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
- when(mTetheringDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+ when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
+ when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
when(mRaDaemon.start()).thenReturn(true);
}
@@ -130,11 +128,11 @@ public class TetherInterfaceStateMachineTest {
private void initTetheredStateMachine(int interfaceType, String upstreamIface,
boolean usingLegacyDhcp) throws Exception {
initStateMachine(interfaceType, usingLegacyDhcp);
- dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
if (upstreamIface != null) {
dispatchTetherConnectionChanged(upstreamIface);
}
- reset(mNMService, mStatsService, mTetherHelper);
+ reset(mNMService, mStatsService, mCallback);
when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
}
@@ -145,34 +143,34 @@ public class TetherInterfaceStateMachineTest {
@Test
public void startsOutAvailable() {
- mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
- false /* usingLegacyDhcp */, mTetheringDependencies);
- mTestedSm.start();
+ mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(),
+ TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback,
+ false /* usingLegacyDhcp */, mDependencies);
+ mIpServer.start();
mLooper.dispatchAll();
- verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
- verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
- verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
+ verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+ verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+ verifyNoMoreInteractions(mCallback, mNMService, mStatsService);
}
@Test
public void shouldDoNothingUntilRequested() throws Exception {
initStateMachine(TETHERING_BLUETOOTH);
final int [] NOOP_COMMANDS = {
- TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
- TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
- TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR,
- TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR,
- TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR,
- TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR,
- TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED
+ IpServer.CMD_TETHER_UNREQUESTED,
+ IpServer.CMD_IP_FORWARDING_ENABLE_ERROR,
+ IpServer.CMD_IP_FORWARDING_DISABLE_ERROR,
+ IpServer.CMD_START_TETHERING_ERROR,
+ IpServer.CMD_STOP_TETHERING_ERROR,
+ IpServer.CMD_SET_DNS_FORWARDERS_ERROR,
+ IpServer.CMD_TETHER_CONNECTION_CHANGED
};
for (int command : NOOP_COMMANDS) {
// None of these commands should trigger us to request action from
// the rest of the system.
dispatchCommand(command);
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
}
@@ -180,57 +178,57 @@ public class TetherInterfaceStateMachineTest {
public void handlesImmediateInterfaceDown() throws Exception {
initStateMachine(TETHERING_BLUETOOTH);
- dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
- verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
- verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+ verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+ verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
@Test
public void canBeTethered() throws Exception {
initStateMachine(TETHERING_BLUETOOTH);
- dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mTetherHelper, mNMService);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+ InOrder inOrder = inOrder(mCallback, mNMService);
inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
- inOrder.verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
- inOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ inOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+ inOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), any(LinkProperties.class));
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
@Test
public void canUnrequestTethering() throws Exception {
initTetheredStateMachine(TETHERING_BLUETOOTH, null);
- dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
- InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+ dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+ InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
- inOrder.verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
- inOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ inOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+ inOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), any(LinkProperties.class));
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
@Test
public void canBeTetheredAsUsb() throws Exception {
initStateMachine(TETHERING_USB);
- dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mTetherHelper, mNMService);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+ InOrder inOrder = inOrder(mCallback, mNMService);
inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
- inOrder.verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
- inOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ inOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+ inOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
@Test
@@ -243,7 +241,7 @@ public class TetherInterfaceStateMachineTest {
InOrder inOrder = inOrder(mNMService);
inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
@Test
@@ -257,7 +255,7 @@ public class TetherInterfaceStateMachineTest {
inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
@Test
@@ -300,18 +298,18 @@ public class TetherInterfaceStateMachineTest {
public void canUnrequestTetheringWithUpstream() throws Exception {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
- dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
- InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+ dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+ InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
inOrder.verify(mStatsService).forceUpdate();
inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
- inOrder.verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
- inOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ inOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+ inOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), any(LinkProperties.class));
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
@Test
@@ -322,15 +320,15 @@ public class TetherInterfaceStateMachineTest {
if (shouldThrow) {
doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
}
- dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+ dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+ InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
usbTeardownOrder.verify(mNMService).setInterfaceConfig(
IFACE_NAME, mInterfaceConfiguration);
- usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
- usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ usbTeardownOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+ usbTeardownOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), mLinkPropertiesCaptor.capture());
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
}
}
@@ -340,15 +338,15 @@ public class TetherInterfaceStateMachineTest {
initStateMachine(TETHERING_USB);
doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
- dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+ InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
usbTeardownOrder.verify(mNMService).setInterfaceConfig(
IFACE_NAME, mInterfaceConfiguration);
- usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
- usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ usbTeardownOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
+ usbTeardownOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), mLinkPropertiesCaptor.capture());
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
}
@@ -358,13 +356,13 @@ public class TetherInterfaceStateMachineTest {
doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+ InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
- usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
- mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
- usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ usbTeardownOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
+ usbTeardownOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), mLinkPropertiesCaptor.capture());
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
}
@@ -372,11 +370,11 @@ public class TetherInterfaceStateMachineTest {
public void ignoresDuplicateUpstreamNotifications() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
for (int i = 0; i < 5; i++) {
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
}
}
@@ -401,11 +399,11 @@ public class TetherInterfaceStateMachineTest {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- verify(mTetheringDependencies, never()).makeDhcpServer(any(), any(), any(), any());
+ verify(mDependencies, never()).makeDhcpServer(any(), any(), any(), any());
}
private void assertDhcpStarted(IpPrefix expectedPrefix) {
- verify(mTetheringDependencies, times(1)).makeDhcpServer(
+ verify(mDependencies, times(1)).makeDhcpServer(
eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog));
verify(mDhcpServer, times(1)).start();
final DhcpServingParams params = mDhcpParamsCaptor.getValue();
@@ -422,21 +420,21 @@ public class TetherInterfaceStateMachineTest {
/**
* Send a command to the state machine under test, and run the event loop to idle.
*
- * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+ * @param command One of the IpServer.CMD_* constants.
* @param arg1 An additional argument to pass.
*/
private void dispatchCommand(int command, int arg1) {
- mTestedSm.sendMessage(command, arg1);
+ mIpServer.sendMessage(command, arg1);
mLooper.dispatchAll();
}
/**
* Send a command to the state machine under test, and run the event loop to idle.
*
- * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+ * @param command One of the IpServer.CMD_* constants.
*/
private void dispatchCommand(int command) {
- mTestedSm.sendMessage(command);
+ mIpServer.sendMessage(command);
mLooper.dispatchAll();
}
@@ -447,7 +445,7 @@ public class TetherInterfaceStateMachineTest {
* @param upstreamIface String name of upstream interface (or null)
*/
private void dispatchTetherConnectionChanged(String upstreamIface) {
- mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+ mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
new InterfaceSet(upstreamIface));
mLooper.dispatchAll();
}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 0d3b8e4a0452..40d5544dccd8 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -75,6 +75,7 @@ import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams;
import android.net.util.NetworkConstants;
@@ -99,10 +100,8 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.StateMachine;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadHardwareInterface;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
@@ -190,7 +189,7 @@ public class TetheringTest {
public class MockTetheringDependencies extends TetheringDependencies {
StateMachine upstreamNetworkMonitorMasterSM;
- ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+ ArrayList<IpServer> ipv6CoordinatorNotifyList;
int isTetheringSupportedCalls;
public void reset() {
@@ -213,29 +212,35 @@ public class TetheringTest {
@Override
public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
- ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+ ArrayList<IpServer> notifyList, SharedLog log) {
ipv6CoordinatorNotifyList = notifyList;
return mIPv6TetheringCoordinator;
}
@Override
- public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
- return mRouterAdvertisementDaemon;
- }
-
- @Override
- public INetd getNetdService() {
- return mNetd;
- }
-
- @Override
- public InterfaceParams getInterfaceParams(String ifName) {
- final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME,
- TEST_MOBILE_IFNAME };
- final int index = ArrayUtils.indexOf(ifaces, ifName);
- assertTrue("Non-mocked interface: " + ifName, index >= 0);
- return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
- MacAddress.ALL_ZEROS_ADDRESS);
+ public IpServer.Dependencies getIpServerDependencies() {
+ return new IpServer.Dependencies() {
+ @Override
+ public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
+ InterfaceParams ifParams) {
+ return mRouterAdvertisementDaemon;
+ }
+
+ @Override
+ public InterfaceParams getInterfaceParams(String ifName) {
+ final String[] ifaces = new String[] {
+ TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
+ final int index = ArrayUtils.indexOf(ifaces, ifName);
+ assertTrue("Non-mocked interface: " + ifName, index >= 0);
+ return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
+ MacAddress.ALL_ZEROS_ADDRESS);
+ }
+
+ @Override
+ public INetd getNetdService() {
+ return mNetd;
+ }
+ };
}
@Override
@@ -458,9 +463,9 @@ public class TetheringTest {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
- // If, and only if, Tethering received an interface status changed
- // then it creates a TetherInterfaceStateMachine and sends out a
- // broadcast indicating that the interface is "available".
+ // If, and only if, Tethering received an interface status changed then
+ // it creates a IpServer and sends out a broadcast indicating that the
+ // interface is "available".
if (emulateInterfaceStatusChanged) {
assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
@@ -557,18 +562,18 @@ public class TetheringTest {
}
/**
- * Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator.
+ * Send CMD_IPV6_TETHER_UPDATE to IpServers as would be done by IPv6TetheringCoordinator.
*/
private void sendIPv6TetherUpdates(NetworkState upstreamState) {
// IPv6TetheringCoordinator must have been notified of downstream
verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
- eq(IControlsTethering.STATE_TETHERED));
+ eq(IpServer.STATE_TETHERED));
- for (TetherInterfaceStateMachine tism :
+ for (IpServer ipSrv :
mTetheringDependencies.ipv6CoordinatorNotifyList) {
NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
- tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
+ ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
upstreamState.linkProperties.isIPv6Provisioned()
? ipv6OnlyState.linkProperties
: null);
@@ -812,7 +817,7 @@ public class TetheringTest {
// We verify get/set called thrice here: once for setup and twice during
// teardown because all events happen over the course of the single
- // dispatchAll() above. Note that once the TISM IPv4 address config
+ // dispatchAll() above. Note that once the IpServer IPv4 address config
// code is refactored the two calls during shutdown will revert to one.
verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
verify(mNMService, times(3))
diff --git a/tools/aapt2/Diagnostics.h b/tools/aapt2/Diagnostics.h
index 50e8b33ab9b1..30deb5555b21 100644
--- a/tools/aapt2/Diagnostics.h
+++ b/tools/aapt2/Diagnostics.h
@@ -133,11 +133,19 @@ class SourcePathDiagnostics : public IDiagnostics {
void Log(Level level, DiagMessageActual& actual_msg) override {
actual_msg.source.path = source_.path;
diag_->Log(level, actual_msg);
+ if (level == Level::Error) {
+ error = true;
+ }
+ }
+
+ bool HadError() {
+ return error;
}
private:
Source source_;
IDiagnostics* diag_;
+ bool error = false;
DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
};
diff --git a/tools/aapt2/compile/XmlIdCollector.cpp b/tools/aapt2/compile/XmlIdCollector.cpp
index d61a15af0d85..2199d003bccb 100644
--- a/tools/aapt2/compile/XmlIdCollector.cpp
+++ b/tools/aapt2/compile/XmlIdCollector.cpp
@@ -21,6 +21,7 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
+#include "text/Unicode.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -35,8 +36,9 @@ struct IdCollector : public xml::Visitor {
public:
using xml::Visitor::Visit;
- explicit IdCollector(std::vector<SourcedResourceName>* out_symbols)
- : out_symbols_(out_symbols) {}
+ explicit IdCollector(std::vector<SourcedResourceName>* out_symbols,
+ SourcePathDiagnostics* source_diag) : out_symbols_(out_symbols),
+ source_diag_(source_diag) {}
void Visit(xml::Element* element) override {
for (xml::Attribute& attr : element->attributes) {
@@ -44,12 +46,16 @@ struct IdCollector : public xml::Visitor {
bool create = false;
if (ResourceUtils::ParseReference(attr.value, &name, &create, nullptr)) {
if (create && name.type == ResourceType::kId) {
- auto iter = std::lower_bound(out_symbols_->begin(),
- out_symbols_->end(), name, cmp_name);
- if (iter == out_symbols_->end() || iter->name != name) {
- out_symbols_->insert(iter,
- SourcedResourceName{name.ToResourceName(),
- element->line_number});
+ if (!text::IsValidResourceEntryName(name.entry)) {
+ source_diag_->Error(DiagMessage(element->line_number)
+ << "id '" << name << "' has an invalid entry name");
+ } else {
+ auto iter = std::lower_bound(out_symbols_->begin(),
+ out_symbols_->end(), name, cmp_name);
+ if (iter == out_symbols_->end() || iter->name != name) {
+ out_symbols_->insert(iter, SourcedResourceName{name.ToResourceName(),
+ element->line_number});
+ }
}
}
}
@@ -60,15 +66,17 @@ struct IdCollector : public xml::Visitor {
private:
std::vector<SourcedResourceName>* out_symbols_;
+ SourcePathDiagnostics* source_diag_;
};
} // namespace
bool XmlIdCollector::Consume(IAaptContext* context, xml::XmlResource* xmlRes) {
xmlRes->file.exported_symbols.clear();
- IdCollector collector(&xmlRes->file.exported_symbols);
+ SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics());
+ IdCollector collector(&xmlRes->file.exported_symbols, &source_diag);
xmlRes->root->Accept(&collector);
- return true;
+ return !source_diag.HadError();
}
} // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector_test.cpp b/tools/aapt2/compile/XmlIdCollector_test.cpp
index 98da56d03ae3..d49af3bf903c 100644
--- a/tools/aapt2/compile/XmlIdCollector_test.cpp
+++ b/tools/aapt2/compile/XmlIdCollector_test.cpp
@@ -64,4 +64,14 @@ TEST(XmlIdCollectorTest, DontCollectNonIds) {
EXPECT_TRUE(doc->file.exported_symbols.empty());
}
+TEST(XmlIdCollectorTest, ErrorOnInvalidIds) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ std::unique_ptr<xml::XmlResource> doc =
+ test::BuildXmlDom("<View foo=\"@+id/foo$bar\"/>");
+
+ XmlIdCollector collector;
+ ASSERT_FALSE(collector.Consume(context.get(), doc.get()));
+}
+
} // namespace aapt
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/Files.cpp b/tools/aapt2/util/Files.cpp
index 7cd023bca369..73105e16559b 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -102,12 +102,25 @@ FileType GetFileType(const std::string& path) {
#endif
bool mkdirs(const std::string& path) {
- constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
+ #ifdef _WIN32
+ // Start after the drive path if present. Calling mkdir with only the drive will cause an error.
+ size_t current_pos = 1u;
+ if (path.size() >= 3 && path[1] == ':' &&
+ (path[2] == '\\' || path[2] == '/')) {
+ current_pos = 3u;
+ }
+ #else
// Start after the first character so that we don't consume the root '/'.
// This is safe to do with unicode because '/' will never match with a continuation character.
size_t current_pos = 1u;
+ #endif
+ constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
while ((current_pos = path.find(sDirSep, current_pos)) != std::string::npos) {
std::string parent_path = path.substr(0, current_pos);
+ if (parent_path.empty()) {
+ continue;
+ }
+
int result = ::android::base::utf8::mkdir(parent_path.c_str(), mode);
if (result < 0 && errno != EEXIST) {
return false;